STRUCTLEAK structure auto-init¶
Compiler'ın aksi halde uninitialized bırakacağı on-stack structure'ları zero-initialize eden bir GCC-plugin hardening'i (grsecurity/PaX'ten port edilmiş); yaygın bir kernel stack infoleak kaynağını kapatır.
Mechanism¶
CONFIG_GCC_PLUGIN_STRUCTLEAK, uninitialized bırakılan local structure
variable'larını bulup onlara bir zero-initialization ekleyen bir GCC plugin'idir.
Seçilen coverage seviyesine bağlı olarak ya bir __user attribute'u içeren
structure'ları, ya reference ile geçilen structure'ları, ya da bu tür tüm
local'leri hedefler.
Neden işe yarar
Kernel, kaçırılmış stack-variable initialization'ı için warning'lerle build
edilir, ama dokümantasyon, başka bir function'a reference ile geçilen herhangi
bir şey için o warning'in susturulduğunu belirtir — "function'ın
initialization'ı yapacağına dair ara sıra yanıltıcı olan varsayım altında." O
varsayım yanlış olduğunda, bir struct stack'in tuttuğu her stale byte'ı korur
(artık pointer'lar, secret'lar, padding delikleri). Böyle bir struct — ya da
padding'i — daha sonra userspace'e kopyalanırsa, o byte'lar leak eder.
STRUCTLEAK şu önkoşulu kırar: uninitialized struct memory attacker-useful
artık taşır: tüm structure'ı (padding/delikler dahil) definition'da
sıfırlayarak, code'un set etmeyi unuttuğu herhangi bir field ya da delik,
stale kernel data yerine 0 olarak okunur. __user-only mode'u, kernel/user
boundary'sini geçme olasılığı en yüksek structure'lara tam isabetle yönelen
ucuz, hedefli bir varyanttır, dolayısıyla minimal maliyetle "bazı information
exposure sınıflarını" önler.
Varyantlar (coverage seviyeleri):
GCC_PLUGIN_STRUCTLEAK_USER # zero-init structs containing a __user pointer
GCC_PLUGIN_STRUCTLEAK_BYREF # zero-init structs that may be passed by reference
GCC_PLUGIN_STRUCTLEAK_BYREF_ALL # broadest: aim to eliminate all such uninit cases
GCC_PLUGIN_STRUCTLEAK_VERBOSE # emit which variables were instrumented
Walkthrough¶
Plugin'i etkinleştir ve kernel config'inde bir coverage seviyesi seç:
CONFIG_GCC_PLUGIN_STRUCTLEAK=y
CONFIG_GCC_PLUGIN_STRUCTLEAK_USER=y # or _BYREF / _BYREF_ALL
CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE=y # optional build-time reporting
Kapattığı bug sınıfı
struct layout {
__u32 a;
/* 4 bytes of implicit padding here */
__u64 b;
};
long do_ioctl(void __user *arg)
{
struct layout out; /* uninitialized: stale stack bytes */
out.a = 1;
out.b = 2;
/* out.a and out.b are set, but the 4-byte padding hole is NOT.
copy_to_user leaks 4 bytes of leftover kernel stack data. */
return copy_to_user(arg, &out, sizeof(out));
}
out'un tam bir zeroing'ini
(padding deliğini de kapsayarak) ekler, böylece kopyalanan padding residual
kernel memory yerine 0 olur.
Uyarılar ve soy
- STRUCTLEAK yalnızca GCC'dir (bir plugin). Stack'teki padding dahil her şeyi
zero-initialize eden, compiler-agnostic whole-stack yaklaşımı
CONFIG_INIT_STACK_ALL_ZERO'nun (Clang/GCC-ftrivial-auto-var-init=zero) öncülü/akrabasıdır — bkz. Mitigation. STRUCTLEAK_USERyalnızca bir__usermember'ı olan struct'ları kapsar, dolayısıyla başka path'ler üzerinden yine de userspace'e ulaşan non-__userstruct'lar o mode tarafından kapsanmaz; daha geniş mode'lar daha pahalıdır.- Structure'ları initialize eder; scalar local'ler ve daha geniş uninitialized-read sınıfı, full stack auto-init tarafından daha iyi ele alınır.
Detection¶
Plugin'in derlemeye dahil edildiğini doğrula:
..._VERBOSE=y ile, build log'u her instrument edilen variable'ı raporlar; bu da
maintainer'ların plugin'in neye dokunduğunu görmesini sağlar.
Mitigation¶
Residual risk / daha tam coverage'ı nasıl elde edilir:
- STRUCTLEAK structure'ları ele alır; modern, kapsamlı ikame, tüm stack
variable'larının zorla initialization'ıdır
(stack-variable-auto-init.md, yani
CONFIG_INIT_STACK_ALL_ZERO/-ftrivial-auto-var-init); bu, STRUCTLEAK'in yaptığının çoğunu kapsar ve compiler-agnostic'tir. - Cross-syscall artığı da sınırlamak için stack-erase-on-return (stackleak-stack-erase-on-syscall-return.md) ile, ve heap karşılığı için heap-init (init-on-alloc.md / init-on-free.md) ile eşle.
- Copy-boundary check'leri (hardened-usercopy.md), aksi halde leak edecek bazı over-read'leri yakalar. Bunların önlediği pointer leak'leri ayrıca kernel-address-space-layout-randomization.md'i de savunur.
References¶
- Linux kernel docs, "Kernel Self-Protection" (Memory initialization): https://docs.kernel.org/security/self-protection.html
- Linux Kernel Driver DataBase,
CONFIG_GCC_PLUGIN_STRUCTLEAK: https://cateee.net/lkddb/web-lkddb/GCC_PLUGIN_STRUCTLEAK.html