Skip to content

Unaligned msg_msg technique

Bir System V msg_msg nesnesinin m_ts size alanını ya da next segment pointer'ını corrupt et — çoğu zaman sadece küçük/kısmi bir overwrite ile — onu bir out-of-bounds read'e ya da userfaultfd ile slab boyunca bir arbitrary read/write'a çevirmek için.

Mechanism

Note

msgsnd(), load_msgalloc_msg aracılığıyla bir struct msg_msg header'ı (ve büyük mesajlar için zincirlenmiş msg_msgseg segmentleri) kurar ve user verisini copy_from_user() ile kopyalar. msgrcv(), copy_msg/store_msg aracılığıyla min(bufsz, msg->m_ts) byte'ı geri kopyalar, sonra (MSG_COPY olmadan) unlink eder, nesneyi free_msg()'ler ve next segment zincirini yürür. İki primitive bunu izler. m_ts üzerinden OOB read: m_ts size alanını overwrite etmek (bir UAF write ya da header'a küçük/kısmi bir overflow) raporlanan uzunluğu şişirir, böylece msgrcv chunk sınırını aşarak kopyalar ve bitişik slab verisini ile kernel pointer'larını leak'ler. next üzerinden arb read/write: next pointer'ını overwrite etmek kernel'in saldırganın seçtiği bir adresi msg_msgseg gibi ele almasına yol açar; böylece sonraki bir msgrcv o hedefi dışarı kopyalar (arbitrary read) ya da bir re-send onun içine yazar (arbitrary write). "Unaligned/kısmi" yönü şudur: m_ts/next'in tek bir null byte'ı ya da birkaç low byte'ı zinciri başlatmaya yeter — tam bir pointer overwrite gerekmez.

Walkthrough

Doğrulanmış layout (header 0x30 byte; DATALEN_MSG = PAGE_SIZE - sizeof(struct msg_msg) = 0xfd0, DATALEN_SEG = PAGE_SIZE - sizeof(struct msg_msgseg) = 0xff8):

struct msg_msg {
    struct list_head   m_list;    /* prev/next queue linkage */
    long               m_type;
    size_t             m_ts;      /* message text size */
    struct msg_msgseg *next;      /* pointer to next segment */
    void              *security;  /* LSM pointer (NULL without SELinux) */
    /* data follows */
};
  1. OOB read (m_ts): msg_msg'i spray'le ki biri freed/UAF chunk'a düşsün; onun m_ts'ini büyük bir değere corrupt et; sonra msgrcv(qid, buf, large, type, IPC_NOWAIT | MSG_NOERROR) gerçek sınırları aşarak kopyalar ve bitişik slab/kernel pointer'larını leak'ler. Unlink/free etmeden okumak için MSG_COPY kullan, böylece aynı mesaj tekrar okunabilir.
  2. Kısıt: next-pointer arbitrary read için hedef bir NULL qword (zincir sonlandırıcı) ile başlamalıdır, aksi halde kernel panic olur.
  3. Arbitrary write (next + userfaultfd): load_msg()'deki copy_from_user()'ın source/dest'i olarak bir userfaultfd region register et; copy'si fault'layan bir msgsnd/msgrcv tetikle, böylece kernel thread'i next'i okumadan önce askıya alınır. Askıdayken next'i hedefe (örneğin cred - 0x8) işaret ettirmek için UAF'yi kullan; UFFDIO_COPY ile serbest bırak; devam eden işlem saldırgan byte'larını yazar (örneğin cred uid/gid üzerine sıfırlar → root).

Warning

NULL olmayan bir security pointer'ı (SELinux/LSM açık), layout'u değiştirir ve naif m_ts/next matematiğini bozabilir. Hedef offset'ler (örneğin task_struct.cred) kernel/config'e özgüdür.

Mitigation

  • CONFIG_SLAB_FREELIST_HARDENED / CONFIG_SLAB_FREELIST_RANDOM, tekniğin dayandığı LIFO free/realloc swap'ini zorlaştırır.
  • CONFIG_HARDENED_USERCOPY, nesne sınırlarını aşan aşırı büyük m_ts kopyalarını yakalayabilir.
  • vm.unprivileged_userfaultfd = 0, arbitrary-write adımının merkezindeki unprivileged stall primitive'ini kaldırır.

References