Use of uninitialized variable¶
Bir stack veya heap variable'ını atanmadan önce okumak; böylece değeri o belleği işgal eden eski byte'lar ne ise odur — bir info leak ya da bir control-flow tehlikesi.
Mechanism¶
C/C++'ta automatic (stack) ve yeni malloc'lanmış storage sıfırla
initialize edilmez; önceki bir frame'in veya allocation'ın geride bıraktığı her
şeyi muhafaza eder. CWE-457 sonucu şöyle çerçeveler:
Note
"In languages like C and C++, stack variables lack default initialization and contain junk data from previous stack memory. Attackers may sometimes control or read these contents." — CWE-457
İki ayrı güvenlik sonucu doğar. (1) Information disclosure: uninitialized
byte'lar kullanıcıya kopyalanırsa (örneğin bir struct'ı dolduran ama padding/
kullanılmayan alanlara dokunmayan, ardından tüm struct'ı copy_to_user ile
gönderen bir kernel ioctl'ü), eski kernel pointer'ları ya da sırlar leak olur —
yaygın bir KASLR-defeat primitive'i. (2) Control hazard: uninitialized bir
pointer veya uzunluk, bir branch'i ya da bir dereference'i attacker'ın
etkileyebileceği eski bir değere doğru yönlendirir.
Walkthrough¶
CWE-457 control-flow örneği:
char *test_string;
if (i != err_val) {
test_string = "Hello World!";
}
printf("%s", test_string); /* if i == err_val, test_string is junk */
i == err_val olduğunda test_string hiç atanmamıştır ve printf("%s", ...)
garbage'ı dereference eder. Düzeltme koşulsuz initialization'dır:
char *test_string = "Done at the beginning";.
Kernel tarzı padding leak (pratik exploitation biçimi):
struct info {
u32 a; /* set */
/* 4 bytes of implicit padding here -- NEVER written */
u64 ptr; /* set */
};
struct info k;
k.a = x;
k.ptr = y;
/* the 4 padding bytes still hold prior stack contents */
if (copy_to_user(uptr, &k, sizeof(k))) /* leaks 4 stale kernel bytes */
return -EFAULT;
MemorySanitizer ile tespit
Detection¶
MemorySanitizer (-fsanitize=memory) ve Valgrind/memcheck, uninitialized belleğin
okunmasını runtime'da işaretler. Linux kernel aynısı için KMSAN kullanır;
-Wuninitialized -Wmaybe-uninitialized ile derle. Auto-init mitigation'ları
(-ftrivial-auto-var-init=zero, CONFIG_INIT_STACK_ALL_ZERO) hem bunları önler
hem de yüzeye çıkarmaya yardımcı olur.
Mitigation¶
Tanımda initialize et; bir trust boundary'yi geçen struct'ları kısmen doldurmadan
önce padding'i açıkça sıfırla (memset(&k, 0, sizeof k)); compiler/kernel'de
stack-variable auto-init'i etkinleştir. Tüm object'i kapsayan designated
initializer'ları tercih et.