Here's a minimal example of how I'm rasing the stack-use-after-return
error:
int *ptr; // global definition
// stack allocate and initialize`ptr`
void alloc() {
int local[10];
ptr = &local[0];
}
// make a `return`
int ret_after_use() {
return ptr[10];
}
int main() {
alloc();
int i = ret_after_use();
ptr = &i; // error: use after return
return 0;
}
As expected, Asan catches this problem and raises the following message (raw) -
=================================================================
==1011387==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f3ada500048 at pc 0x564ebacaa22c bp 0x7ffe3f0635d0 sp 0x7ffe3f0635c8
READ of size 4 at 0x7f3ada500048 thread T0
#0 0x564ebacaa22b in ret_after_use /home/aissy/c_cpp/understanding/UBs/stack_use_after_return.c:17:9
#1 0x564ebacaa4c9 in main /home/aissy/c_cpp/understanding/UBs/stack_use_after_return.c:31:11
#2 0x7f3adc23c78f in __libc_start_call_main /usr/src/debug/glibc-git/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#3 0x7f3adc23c849 in __libc_start_main@GLIBC_2.2.5 /usr/src/debug/glibc-git/glibc/csu/../csu/libc-start.c:360:3
#4 0x564ebabad084 in _start /home/aissy/aur/glibc-git/src/glibc/csu/../sysdeps/x86_64/start.S:115
Address 0x7f3ada500048 is located in stack of thread T0 at offset 72 in frame
#0 0x564ebacaa04f in alloc /home/aissy/c_cpp/understanding/UBs/stack_use_after_return.c:7
This frame has 1 object(s):
[32, 72) 'local' (line 8) <== Memory access at offset 72 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return /home/aissy/c_cpp/understanding/UBs/stack_use_after_return.c:17:9 in ret_after_use
Shadow bytes around the buggy address:
0x0fe7db497fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db497fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db497fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db497fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db497ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0fe7db498000: f5 f5 f5 f5 f5 f5 f5 f5 f5[f5]f5 f5 f5 f5 f5 f5
0x0fe7db498010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db498020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db498030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db498040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe7db498050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1011387==ABORTING
The part I'm interested about is the Shadow bytes around the buggy address:
part, particularly what I'm confused about is the addresses that are being shown here to indicate redzones, use-after-free etc. I don't understand where these addresses are coming from, nor how to read from those addresses in either my C program or a debugger like GDB.
I assume the block of memory or stack these addresses are referring to is not the address to the stack (by looking at sp
and bp
, they are not what it seems like).
Starting with the first of stack-after-return
(f5
), namely 0x0ffb70398000
, I want to know -
a) Where are these addresses coming from?
b) How to read from those addresses (the contents) in a debugger or my C program itself?