]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix(security): mq_receive_impl TOCTOU race — copy msg data under lock
authorTulio A M Mendes <[email protected]>
Sun, 5 Apr 2026 15:30:44 +0000 (12:30 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 5 Apr 2026 15:30:44 +0000 (12:30 -0300)
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

index e6e4ecc3881813a1e6e7e31e062cf9bb2edcdfde..297f61c38a439dca051b234d02d4213b1015a035 100644 (file)
@@ -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);