eBPF JIT spray¶
Encode native shellcode bytes inside a BPF program's immediate constants so the JIT emits them into executable kernel memory, then jump to the planted payload — defeated by constant blinding.
Mechanism¶
Note
Bir BPF program'ının 32-bit immediate sabitleri (örneğin BPF_LD/BPF_MOV imm), JIT
tarafından native makine koduna birebir yayımlanır. x86 shellcode byte'larını encode
eden immediate'lar seçerek attacker, bir kernel JIT page'ine yürütülebilir byte'lar
diker. Tarihsel olarak o page'ler JIT bölgesinde ASLR olmadan tahmin edilebilir
adreslerde RWX idi, dolayısıyla attacker gömülü payload'a atlar (ya da içine slide
eder). Keegan McAllister'ın "Attacking hardened Linux systems with kernel JIT spraying"
(2012) çalışmasından gelir. Bu doküman spesifik olarak immediate-constant-encoding
variant'ını (shellcode byte'larını BPF immediate sabitlerine gömme) ele alır;
bpf-jit-spray ise mid-instruction gadget / ret2bpf çerçevelemesini
vurgular.
Walkthrough¶
Fikir: encode edilmiş byte'ları bir NOP-sled + payload oluşturan bir immediate load zinciri. Attacker sonra kontrolü sprayed RWX bölgesi içinde tahmin edilen bir adrese aktarır. (Modern kernel'ler JIT page'lerini read-only/executable ve randomize yapar, dolayısıyla bu aşağıdaki savunmaları aşmayı gerektirir.)
Belirleyici mitigation, 4f3446bb809f commit'inde eklenen constant blinding'dir
("bpf: add generic constant blinding for use in jits", Linux 4.7). bpf_jit_blind_constants()
program'ı klonlar ve sabit taşıyan her instruction'ı, gizli bir yardımcı register BPF_REG_AX
(#define BPF_REG_AX MAX_BPF_REG) kullanarak bpf_jit_blind_insn() üzerinden yeniden yazar:
Gerçek sabit asla kontrol edilebilir bir immediate olarak görünmez — instruction-başına
rastgele bir key ile yapılan bir XOR'a bölünür, dolayısıyla attacker artık JIT çıktısına
seçtiği byte'ları yerleştiremez. net.core.bpf_jit_harden ile kontrol edilir: 0 kapalı
(default), 1 unprivileged için blind, 2 herkes için blind.
Warning
Blinding ile bile JIT bölgesinin yerleşimi bir araştırma hedefiydi — Reshetova ve ark., "Randomization Can't Stop BPF JIT Spray" (Black Hat EU 2016) — dolayısıyla gerçek savunma tek başına blinding değil, blinding artı page hardening'dir.
Mitigation¶
net.core.bpf_jit_harden=2— tüm kullanıcılar için constant blinding.CONFIG_BPF_JIT_ALWAYS_ON; JIT page'leri RWX yerine read-only + executable (set_memory_ro/set_memory_x) yapılır.kernel.unprivileged_bpf_disabled=1/BPF_UNPRIV_DEFAULT_OFF, unprivileged attack surface'ı tamamen kaldırır.