addr_limit overwrite (set_fs KERNEL_DS) arbitrary R/W¶
Per-thread
addr_limit'iKERNEL_DS'e overwrite et; böylececopy_to/from_userkernel adreslerini kabul eder ve sıradanread()/write()çağrıları arbitrary kernel R/W'ye dönüşür.
Mechanism¶
Note
set_fs(), per-thread bir değişken olan addr_limit'i ayarlar; bu değişken user ve
kernel space arasındaki sınırı işaretler. access_ok(), user erişimlerini addr_limit
ile basit bir karşılaştırma yaparak doğrular. addr_limit KERNEL_DS (tüm adres
aralığı) olduğunda, copy_from_user() / copy_to_user() kernel adreslerini de
kabul eder. Yani bir attacker addr_limit'i corrupt ederse, access_ok kontrolü her
zaman geçer ve usercopy helper'ları kernel memory'yi okur/yazar.
x86_64'te bu alan, task_struct içindeki struct thread_struct içinde yaşar ve
access_ok() sınırı user_addr_max() üzerinden çözer:
Walkthrough¶
Klasik akış: thread_info/task_struct'a ulaşan bir write primitive bul, addr_limit'i
overwrite et, sonra attacker'ın kontrol ettiği adreslerde usercopy çağıran bir syscall
kullan. iovec tabanlı yollar (writev/readv/recvmsg) idealdir çünkü hem kernel
target'ını (iov_base) hem de uzunluğu (iov_len) kontrol edersin:
/* after addr_limit has been corrupted to ~0 */
struct iovec iov[1];
iov[0].iov_base = (void *)KERNEL_TARGET_ADDR; /* kernel address */
iov[0].iov_len = LEN;
writev(pipe_fd[1], iov, 1); /* write into kernel memory */
/* recvmsg(... MSG_WAITALL ...) is used to block/synchronize the corruption */
Warning
addr_limit'i 0xFFFFFFFFFFFFFFFE yap, literal KERNEL_DS
(0xFFFFFFFFFFFFFFFF / -1) değil. ARM64'te do_page_fault(),
if (regs->orig_addr_limit == KERNEL_DS) die() kontrolünü yapar, dolayısıyla tam
olarak -1 değeri kernel'i panic'e sokar. 0xFFFFFFFFFFFFFFFE ise tüm kernel
adreslerini kapsayacak kadar büyüktür.
Mitigation¶
- set_fs() kaldırılması (kernel ~5.10+):
addr_limitmekanizmasının tamamı kaldırıldı veiov_iterarayüzüyle değiştirildi, böylece helper'lar user/kernel sınırı hakkında asla "yalan söylemek" zorunda kalmıyor — bu, attack vector'ı tamamen ortadan kaldırır. Asıl motivasyon, kernel'in eşleşmişset_fs(KERNEL_DS)/set_fs(old_fs)çağrıları arasında oops verip kernel memory'yi user-writable bıraktığı bir bug sınıfıydı (örn. CVE-2010-4258). - PAN / UAO (ARM64) ve SMAP (x86),
addr_limit == KERNEL_DSiken user memory'ye yapılan privileged erişimi trap'ler ve set_fs kaldırılmadan önce bile tekniği körleştirir.