From fac5d10340df24a0cf17d170d71dddf1a00f509b Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Sun, 5 Apr 2026 12:30:44 -0300 Subject: [PATCH] =?utf8?q?fix(security):=20mq=5Freceive=5Fimpl=20TOCTOU=20?= =?utf8?q?race=20=E2=80=94=20copy=20msg=20data=20under=20lock?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Mirror the mq_send_impl fix: copy message data into a kernel buffer while holding mq_lock, then copy_to_user after release. Without this, another thread could overwrite the dequeued slot via mq_send before the copy_to_user completes. Found during deep re-scan. All tests pass (102/103, 1 pre-existing timeout). --- src/kernel/syscall.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index e6e4ecc3..297f61c3 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -168,21 +168,28 @@ static int syscall_mq_send_impl(int mqd, const void* user_buf, uint32_t len, uin static int syscall_mq_receive_impl(int mqd, void* user_buf, uint32_t len, uint32_t* user_prio) { if (mqd < 0 || mqd >= MQ_MAX_QUEUES) return -EBADF; + uint8_t kbuf[MQ_MSG_SIZE]; + uint32_t mlen, mprio; + uintptr_t fl = spin_lock_irqsave(&mq_lock); struct mq_queue* q = &mq_table[mqd]; if (!q->active) { spin_unlock_irqrestore(&mq_lock, fl); return -EBADF; } if (q->count == 0) { spin_unlock_irqrestore(&mq_lock, fl); return -EAGAIN; } struct mq_msg* m = &q->msgs[q->head]; - uint32_t mlen = m->len; - uint32_t mprio = m->prio; + mlen = m->len; + mprio = m->prio; if (mlen > len) mlen = len; + /* Copy message data to kernel buffer while holding the lock + * to avoid TOCTOU: another thread could overwrite the slot. */ + memcpy(kbuf, m->data, mlen); + q->head = (q->head + 1) % q->maxmsg; q->count--; spin_unlock_irqrestore(&mq_lock, fl); - if (copy_to_user(user_buf, m->data, mlen) < 0) return -EFAULT; + if (copy_to_user(user_buf, kbuf, mlen) < 0) return -EFAULT; if (user_prio) { if (user_range_ok(user_prio, 4)) (void)copy_to_user(user_prio, &mprio, 4); -- 2.43.0