Retpoline¶
Google's "return trampoline": rewrite every indirect
call/jmpso the CPU's speculative path is captured in apause/lfenceloop instead of following a poisoned BTB target — defeating Spectre v2 branch target injection.
Mechanism¶
Neden çalışır
Spectre v2 (branch target injection)
çalışır çünkü bir saldırgan Branch Target Buffer (BTB)'yi eğitir ki bir victim'in
indirect branch'i (call *%rax, jmp *%rdx) gerçek hedef çözülmeden önce
spekülatif olarak saldırgan-seçimli bir gadget'a atlasın.
Bir retpoline, indirect branch'i spekülasyon yolundan tamamen kaldırır. Hile:
CPU'nun predict edecek tek kalan branch'i bir ret'tir ve ret, BTB'den değil,
Return Stack Buffer (RSB)'den predict edilir. Önce doğrudan bir call ayarlayarak,
konstrüksiyon güvenli, iyi huylu bir pause/lfence loop'una işaret eden bir RSB
entry'si yerleştirir. Bu arada stack'teki gerçek return address, hakiki hedefle
overwrite edilir.
Sonuç bir invariant'tır: mimari olarak ret gerçek hedefe gider; spekülatif olarak
RSB, CPU'yu spin loop'una gönderir; orada misprediction çözülene kadar zararsızca
spin'ler. Saldırganın zehirlenmiş BTB entry'sine asla başvurulmaz, bu yüzden bir
gadget'a ulaşacak bir pencere yoktur.
Walkthrough¶
1. Klasik thunk. *%r11'e bir indirect branch için, compiler bunun yerine bir
trampoline'e doğrudan bir call üretir. Konstrüksiyon (Google'ın açıklamasına göre)
şöyledir:
call set_up_target ; (1) push return addr -> trains RSB to capture_spec
capture_spec:
pause ; (4) speculation is trapped here, spinning
jmp capture_spec
set_up_target:
mov %r11, (%rsp) ; (2) overwrite return addr with the REAL target
ret ; (3) architecturally returns to *%r11
(1)doğrudancall, return address olarakcapture_spec'i push eder vecapture_spec'e bir return predict eden bir RSB entry'si oluşturur.(2)gerçek hedef (%r11), stack üzerindeki return address'in üzerine yazılır.(3)retmimari olarak gerçek hedefe atlar; spekülatif olarak CPU(1)'deki RSB entry'sini tüketir ve(4)'tekipauseloop'una düşer.
pause (ve bazı varyantlarda lfence) spekülatif loop'un yürütme kaynaklarını
tüketmesini engeller, böylece hassas bir gadget'a yönlendirilemez.
2. Retpoline'lerle bir kernel build etme. Compiler thunk'ları üretir; kernel, hot-patch edilebilsin diye harici bir thunk'a link'lenir:
# GCC
-mindirect-branch=thunk-extern -mindirect-branch-register
# Clang
-mretpoline-external-thunk
# Kconfig
CONFIG_MITIGATION_RETPOLINE=y # (older trees: CONFIG_RETPOLINE)
3. Runtime'da aktif olduğunu doğrula.
$ cat /sys/devices/system/cpu/vulnerabilities/spectre_v2
Mitigation: Retpolines, IBPB: conditional, RSB filling, ...
Retpoline'ler return'leri korumaz
Retpoline yalnızca indirect call'ları/jump'ları etkisiz kılar. Tüm konstrüksiyon
ret'in güvenli olmasına dayanır — ama bazı microarchitecture'larda ret
predictor'ının kendisi BTB'den eğitilebilir, ki bu tam olarak
Retbleed açığıdır. Bu yüzden retpoline tek başına
etkilenen AMD Zen 1/2 ve belirli Intel core'larında yetersizdir ve bir
return thunk ile eşlenmelidir.
Mitigation¶
(Artık risk / bypass.) Retbleed'in ötesinde, RSB underflow edebilir: RSB boşaldığında
(derin call stack'leri, context switch'ler, SMM çıkışları) bazı CPU'lar ret prediction'ı
için BTB'ye geri döner ve saldırıyı yeniden açar. Kernel bunu, context switch ve VM exit'te
RSB stuffing/filling ile karşılar. Daha yeni
parçalarda, hardware eIBRS genellikle retpoline'e tercih edilir.
References¶
- Google. Retpoline: a software construct for preventing branch-target-injection. (arşiv kopyası) — https://web.archive.org/web/20191220152200/https://support.google.com/faqs/answer/7625886
- The Linux Kernel. Spectre Side Channels — admin guide. — https://docs.kernel.org/admin-guide/hw-vuln/spectre.html