DirtyCred file-object swap¶
The specific swap primitive of DirtyCred: free a writable
struct filemid-write and reallocate the freed slot with a privileged read-only file so the kernel's approved write redirects into the privileged file.
Mechanism¶
Bu not vs. credential swap
Bu not yalnızca struct file swap primitive'inin düşük seviye mekaniğine (filp_cache, kernel layout, race window'ları) odaklanır. Generic DirtyCred tekniği ve struct cred / root-cred reclaim path'i için bkz. DirtyCred credential swap.
Note
Tek cümleyle: yazılabilir bir dosyanın struct file'ını write-permission kontrolü
geçtikten sonra ama data yazılmadan önce free et, sonra aynı slab slot'unu
privileged read-only bir dosyanın struct file'ı ile reclaim et; böylece bekleyen
write privileged dosyaya düşer. Write'ın kendisi zaten yazılabilir dosyanın f_mode'una
(FMODE_WRITE / FMODE_CAN_WRITE) karşı onaylanmıştı; swap, o kontrol ile asıl data
store arasındaki boşluğu istismar eder.
struct file, özel filp_cache slab'ından (sembol filp_cachep) allocate edilir.
İki kernel layout'u önemlidir:
- Linux 4.13'ten önce
vfs_writevpermission-check ->import_iovec-> write sırasını izlerdi, dolayısıylaimport_iovecsırasındaki bir userfaultfd page-fault, kontrol ile write arasında yürütmeyi duraklatırdı (early userfaultfd-based race yaklaşımı). - 4.13'ten sonra
import_ioveckontrolün önüne taşındı, dolayısıyla exploit filesystem katmanına kayar:generic_perform_write, filesystem write'ından önce kullanıcı page'iniiov_iter_fault_in_readableile pre-fault eder — userfaultfd'lenebilir bir nokta — ya da daha sağlam olarak, aynı dosyaya yazan iki writer ext4 inode lock'unda (ext4_buffered_write_iteriçindekiinode_lock) serileşir, bu da çok saniyelik bir swap window verir.
Walkthrough¶
// Writer A holds the inode lock with a slow 4GB write (~dozens of seconds on HDD)
int big = open("/tmp/x", O_WRONLY);
write(big, buf, 4UL<<30);
// Writer B: victim writable file object — opened via a softlink so it lacks
// FMODE_ATOMIC_POS and does not stall in __fdget_pos on the shared position lock
int fd = open("/tmp/x_symlink", O_WRONLY); // struct file -> filp_cache
write(fd, payload, len); // FMODE_WRITE check passes, blocks on inode_lock
// Free B's file via the heap bug, then place a privileged read-only file in the slot
trigger_uaf_free_file(); // dangling filp_cache slot
int p = open("/etc/passwd", O_RDONLY); // reclaims slot with read-only file
// A releases inode_lock -> B's approved write now stores into /etc/passwd
Warning
Literatürde gösterilen write hedefi /etc/passwd'dir (hacker:x:0:0:root:/:/bin/sh
enjekte edilir); bir SUID binary'sinin içeriğini file-swap ile overwrite etmek
belgelenmiş bir yol değildir — SUID istismarı cred variant'ına aittir (root bir
cred allocate etmek için su, mount, pkexec vb. çalıştırmak). f_cred/f_pos
standart alanlardır ama makaleden birebir değildir; yalnızca f_mode/FMODE_* öyledir.
Aynı dosyanın double-open'ı file refcount'unu artırır, bu normalde __fdget_pos içindeki
FMODE_ATOMIC_POS position lock'unu devreye sokardı; writer B'yi bir symlink üzerinden açmak
bu lock'tan kaçınır, böylece thread yalnızca inode lock'unda stall olur — amaçlanan race
window.
Mitigation¶
DirtyCred'in önerdiği savunma, yazılabilir file object'lerini (ve root cred'i) vmalloc
bölgesine izole eder (__alloc_file -> vzalloc, file_free_rcu -> kvfree); böylece free
edilmiş yazılabilir-dosya page'leri asla unprivileged direct-mapped pool'a geri dönmez ve swap
kırılır. Upstream bunun yerine reclaim'i daha az deterministik yapmak için slab-cache
ayrımına ve freelist hardening'e dayanır.