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>
Stacey Son committed
Feb 2, 2026 at 16:46 UTC
bc903963bffbc63931d87f5e8bb98ea335d7dd3a
1 file changed
+97
bsd-user/bsd-misc.h
+97
@@ -17,6 +17,8 @@
17
18
#include "qemu-bsd.h"
19
20
+static int bsd_msgmax;
21
+
22
/* quotactl(2) */
23
static inline abi_long do_bsd_quotactl(abi_ulong path, abi_long cmd,
24
__unused abi_ulong target_addr)
@@ -260,6 +262,101 @@ static inline abi_long do_bsd_msgctl(int msgid, int target_cmd, abi_long ptr)
262
return ret;
263
}
264
265
+struct kern_mymsg {
266
+ long mtype;
267
+ char mtext[1];
268
+};
269
+
270
+static inline abi_long bsd_validate_msgsz(abi_ulong msgsz)
271
+{
272
+ /* Fetch msgmax the first time we need it. */
273
+ if (bsd_msgmax == 0) {
274
+ size_t len = sizeof(bsd_msgmax);
275
+
276
+ if (sysctlbyname("kern.ipc.msgmax", &bsd_msgmax, &len, NULL, 0) == -1) {
277
+ return -TARGET_EINVAL;
278
+ }
279
+ }
280
+
281
+ if (msgsz > bsd_msgmax) {
282
+ return -TARGET_EINVAL;
283
+ }
284
+ return 0;
285
+}
286
+
287
+/* msgsnd(2) */
288
+static inline abi_long do_bsd_msgsnd(int msqid, abi_long msgp,
289
+ abi_ulong msgsz, int msgflg)
290
+{
291
+ struct target_msgbuf *target_mb;
292
+ struct kern_mymsg *host_mb;
293
+ abi_long ret;
294
+
295
+ ret = bsd_validate_msgsz(msgsz);
296
+ if (is_error(ret)) {
297
+ return ret;
298
+ }
299
+ if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
300
+ return -TARGET_EFAULT;
301
+ }
302
+ host_mb = g_malloc(msgsz + sizeof(long));
303
+ host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
304
+ memcpy(host_mb->mtext, target_mb->mtext, msgsz);
305
+ ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
306
+ g_free(host_mb);
307
+ unlock_user_struct(target_mb, msgp, 0);
308
+
309
+ return ret;
310
+}
311
+
312
+/* msgget(2) */
313
+static inline abi_long do_bsd_msgget(abi_long key, abi_long msgflag)
314
+{
315
+ abi_long ret;
316
+
317
+ ret = get_errno(msgget(key, msgflag));
318
+ return ret;
319
+}
320
+
321
+/* msgrcv(2) */
322
+static inline abi_long do_bsd_msgrcv(int msqid, abi_long msgp,
323
+ abi_ulong msgsz, abi_long msgtyp, int msgflg)
324
+{
325
+ struct target_msgbuf *target_mb = NULL;
326
+ char *target_mtext;
327
+ struct kern_mymsg *host_mb;
328
+ abi_long ret = 0;
329
+
330
+ ret = bsd_validate_msgsz(msgsz);
331
+ if (is_error(ret)) {
332
+ return ret;
333
+ }
334
+ if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
335
+ return -TARGET_EFAULT;
336
+ }
337
+ host_mb = g_malloc(msgsz + sizeof(long));
338
+ ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
339
+ if (ret > 0) {
340
+ abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
341
+ target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
342
+ if (target_mtext == NULL) {
343
+ ret = -TARGET_EFAULT;
344
+ goto end;
345
+ }
346
+ memcpy(target_mb->mtext, host_mb->mtext, ret);
347
+ unlock_user(target_mtext, target_mtext_addr, ret);
348
+ }
349
+ if (!is_error(ret)) {
350
+ target_mb->mtype = tswapal(host_mb->mtype);
351
+ }
352
+end:
353
+ if (target_mb != NULL) {
354
+ unlock_user_struct(target_mb, msgp, 1);
355
+ }
356
+ g_free(host_mb);
357
+ return ret;
358
+}
359
+
360
/* getdtablesize(2) */
361
static inline abi_long do_bsd_getdtablesize(void)
362
{