Unprivileged user namespace attack surface¶
Unprivileged bir user namespace (
clone(CLONE_NEWUSER)), çağıran process'e namespace içinde full capability set verir — böylece eskiden root-only olan kernel kod path'leri (overlayfs, nftables/netfilter, birçok net/fs subsystem) unprivileged local attacker'a açılır ve bu tek başına en büyük LPE enabler'larından biri olur.
Mechanism¶
Invariant: capability namespace-scoped'tur, ama code path aynıdır
User namespace'in tasarım invariant'ı şudur: bir capability yalnızca onu
grant eden namespace ve child'ları içinde geçerlidir; parent namespace'te
hiçbir capability'ye dönüşmez. man7'nin ifadesiyle, CLONE_NEWUSER ile
yaratılan child "a complete set of capabilities in the new user namespace"
ile başlar. uid_map/gid_map sayesinde bir process, namespace dışında
normal unprivileged bir uid'e sahipken içeride uid 0 + CAP_SYS_ADMIN,
CAP_NET_ADMIN, CAP_NET_RAW vb. taşıyabilir.
Güvenlik açığı, bu capability'lerin hangi kod'u reachable yaptığındadır.
Capability check'i (ns_capable()) namespace-aware'dir, ama check'in
arkasındaki subsystem — nftables parser'ı, overlayfs copy-up path'i, bir net
scheduler qdisc'i — çoğunlukla namespace-naive, yıllarca yalnızca gerçek root
tarafından fuzz'lanmış eski C kodudur. Böylece boundary şöyle crossed olur:
attacker gerçek privilege kazanmaz; bunun yerine daha önce yalnızca root'un
dokunabildiği geniş bir kernel attack surface'e unprivileged erişim
kazanır. Tek bir memory-safety bug'ı (UAF, OOB, refcount, race) o surface
içinde host root'a pivot etmek için yeterlidir.
Neden en büyük LPE enabler'lardan biri
Public ölçümler bunu net yapıyor: systemshardening analizi unprivileged user
namespace'leri açmanın reachable kernel attack surface'i yaklaşık 3.4x
büyüttüğünü, Google'ın exploit telemetry'sinde ise gözlenen exploit'lerin
%44'ünün zincirlerinin parçası olarak unprivileged user namespace
gerektirdiğini raporluyor. nf_tables, overlayfs ve net/sched ailesindeki
onlarca LPE (bkz. bu KB'deki nf-tables ve overlayfs not'ları) tetikleyici
ön koşul olarak tam olarak bu tek unshare primitive'ine dayanır.
Walkthrough¶
Kavramsal (weaponize edilmemiş) reachability adımları — bir attacker'ın formerly-root subsystem'e nasıl ulaştığını, defender'ın anlaması için:
- Unprivileged process yeni bir user namespace açar ve içeride full capability set'e sahip olur:
/* tek syscall, hiçbir privilege gerektirmez */
unshare(CLONE_NEWUSER | CLONE_NEWNET); /* +CAP_SYS_ADMIN, +CAP_NET_ADMIN */
- uid/gid mapping kurulur ki içeride "root" görünülsün (bazı distro helper'ları
bunu
newuidmap/unshare -rile yapar):
# kavramsal: outer-unprivileged uid -> inner uid 0
echo "0 $(id -u) 1" > /proc/self/uid_map # sadeleştirilmiş
- Artık
ns_capable()gate'li subsystem'ler unprivileged'a reachable:
# normalde CAP_NET_ADMIN ister; şimdi namespace içinde geçer
nft add table inet t
# overlayfs mount, net scheduler qdisc, vb. de aynı şekilde açılır
- Attacker bu geniş surface içinde zaten disclosed/patched bir bug'ı tetikler (ör. bir nf_tables UAF ya da bir overlayfs copy-up flaw). Namespace içinde grant edilen capability + subsystem bug'ı, host'a etki eden bir memory-corruption primitive'ine dönüşür.
Neden fix her bug'ı ayrı yamalamakla bitmiyor
Surface o kadar geniştir ki (net, fs, crypto, keyring alt sistemleri) tek tek bug'ları kapatmak whack-a-mole olur. Bu yüzden hardening, bug'ı değil, unprivileged'ın user namespace açma yeteneğini hedefler — tüm surface'i tek hamlede kapatır.
Detection¶
- Telemetri: unprivileged uid'lerden gelen
unshare(2)/clone(2)çağrılarındaCLONE_NEWUSERflag'ini izleyin; ardından hızlıcaCLONE_NEWNET/CLONE_NEWNSgelmesi container-benzeri bir setup değilse anormaldir. - Bir user namespace açtıktan hemen sonra
nft/iptables,mount -t overlay, ya datc qdisc addgibi eskiden-root işlemlerini yapan process'ler yüksek değerli sinyaldir; audit'te-a always,exit -F arch=b64 -S unshare -S cloneile yakalayın. - Host-level: bir process'in
/proc/self/uid_map'e yazıp hemen kernel subsystem'lerine dokunması; KASAN/dmesg'teuse-after-free/slab-out-of-boundsimzalarının unprivileged bir uid ile korele olması. - Runtime EDR/eBPF:
user_namespacecreate eventlerini per-uid sayın; baseline dışı spike'lar (özellikle browser/sandbox olmayan binary'lerden) triage edin.
Mitigation¶
- En temiz kontrol: unprivileged user namespace yaratmayı kapatın.
Debian/Ubuntu türevlerinde
sysctl -w kernel.unprivileged_userns_clone=0; RHEL/Fedora türevlerindesysctl -w user.max_user_namespaces=0. Ubuntu'da her ikisini de set etmek önerilir çünkü ilkini set edipuser.max_user_namespaces'i pozitif bırakmak bazı kernel'lerde residual bir path bırakabilir. - Granular alternatif (Ubuntu 23.10+): binary on/off yerine AppArmor tabanlı
kontrol.
sysctl -w kernel.apparmor_restrict_unprivileged_userns=1(vekernel.apparmor_restrict_unprivileged_unconfined=1) ile yalnızca profilindeuserns,rule'u olan confined uygulamalar user namespace açabilir; geri kalan unprivileged process'lere kapalıdır. Bu, browser sandbox'ları gibi meşru kullanıcıları bozmadan surface'i daraltır. - Kernel limit: nesting zaten 32 seviyeyle sınırlıdır (aşımda
EUSERS), ama bu bir security kontrolü değildir; asıl kaldıraç yukarıdaki sysctl'lerdir. - Derinlik: seccomp ile container/sandbox içinden
unshare/cloneyeni-userns path'ini engelleyin; distro'nun subsystem yamalarını güncel tutun; user namespace'e ihtiyaç duymayan workload'larda systemd unit'lerindeRestrictNamespaces=kullanın.