Skip to content

Cross-CPU allocation to exploit preempt-disabled paths

Controlling allocation'ları farklı bir CPU'nun per-CPU slab'inden sür ki bir preempt-disabled critical section içinde free edilen bir object yine de reclaim edilebilsin.

Mechanism

SLUB cache'leri per-CPU'dur: her CPU'nun kmem_cache_cpu içinde kendi aktif slab'i (c->slab), lockless freelist'i (c->freelist) ve per-CPU partial list'i (c->partial) vardır. Normalde bir exploit kendini sched_setaffinity() ile tek bir CPU'ya pinler; böylece free'ler ve reallocation'lar aynı per-CPU freelist'e isabet eder ve layout determinizmi maksimize edilir.

Note

Preempt-disabled allocation path'leri için incelik: vulnerable allocation/free bir preempt_disable() (ya da local_lock) critical section'ı içinde çalıştığında, kernel task'ı migrate edemez ve attacker victim operasyonları arasında o aynı CPU'da grooming allocation'larını araya ekleyemez — same-CPU reclaim window'u kapalıdır. Cross-CPU fikri, controlling allocation'lar için farklı bir CPU'nun per-CPU slab'ini/freelist'ini kullanmaktır: diğer core'lara pinlenmiş helper thread'ler, CPU N'de free edilen object'in CPU M'de sürülen allocation'larla reclaim edilmesini sağlar (tipik olarak her ikisini de per-node partial list'ten ya da taze bir slab'den geçmeye zorlayarak) ve preempt-disable'ın aksi takdirde reddedeceği reclaim window'unu geri kazandırır.

Bu teknik HEXACON 2024'te sunuldu ("Utilizing Cross-CPU Allocation to Exploit Preempt-Disabled Linux Kernel", Mingi Cho & Wongi Lee); CVE-2023-31248 (nftables UAF) ve CVE-2024-36978 (net/sched sch_multiq OOB write) exploit edildi.

Walkthrough

Per-CPU pinning primitive'i (Google'ın kernelCTF CVE-2023-3390 exploit'inden):

void set_cpu_affinity(int cpu_n, pid_t pid) {
    cpu_set_t *set = malloc(sizeof(cpu_set_t));
    CPU_ZERO(set);
    CPU_SET(cpu_n, set);
    if (sched_setaffinity(pid, sizeof(*set), set) < 0){
        perror("sched_setaffinity");
        return;
    }
    free(set);
}
// set_cpu_affinity(0, 0); pins the current task to CPU core 0 to keep the
// exploit context on one core and reuse its percpu slab cache and freelist.

Cross-CPU slab-movement primitive'i ("Interleaving Cores", CROSS-X'te dokümante edilmiş): "It first fills the active slab of the current CPU to produce a full slab, then uses CPU pinning to switch to another core. When all objects allocated in step 1 are freed, the slab moves to the per-CPU partial slab list of the switched CPU." Bu, freed slab'i core'lar arasında taşır; böylece victim free başka bir core'da bir preempt-disabled path'te gerçekleşmiş olsa bile controlling CPU onu reclaim edebilir.

Warning

Hexacon slide deck PDF'i şu anda erişilemez durumda (HTTP 404). Yukarıdaki mekanizma, talk'un slide metnine değil; public per-CPU SLUB modeline, doğrulanmış talk/CVE'lere, sched_setaffinity bloğuna ve CROSS-X'in dokümante ettiği Interleaving Cores stratejisine dayanmaktadır. Talk'un kesin grooming sayılarını, kayıttan doğrulama gerektiren bilgiler olarak ele al.

Mitigation

Allocator state'inin daha güçlü per-CPU isolation'ı ve SLAB_VIRTUAL (araştırma) cross-CPU reclaim güvenilirliğini azaltır. Unprivileged user namespace'leri devre dışı bırakmak, adı geçen CVE'ler için netfilter/net-sched erişimini bloke eder.

References