bsd-user: Add message queue implementations

Add implementations for:
- msgsnd(2): Send message to queue with size validation
- msgget(2): Get message queue identifier
- msgrcv(2): Receive message from queue with size validation

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
This commit is contained in:
Stacey Son
2026-02-02 16:46:42 -07:00
committed by Warner Losh
parent 1bbdc46d58
commit bc903963bf

View File

@@ -17,6 +17,8 @@
#include "qemu-bsd.h"
static int bsd_msgmax;
/* quotactl(2) */
static inline abi_long do_bsd_quotactl(abi_ulong path, abi_long cmd,
__unused abi_ulong target_addr)
@@ -260,6 +262,101 @@ static inline abi_long do_bsd_msgctl(int msgid, int target_cmd, abi_long ptr)
return ret;
}
struct kern_mymsg {
long mtype;
char mtext[1];
};
static inline abi_long bsd_validate_msgsz(abi_ulong msgsz)
{
/* Fetch msgmax the first time we need it. */
if (bsd_msgmax == 0) {
size_t len = sizeof(bsd_msgmax);
if (sysctlbyname("kern.ipc.msgmax", &bsd_msgmax, &len, NULL, 0) == -1) {
return -TARGET_EINVAL;
}
}
if (msgsz > bsd_msgmax) {
return -TARGET_EINVAL;
}
return 0;
}
/* msgsnd(2) */
static inline abi_long do_bsd_msgsnd(int msqid, abi_long msgp,
abi_ulong msgsz, int msgflg)
{
struct target_msgbuf *target_mb;
struct kern_mymsg *host_mb;
abi_long ret;
ret = bsd_validate_msgsz(msgsz);
if (is_error(ret)) {
return ret;
}
if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
return -TARGET_EFAULT;
}
host_mb = g_malloc(msgsz + sizeof(long));
host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
g_free(host_mb);
unlock_user_struct(target_mb, msgp, 0);
return ret;
}
/* msgget(2) */
static inline abi_long do_bsd_msgget(abi_long key, abi_long msgflag)
{
abi_long ret;
ret = get_errno(msgget(key, msgflag));
return ret;
}
/* msgrcv(2) */
static inline abi_long do_bsd_msgrcv(int msqid, abi_long msgp,
abi_ulong msgsz, abi_long msgtyp, int msgflg)
{
struct target_msgbuf *target_mb = NULL;
char *target_mtext;
struct kern_mymsg *host_mb;
abi_long ret = 0;
ret = bsd_validate_msgsz(msgsz);
if (is_error(ret)) {
return ret;
}
if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
return -TARGET_EFAULT;
}
host_mb = g_malloc(msgsz + sizeof(long));
ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
if (ret > 0) {
abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
if (target_mtext == NULL) {
ret = -TARGET_EFAULT;
goto end;
}
memcpy(target_mb->mtext, host_mb->mtext, ret);
unlock_user(target_mtext, target_mtext_addr, ret);
}
if (!is_error(ret)) {
target_mb->mtype = tswapal(host_mb->mtype);
}
end:
if (target_mb != NULL) {
unlock_user_struct(target_mb, msgp, 1);
}
g_free(host_mb);
return ret;
}
/* getdtablesize(2) */
static inline abi_long do_bsd_getdtablesize(void)
{