mirror of
https://github.com/qemu/qemu.git
synced 2026-04-05 21:46:25 +00:00
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:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user