eBPF verifier abuse¶
Find a bug where the verifier's tracked register bounds diverge from the real runtime value, then build OOB pointer arithmetic on a BPF map to obtain arbitrary kernel read/write.
Mechanism¶
Note
BPF verifier'ı, load'dan önce bir program'ın güvenli olduğunu statik olarak kanıtlar.
Her register için scalar bounds takip eder — umin_value/umax_value,
smin_value/smax_value, artı 32-bit variant'lar — ve bir tnum var_off
({mask, value}: mask'te set olan bit'ler unknown'dır). Loop/back-edge'leri ve pointer
karşılaştırmalarını yasaklar, yalnızca pointer'lara eklenen scalar'lara izin verir ve
pointer arithmetic'in bir map'in güvenli bounds'u içinde kalmasını gerektirir. Tüm
verifier exploit sınıfı tek bir invariant kırılmasına iner: bir scalar'ın takip edilen
bounds'unu gerçek runtime değeriyle uyuşmaz hâle getir (verifier R = 0 sanır, runtime
R = 1), sonra o register'ı bir BPF map value/array pointer'ına karşı offset olarak
kullan; böylece verifier erişimin in-bounds olduğuna inanırken o aslında out of bounds'tur.
Walkthrough¶
chompie1337'nin "Kernel Pwning with eBPF: a Love Story"'sindeki gibi generic primitive inşası:
- "0-ama-aslında-1" bir register elde etmek için verifier bug'ını tetikle.
- Onu bir map value/array üzerinde pointer arithmetic'te kullan -> map belleği üzerinde OOB read ve OOB write.
- Bir map value üzerinden bir kernel pointer leak'le, kernel base'ini hesapla.
- Bir hedefi overwrite et — klasik olarak
credstruct'ı (uid 0 yap) ya damodprobe_path.
Altyapı: bpf() syscall'ı (BPF_MAP_CREATE, BPF_MAP_UPDATE_ELEM,
BPF_MAP_LOOKUP_ELEM) ve map value'larına pointer elde etmek için map_lookup_elem helper'ı.
Warning
O blog'daki işlenmiş örnek, ayrı ZDI CVE-2020-8835 değil, CVE-2021-3490'dır (ALU32 bitwise bounds). Her belirli verifier bug'ı için özel kayıtlara bakın; bu not yeniden kullanılabilir istismar kalıbını kapsar.
Mitigation¶
sysctl kernel.unprivileged_bpf_disabled=1 (ya da BPF_UNPRIV_DEFAULT_OFF) unprivileged
load'u bloklar. Constant blinding (net.core.bpf_jit_harden) ve read-only JIT page'leri
post-exploitation adımını sertleştirir. Altta yatan her verifier bug'ı kernel/bpf/verifier.c
içinde bounds-tracking düzeltmeleri olarak tek tek fix'lenir.