Skip to content

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
Compiler kontrolü: -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.

References