STACKLEAK stack erase on syscall return¶
Her userspace'e return'de kernel stack'inin kullanılmış kısmını poison'layan bir GCC-plugin hardening'i (grsecurity/PaX'ten port edilmiş); uninitialized-stack infoleak'leri öldürür ve hassas stack data'sının ömrünü kısaltır.
Mechanism¶
STACKLEAK, bugün CONFIG_KSTACK_ERASE ("clear stack on a syscall return")
tarafından kapatılan Linux CONFIG_GCC_PLUGIN_STACKLEAK feature'ıdır. Bir GCC
plugin'i kernel'i instrument eder; her syscall'un sonunda, user space'e return
etmeden önce, kernel, syscall'un gerçekten dokunduğu kernel stack porsiyonunu bir
poison değeriyle overwrite eder.
Neden işe yarar
Kernel stack frame'leri entry'de sıfırlanmaz, dolayısıyla uninitialized bir
local okuyan bir function — ya da partially-filled bir struct'ın
copy_to_user()'ı — önceki, daha derin bir call chain'in stack'te bıraktığı
her şeyi leak edebilir: pointer'lar (KASLR'yi yenerek), credential'lar ya da
başka secret'lar. STACKLEAK, bu tür leak'lerin dayandığı önkoşulu kırar:
attacker-useful stale data'nın çağrılar arasında stack'te kalıcı olması. Her
syscall'dan sonra kullanılmış bölge STACKLEAK_POISON (-0xBEEF) sabitine
set edilir, böylece sonraki bir uninitialized read residual data yerine bilinen,
secret-olmayan, pointer-ımsı-olmayan bir sabit görür. Ayrıca temporal pencereyi
de kısaltır: tek bir syscall içinde bile en derin önceki kullanım silinmiştir.
Yalnızca stack'in kullanılmış kısmı temizlendiği için — sürekli güncellenen
bir lowest_stack water-mark'ı üzerinden izlenir — maliyet call complexity'siyle
değil stack depth'iyle ölçeklenir, ki bu yüzden ucuzdur. Aynı instrumentation
bir runtime kernel-stack-depth/overflow check'i de ekler.
Walkthrough¶
Kernel config'inde etkinleştir (iki option birlikte çalışır, ikisi de =y olmalı):
CONFIG_KSTACK_ERASE=y # (historically CONFIG_GCC_PLUGIN_STACKLEAK=y)
CONFIG_GCC_PLUGIN_STACKLEAK=y # GCC plugin that does the instrumentation
CONFIG_STACKLEAK_METRICS=y # optional: expose metrics
CONFIG_STACKLEAK_RUNTIME_DISABLE=y # optional: allow runtime toggle
CONFIG_KSTACK_ERASE alternatif değil, feature'ın modern umbrella/menu config'idir
ve altındaki CONFIG_GCC_PLUGIN_STACKLEAK plugin'ini gate'ler; historically feature
yalnızca CONFIG_GCC_PLUGIN_STACKLEAK adıyla vardı. Feature'ın aktif olması için
ikisi de =y olmalıdır.
Çekirdek runtime parçaları (kernel/stackleak.c'den, sonradan kernel/kstack_erase.c):
STACKLEAK_POISON = -0xBEEF # value written into the used stack region
current->lowest_stack # per-task water-mark of deepest stack use
stackleak_track_stack() # plugin-inserted; updates lowest_stack
stackleak_erase() # runs before return-to-user; poisons stack
Runtime'da değiştir (runtime-disable seçeneğiyle build edildiğinde):
Syscall başına kavramsal akış
syscall entry
└─ deep call chain runs; stackleak_track_stack() keeps lowest_stack
pointing at the deepest byte touched
syscall exit (return to user)
└─ stackleak_erase():
from current stack pointer down to lowest_stack,
write STACKLEAK_POISON over every byte
└─ lowest_stack reset for next syscall
A subsequent syscall that reads an uninitialized local now reads
0x...BEEF instead of a leftover kernel pointer or secret.
Uyarılar
- STACKLEAK eşleşen GCC plugin'ini gerektirir; yalnızca GCC'ye özgü bir
feature'dır (Clang,
-ftrivial-auto-var-initgibi farklı mekanizmalar kullanır). - Syscall return'ünde poison'lar, dolayısıyla data onu üreten syscall'un süresi boyunca canlıdır — exposure penceresini ortadan kaldırmaz, azaltır.
- Variable'ları bir function içinde ilk kullanımdan önce initialize etmez; bunun için stack auto-init ile eşle (bkz. Mitigation).
Detection¶
Feature'ın derlemeye dahil edildiğini ve aktif olduğunu doğrula:
grep -E 'KSTACK_ERASE|GCC_PLUGIN_STACKLEAK' /boot/config-$(uname -r)
sysctl kernel.stack_erasing # 1 when erasing is enabled
In-tree self-test (lkdtm STACKLEAK_ERASING / STACKLEAK test driver),
stack'in gerçekten silindiğini doğrulamak için poison-and-erase path'ini çalıştırır.
Mitigation¶
Residual risk ve saldırganların başa çıkma yolu:
- Üreten syscall sırasında (erase çalışmadan önce) leak edilen data hâlâ ulaşılabilirdir; STACKLEAK same-syscall leak'leri değil, cross-syscall stale data'yı hedefler.
- Bir field'ı userspace'e açıkça ama yanlış initialize edilmiş halde kopyalayan logic'i durdurmaz.
- Tam coverage için, compiler stack auto-initialization'ı (stack-variable-auto-init.md) ve structure-init plugin'i (structleak-structure-auto-init.md), artı copy-boundary hardening'i (hardened-usercopy.md) ile birleştir. Önlediği pointer leak'leri ayrıca kernel-address-space-layout-randomization.md'i de korur.
References¶
- Linux kernel docs, "Kernel Self-Protection" (Memory poisoning —
CONFIG_KSTACK_ERASE): https://docs.kernel.org/security/self-protection.html - LWN, "Introduce the STACKLEAK feature and a test for it": https://lwn.net/Articles/735584/
- LWN, "gcc-plugins: Add stackleak feature erasing the kernel stack at the end of syscalls": https://lwn.net/Articles/725287/