Created
May 21, 2023 18:42
-
-
Save itamaro/bca973ae5cb962dec3a9704d0feea656 to your computer and use it in GitHub Desktop.
py-setproctitle find_argv_from_env heap buffer underflow repro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# build it with ASAN | |
clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer test.cpp -o test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# run without args | |
./test | |
argv = 0x7ffd68aa6f58 argv[0] = 0x7ffd68aa8dd5 | |
environ = 0x7ffd68aa6f68:SHELL=/bin/bash at 89 | |
environ = 0x7ffd68aa6f68 at 99 | |
walking from environ to look for the arguments | |
environ = 0x7ffd68aa6f68 at 31 | |
ptr = 0x602000000030:SHELL=0 | |
found environ at 0x602000000030 | |
argv[0] should be at 0x602000000029 | |
================================================================= | |
==4060496==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000029 at pc 0x0000004a3e13 bp 0x7ffd68aa6db0 sp 0x7ffd68aa6560 | |
READ of size 1 at 0x602000000029 thread T0 | |
#0 0x4a3e12 in __interceptor_strcmp.part.0 (/data/users/itamaro/repro/test+0x4a3e12) | |
#1 0x620df7 in find_argv_from_env(int, char*) /data/users/itamaro/repro/test.cpp:70:9 | |
#2 0x620b45 in main /data/users/itamaro/repro/test.cpp:101:16 | |
#3 0x7fe82262c656 in __libc_start_call_main /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/nptl/libc_start_call_main.h:58:16 | |
#4 0x7fe82262c717 in __libc_start_main_impl /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:409:3 | |
#5 0x421080 in _start /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/x86_64/start.S:116 | |
0x602000000029 is located 7 bytes to the left of 8-byte region [0x602000000030,0x602000000038) | |
allocated by thread T0 here: | |
#0 0x4c827f in malloc (/data/users/itamaro/repro/test+0x4c827f) | |
#1 0x7fe82264743b in __add_to_environ /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/stdlib/setenv.c:215:10 | |
#2 0x620b01 in main /data/users/itamaro/repro/test.cpp:98:3 | |
#3 0x7fe82262c656 in __libc_start_call_main /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/nptl/libc_start_call_main.h:58:16 | |
#4 0x7fe82262c717 in __libc_start_main_impl /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:409:3 | |
#5 0x421080 in _start /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/x86_64/start.S:116 | |
SUMMARY: AddressSanitizer: heap-buffer-overflow (/data/users/itamaro/repro/test+0x4a3e12) in __interceptor_strcmp.part.0 | |
Shadow bytes around the buggy address: | |
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
=>0x0c047fff8000: fa fa 00 00 fa[fa]00 fa fa fa 00 00 fa fa fd fd | |
0x0c047fff8010: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
0x0c047fff8020: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
0x0c047fff8030: fa fa 00 04 fa fa 00 fa fa fa fd fd fa fa 00 00 | |
0x0c047fff8040: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
0x0c047fff8050: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
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 | |
Shadow gap: cc | |
==4060496==ABORTING |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
./test 1 | |
argv = 0x7ffe77590bc8 argv[0] = 0x7ffe77591dd3 | |
environ = 0x7ffe77590be0:SHELL=/bin/bash at 89 | |
environ = 0x7ffe77590be0 at 99 | |
walking from environ to look for the arguments | |
environ = 0x7ffe77590be0 at 31 | |
ptr = 0x602000000030:SHELL=0 | |
found environ at 0x602000000030 | |
================================================================= | |
==4062348==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000002f at pc 0x000000620daf bp 0x7ffe77590a20 sp 0x7ffe77590a18 | |
READ of size 1 at 0x60200000002f thread T0 | |
#0 0x620dae in find_argv_from_env(int, char*) /data/users/itamaro/repro/test.cpp:43:13 | |
#1 0x620b45 in main /data/users/itamaro/repro/test.cpp:101:16 | |
#2 0x7f8a33a2c656 in __libc_start_call_main /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/nptl/libc_start_call_main.h:58:16 | |
#3 0x7f8a33a2c717 in __libc_start_main_impl /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:409:3 | |
#4 0x421080 in _start /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/x86_64/start.S:116 | |
0x60200000002f is located 1 bytes to the left of 8-byte region [0x602000000030,0x602000000038) | |
allocated by thread T0 here: | |
#0 0x4c827f in malloc (/data/users/itamaro/repro/test+0x4c827f) | |
#1 0x7f8a33a4743b in __add_to_environ /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/stdlib/setenv.c:215:10 | |
#2 0x620b01 in main /data/users/itamaro/repro/test.cpp:98:3 | |
#3 0x7f8a33a2c656 in __libc_start_call_main /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/nptl/libc_start_call_main.h:58:16 | |
#4 0x7f8a33a2c717 in __libc_start_main_impl /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:409:3 | |
#5 0x421080 in _start /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/x86_64/start.S:116 | |
SUMMARY: AddressSanitizer: heap-buffer-overflow /data/users/itamaro/repro/test.cpp:43:13 in find_argv_from_env(int, char*) | |
Shadow bytes around the buggy address: | |
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
=>0x0c047fff8000: fa fa 00 00 fa[fa]00 fa fa fa fd fd fa fa fd fd | |
0x0c047fff8010: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
0x0c047fff8020: fa fa fd fd fa fa fd fd fa fa fd fd fa fa 00 04 | |
0x0c047fff8030: fa fa 00 fa fa fa fd fd fa fa 00 00 fa fa fd fd | |
0x0c047fff8040: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
0x0c047fff8050: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd | |
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 | |
Shadow gap: cc | |
==4062348==ABORTING |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#ifndef ARG_MAX | |
#define ARG_MAX (96 * 1024) | |
#endif | |
extern "C" char **environ; | |
static char ** | |
find_argv_from_env(int argc, char *arg0) | |
{ | |
int i; | |
char **buf = NULL; | |
char **rv = NULL; | |
char *ptr; | |
char *limit; | |
printf("walking from environ to look for the arguments\n"); | |
if (!(buf = (char **)malloc((argc + 1) * sizeof(char *)))) { | |
printf("can't malloc %d args!\n", argc); | |
//PyErr_NoMemory(); | |
goto exit; | |
} | |
buf[argc] = NULL; | |
/* Walk back from environ until you find argc-1 null-terminated strings. | |
* Don't look for argv[0] as it's probably not preceded by 0. */ | |
printf("environ = %p at %d\n", environ, __LINE__); | |
ptr = environ[0]; | |
printf("ptr = %p:%s\n", ptr, ptr); | |
if (!ptr) { | |
/* It happens on os.environ.clear() */ | |
printf("environ pointer is NULL\n"); | |
goto exit; | |
} | |
printf("found environ at %p\n", ptr); | |
limit = ptr - ARG_MAX; | |
--ptr; | |
for (i = argc - 1; i >= 1; --i) { | |
if (*ptr) { | |
printf("zero %d not found\n", i); | |
goto exit; | |
} | |
--ptr; | |
while (*ptr && ptr > limit) { --ptr; } | |
if (ptr <= limit) { | |
printf("failed to found arg %d start\n", i); | |
goto exit; | |
} | |
buf[i] = (ptr + 1); | |
printf("found argv[%d] at %p: %s\n", i, buf[i], buf[i]); | |
} | |
/* The first arg has not a zero in front. But what we have is reliable | |
* enough (modulo its encoding). Check if it is exactly what found. | |
* | |
* The check is known to fail on OS X with locale C if there are | |
* non-ascii characters in the executable path. See Python issue #9167 | |
*/ | |
ptr -= strlen(arg0); | |
printf("argv[0] should be at %p\n", ptr); | |
if (ptr <= limit) { | |
printf("failed to found argv[0] start\n"); | |
goto exit; | |
} | |
if (strcmp(ptr, arg0)) { | |
printf("argv[0] doesn't match '%s'\n", arg0); | |
goto exit; | |
} | |
/* We have all the pieces of the jigsaw. */ | |
buf[0] = ptr; | |
printf("found argv[0]: %s\n", buf[0]); | |
rv = buf; | |
buf = NULL; | |
exit: | |
if (buf) { free(buf); } | |
return rv; | |
} | |
int main(int argc, char* argv[]) { | |
printf("argv = %p argv[0] = %p\n", argv, argv[0]); | |
printf("environ = %p:%s at %d\n", environ, environ[0], __LINE__); | |
char* dup = strdup(environ[0]); | |
char* tmp = dup; | |
while (*tmp++) { | |
if (*tmp == '=') { | |
*tmp = '\0'; | |
break; | |
} | |
} | |
setenv(dup, "0", 1); | |
printf("environ = %p at %d\n", environ, __LINE__); | |
auto argv1 = find_argv_from_env(argc, argv[0]); | |
free(dup); | |
return argv1 ? 0:1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment