DirtyCred route4_change double free (CVE-2022-2588)¶
A condition mismatch in
route4_change()leaves a freedcls_routefilter on its hash list, yielding a double free that DirtyCred turns into root by swapping credentials after the permission check.
Mechanism¶
CVE-2022-2588, net/sched/cls_route.c içindeki route4_change()'te bir double free'dir; bu, traffic-control (tc) subsystem'inin "route" classifier'ıdır. Bug Linux v3.17'de (2014) eklendi ve bir user namespace içindeki unprivileged bir kullanıcı tarafından erişilebilir (user namespace özel bir net namespace üzerinde CAP_NET_ADMIN verir ve tc filter konfigürasyonunu açığa çıkarır).
Note
Kök neden, bir filter replacement sırasında eski filter fold için unlink koşulu ile free koşulu arasındaki uyumsuzluktur. Kod eski filter'ı yalnızca şu durumda unlink eder:
ama fold'u şu daha geniş koşul altında free eder:
Bir kullanıcı handle'ı 0 olan bir filter oluşturur, sonra bir replacement tetiklerse, fold->handle kontrolü başarısız olur ve filter unlink edilmez -- yine de free edilir. Free edilmiş route4_filter'a bir dangling pointer linked list üzerinde kalır ve ikinci bir işlem onu tekrar free eder: bir double free. CONFIG_NET_CLS_ACT etkinken, gömülü route4_filter->exts.action object'i de double-free edilir.
İki double-free primitive'i farklı slab cache'lere düşer: route4_filter object'i kmalloc-192'de, route4_filter->exts.action object'i ise kmalloc-256'dadır.
Walkthrough¶
DirtyCred generic bir tekniktir: code pointer'larını bozmak yerine, bir free/double-free primitive'i kullanarak bir permission kontrolü zaten geçtikten sonra aynı cache'ten allocate edilen low-privileged bir credential object'i high-privileged biriyle takas eder. Burada double free, swap primitive'idir.
İki saldırı variant'ı gösterilir:
Task-credential variant (kmalloc-192):
1. Trigger the route4 double free on the route4_filter object.
2. Free a victim cred struct so it lands on the same kmalloc-192 freelist.
3. Reallocate the dangling slot with a privileged cred (uid 0),
so the running task now references a root credential.
File-credential variant (kmalloc-256):
1. Trigger the double free on route4_filter->exts.action.
2. Open the read-only target file -> a struct file passes the
write-permission check while pointing at a writable mode.
3. Use the double free to swap the file's credential after the
check, so a write() lands in a file you only had read on.
Zafiyetli yola ulaşmak için klasik kurulum:
unshare(CLONE_NEWUSER | CLONE_NEWNET); // get CAP_NET_ADMIN in netns
// add a route4 filter with handle 0, then replace it to trigger
// the unlink/free condition mismatch -> double free
Beklenen sonuç
Public exploit (Markakd/CVE-2022-2588) file-credential swap yoluyla /etc/passwd'ye yazar ve root'a escalate eder; Ubuntu 20, CentOS 8 ve Debian 11 kernel'lerine karşı gösterilmiştir. Sonuç: bir user namespace içindeki unprivileged bir kullanıcı root shell elde eder veya read-only dosyalara arbitrary write yapar.
Detection¶
handle 0ile unprivilegedtcroute4 filter oluşturulması ardından bir replacement gelmesi güçlü bir imzadır; netlinktcfilter add/replace ile eşleşenunshare(CLONE_NEWUSER)çağrılarını denetleyin.- Slab freelist tutarlılık kontrolleri (
CONFIG_SLAB_FREELIST_HARDENED) vekfreeiçindeki double-free tespiti ikinci free'yi yakalar.
Mitigation¶
route4_change()içindeki koşul uyumsuzluğunu yamalayın ki unlink ve free koşulları uyuşsun (upstream fix bu sapmayı kaldırır).- Unprivileged user namespace'leri kısıtlayın (
kernel.unprivileged_userns_clone=0/user.max_user_namespaces=0) ve erişilebilirliği ortadan kaldırın. - DirtyCred-sınıfı mitigation: privileged credential object'leri özel cache'lere izole edin (örneğin
kmem_cacheayrımı / vmalloc-destekli cred allocation yoluyla) ki free edilmiş non-privileged bir object privileged olarak yeniden allocate edilemesin.