From: Stacey Son <sson@FreeBSD.org>
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 <sson@FreeBSD.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
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