Skip to content

net/sched sch_hfsc UAF (CVE-2023-4623)

HFSC qdisc'inde bir use-after-free: link-sharing curve'ü olan bir class, hiç curve'ü olmayan bir parent altında oluşturulduğunda, init_vf() parent'ı vt-tree'ye insert eder ama update_vf() onu hiç remove etmez ve dangling bir pointer bırakır — bir unprivileged local privilege-escalation bug'ı.

Mechanism

Note

HFSC (Hierarchical Fair Service Curve), link-sharing service curve'ü (HFSC_FSC flag'i) olan class'ları per-parent bir "virtual-time tree" (vt-tree) içinde izler, böylece scheduler service edilecek bir sonraki class'ı seçebilir. Lifecycle invariant'ı simetridir: bir class'ın parent'ının vt-tree'sine her vttree_insert()'i, class deactivate olduğunda bir vttree_remove() ile dengelenmelidir. Bug bu simetriyi bozar. Bir link-sharing curve'ü olan bir class (HFSC_FSC set), link-sharing curve'ü olmayan bir parent'a attach edilirse, init_vf() yine parent üzerinde vttree_insert() çağırır, ama karşılık gelen vttree_remove() update_vf()'te atlanır, çünkü removal path parent'ın curve flag'lerine gate'lenmiştir. Dolayısıyla parent'ın vt-tree'si free edilebilecek bir class'a bir pointer tutar, dangling bir reference ve scheduler daha sonra tree'yi dolaştığında bir use-after-free verir.

Walkthrough

HFSC qdisc'i bir unprivileged user+net namespace içinden (o netns üzerinde CAP_NET_ADMIN) yapılandırılabilir, yani gerçek bir privilege gerekmez:

unshare(CLONE_NEWUSER | CLONE_NEWNET);   /* CAP_NET_ADMIN in new netns */

Asimetrik hiyerarşiyi kurun: link-sharing (ls/sc) curve'ü olmayan bir root/parent HFSC class, sonra bir curve'ü olan bir child class. tc, service-curve knob'larını doğrudan expose eder:

# root HFSC qdisc
tc qdisc add dev lo root handle 1: hfsc default 1
# parent class with NO link-sharing curve (e.g. only upper-limit / real-time)
tc class add dev lo parent 1: classid 1:1 hfsc ul rate 100mbit
# child class WITH a link-sharing curve under the curve-less parent
tc class add dev lo parent 1:1 classid 1:2 hfsc ls rate 50mbit

Child'ı activate/deactivate etmek (içinden trafik geçirmek ya da onu silmek) init_vf()/update_vf()'i sürer; eksik vttree_remove(), free edilmiş child'ı 1:1'in vt-tree'sinden reachable bırakır. Sonraki bir scheduler geçişi ya da teardown, dangling node'u dereference eder ve bir heap spray'in bir function pointer kontrolüne ve nihayetinde root'a çevirebileceği bir UAF üretir.

Minimal bir trigger, HFSC vt-tree dolaşması içinde (hfsc_dequeue / vttree ile ilgili kod) bir KASAN use-after-free splat'i verir.

Detection

  • KASAN, HFSC vt-tree fonksiyonlarında (init_vf/update_vf/vttree_*) use-after-free Read/Write raporlar.
  • Bir child'ın ls/sc (link-sharing) taşıdığı ama parent'ının taşımadığı bir HFSC class hiyerarşisinin oluşturulması — alışılmadık bir yapılandırma — özellikle bir unprivileged user namespace içinden, davranışsal imzadır.

Mitigation

  • Commit b3d26c5702c7d6c45456326e56d2ccf3f103e60f ile düzeltildi; eksik validation/removal'ı ekler, böylece inner class'lar doğru ele alınır.
  • CAP_NET_ADMIN'e giden unprivileged path'i kaldırmak için unprivileged namespace'leri kısıtlayın (kernel.unprivileged_userns_clone=0) ve HFSC kullanılmayan yerde CONFIG_NET_SCH_HFSC'yi disable edin.

References