Use-after-return¶
Bir local variable'a ait pointer'ı, fonksiyonu return ettikten sonra dereference etmek; stack frame gitmiştir ve slot daha sonraki call'lar tarafından yeniden kullanılır.
Mechanism¶
Bir fonksiyonun automatic variable'ları onun stack frame'inde yaşar. Fonksiyon return
ettiğinde, o frame mantıksal olarak yok edilir ve belleği, aynı (veya daha derin) stack
derinliğinde çağrılan sonraki fonksiyon tarafından yeniden kullanılır. Bu nedenle fonksiyondan
kaçan bir local'e ait bir pointer — return edilmiş, bir global'de saklanmış veya bir callback'e
sıkıştırılmış — fonksiyon return ettiği anda bir dangling-pointer hâline gelir. Klasik bug, bir
local'in adresini return etmektir:
char *get(void) {
char buf[16];
snprintf(buf, sizeof buf, "secret");
return buf; /* returns address of a frame that is about to die */
}
Note
Bu, use-after-free'nin stack karşılığıdır: bir chunk'ı geri dönüştüren heap allocator
yerine, frame'i call mekanizması geri dönüştürür. Leak edilen/kullanılan byte'lar, sonraki
call'un oraya yazdığı her ne ise odur, dolayısıyla bozulma timing- ve call-graph-bağımlıdır,
bu da onu hem değişken hem de gözden kaçırması kolay kılar.
Walkthrough¶
Değer, naive testi kandıracak kadar uzun süre hayatta kalır, sonra sonraki call tarafından ezilir:
#include <stdio.h>
char *get(void) {
char buf[16];
snprintf(buf, sizeof buf, "secret");
return buf; /* UAR: buf belongs to a dead frame */
}
int main(void) {
char *p = get();
printf("%s\n", p); /* may print "secret" by luck ... */
char other[16] = "AAAAAAAAAAAAAAA"; /* reuses the same frame slot */
printf("%s\n", p); /* now prints garbage / "AAAA..." */
}
AddressSanitizer bunu bir fake-stack şemasıyla tespit eder: detect_stack_use_after_return
açık olduğunda, kaçan local'ler return'de poison edilen, ayrıca yönetilen bir "fake stack"
region'ına yerleştirilir, böylece sonraki bir erişim gerçek frame belleğini sessizce yeniden
kullanmak yerine trap eder.
ASan UAR tespitini etkinleştirme ve gözlemleme
$ clang -fsanitize=address uar.c -o uar
$ ASAN_OPTIONS=detect_stack_use_after_return=1 ./uar
==4242==ERROR: AddressSanitizer: stack-use-after-return on address 0x...
#0 0x... in main uar.c:11
Address ... is located in stack of thread T0 at offset ... in frame
#0 0x... in get() uar.c:3
-fsanitize-address-use-after-return=(never|runtime|always);
runtime kontrolü: ASAN_OPTIONS=detect_stack_use_after_return=1 (Linux'ta varsayılan
olarak açık).
Detection¶
detect_stack_use_after_return=1'li (ve eşleşen -fsanitize-address-use-after-return modlu)
ASan güvenilir tespit edicidir; compiler'lar açık "return &local" formu için
-Wreturn-local-addr / -Wdangling-pointer üzerinden uyarır. Static analyzer'lar
automatic'lerin kaçan adreslerini işaretler.
Mitigation¶
Bir automatic'e ait bir pointer'ın frame'inden kaçmasına asla izin verme — değerle return et, caller'ın sağladığı bir buffer al veya açık ownership ile heap-allocate et. Compiler uyarılarını error olarak etkinleştir ve test/CI build'lerini ASan UAR tespiti açık olarak gönder.