Skip to content

Arbitrary read via msg_msg

Bir System V struct msg_msg'in m_ts size field'ını corrupt et; böylece msgrcv(..., MSG_COPY) orijinal allocation'ın ötesine kopyalar ve relative bir out-of-bounds kernel read elde edersin.

Mechanism

Note

msgsnd(), bir struct msg_msg header'ını ve hemen ardından inline olarak mesaj payload'ını tutan tek bir kmalloc chunk allocate eder. Header field'ı m_ts, text boyutunu kaydeder. Bir attacker m_ts'i gerçek payload'dan daha büyük bir değere corrupt ederse (bitişik bir overflow ile veya header'a bir UAF write ile), sonraki bir read m_ts byte transfer eder ve allocation'ın ötesini okur. MSG_COPY bunu mümkün kılan numaradır: MSG_COPY ile do_msgrcv(), mesajı memcpy ile kopyalarken onu queue'da bırakır (non-destructive) ve hardened-usercopy doğrulamasını bypass eder, böylece şişirilmiş mesaj tekrar tekrar okunabilir.

Header layout'u:

struct msg_msg {
    struct list_head m_list;    /* also leaks heap pointers if read */
    long m_type;
    size_t m_ts;                /* message text size  <-- corrupt this */
    struct msg_msgseg *next;
    void *security;
    /* message payload follows immediately */
};                              /* 0x30 bytes */

struct msg_msgseg {
    struct msg_msgseg *next;
    /* inline data follows */
};                              /* 0x8-byte header */

DATALEN_MSG = PAGE_SIZE - sizeof(struct msg_msg) = 0xfd0; DATALEN_SEG = PAGE_SIZE - sizeof(struct msg_msgseg) = 0xff8.

Walkthrough

int qid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);

struct { long mtype; char mtext[SZ]; } m = { .mtype = 1 };
msgsnd(qid, &m, SZ, 0);                 /* allocates msg_msg + payload */

/* ... overflow/UAF raises m_ts to a larger value (and sets next as needed) ... */

struct { long mtype; char buf[BIG]; } out;
msgrcv(qid, &out, BIG, 0, MSG_COPY | IPC_NOWAIT);   /* OOB read of m_ts bytes */

Warning

Şişirilmiş m_ts kopyanın bir segment olacak bölgeye geçmesine neden olduğunda, copy_msg()'nin next olarak okuduğu qword NULL olmalıdır — "kernel panic'leri önlemek için bir sonraki segment null bir qword ile başlamalı." Layout'u öyle hazırla ki traverse edilen next pointer'ı NULL ya da kontrol edilen geçerli bir msg_msgseg olsun.

Sibling not

Bu not yalnızca m_ts şişirme → relative OOB read varyantını kapsar (read-only, sabit yönde, allocation'ın hemen ötesi). next pointer'ını hijack ederek elde edilen arbitrary read/write engine'i ayrı bir nottadır: bkz. msg_msg arbitrary read/write object.

Detection

MSG_COPY, CONFIG_CHECKPOINT_RESTORE gerektirir; unprivileged process'lerden gelen MSG_COPY'li msgrcv çağrılarını izlemek bu read varyantını işaretler.

Mitigation

  • CONFIG_CHECKPOINT_RESTORE'u kapatmak, MSG_COPY non-destructive read yolunu ortadan kaldırır.
  • Kopya memcpy üzerinden gittiğinden hardened-usercopy onu durdurmaz — savunma, başlangıçtaki m_ts corruption'ını engellemeye dayanır (allocator hardening, cache isolation).

References