Skip to content

DirtyCred route4_change double free (CVE-2022-2588)

A condition mismatch in route4_change() leaves a freed cls_route filter 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:

if (fold && fold->handle && f->handle != fold->handle)
    /* unlink fold from the hash bucket list */

ama fold'u şu daha geniş koşul altında free eder:

if (fold)
    /* call_rcu(&fold->rcu, route4_delete_filter); */

Bir kullanıcı handle0 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 0 ile unprivileged tc route4 filter oluşturulması ardından bir replacement gelmesi güçlü bir imzadır; netlink tc filter add/replace ile eşleşen unshare(CLONE_NEWUSER) çağrılarını denetleyin.
  • Slab freelist tutarlılık kontrolleri (CONFIG_SLAB_FREELIST_HARDENED) ve kfree iç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_cache ayrımı / vmalloc-destekli cred allocation yoluyla) ki free edilmiş non-privileged bir object privileged olarak yeniden allocate edilemesin.

References