native image: hardening csu for old glibc (#827)

Workround of return-to-csu problem for old glibc, use non-initialized
static variables instead of the stack ones. See workround 2 of
https://i.blackhat.com/briefings/asia/2018/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf
This commit is contained in:
James Z.M. Gao
2023-04-06 16:57:51 +08:00
committed by GitHub
parent 5093ced94b
commit 99a5cfba7f
3 changed files with 20 additions and 14 deletions

View File

@@ -20,6 +20,7 @@
/* ref:
* https://elixir.bootlin.com/glibc/glibc-2.37.9000/source/csu/libc-start.c
* https://elixir.bootlin.com/glibc/glibc-2.33.9000/source/csu/elf-init.c#L68
* https://i.blackhat.com/briefings/asia/2018/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf
*/
#define _GNU_SOURCE
@@ -29,21 +30,26 @@
__asm__(".symver dlsym,dlsym@GLIBC_2.2.5");
__asm__(".symver dlvsym,dlvsym@GLIBC_2.2.5");
/* These magic symbols are provided by the linker. */
extern void (*__init_array_start[])(int, char **, char **) __attribute__ ((visibility ("hidden")));
extern void (*__init_array_end[])(int, char **, char **) __attribute__ ((visibility ("hidden")));
extern void _init(void);
/* These functions are passed to __libc_start_main by the startup code.
These get statically linked into each program. */
/* __libc_csu_init is statically linked into each program, and passed to __libc_start_main
* when the program is running with an old glibc (<2.34).
*/
static void
__libc_csu_init(const int argc, char **const argv, char **const envp)
{
/* These magic symbols are provided by the linker. */
extern void _init(void);
extern __typeof(&__libc_csu_init) __init_array_start[] __attribute__ ((visibility ("hidden"))),
__init_array_end[] __attribute__ ((visibility ("hidden")));
/* a workround of return-to-csu problem for old glibc,
* use non-initialized static variables instead of the stack ones.
*/
static __typeof(__init_array_start+0) base, end;
_init();
const __auto_type size = __init_array_end - __init_array_start;
for (__auto_type i = 0; i < size; ++i)
(*__init_array_start[i])(argc, argv, envp);
end = __init_array_end;
for (base = __init_array_start; base < end; ++base)
(*base)(argc, argv, envp);
}
int
@@ -60,7 +66,7 @@ __dynamic_libc_start_main(int (*const main)(int, char **, char **),
const __auto_type __libc_start_main = (__typeof(&__dynamic_libc_start_main))(uintptr_t)dlsym(RTLD_DEFAULT, "__libc_start_main");
if (!dlvsym(RTLD_DEFAULT, "__libc_start_main", "GLIBC_2.34")) {
init = &__libc_csu_init; // old runtime glibc, ver < 2.34
init = &__libc_csu_init; /* old runtime glibc, ver < 2.34 */
}
return __libc_start_main(main, argc, argv, init, fini, rtld_fini, stack_end);