Skip to content

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:

BPF_REG_AX = (random_key ^ imm)
BPF_REG_AX ^= random_key
REG OP BPF_REG_AX

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.

References