From: Stacey Son <[email protected]> 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
Includes bsd_validate_msgsz() helper that caches kern.ipc.msgmax to validates message sizes. Signed-off-by: Stacey Son <[email protected]> Signed-off-by: Warner Losh <[email protected]> --- bsd-user/bsd-misc.h | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/bsd-user/bsd-misc.h b/bsd-user/bsd-misc.h index 27f4497d76..0025c97f78 100644 --- a/bsd-user/bsd-misc.h +++ b/bsd-user/bsd-misc.h @@ -281,6 +281,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) { -- 2.52.0
