| 1 | #include <elf.h> |
| 2 | #include <poll.h> |
| 3 | #include <fcntl.h> |
| 4 | #include <signal.h> |
| 5 | #include <unistd.h> |
| 6 | #include "syscall.h" |
| 7 | #include "atomic.h" |
| 8 | #include "libc.h" |
| 9 | |
| 10 | static void dummy(void) {} |
| 11 | weak_alias(dummy, _init); |
| 12 | |
| 13 | extern weak hidden void (*const __init_array_start)(void), (*const __init_array_end)(void); |
| 14 | |
| 15 | static void dummy1(void *p) {} |
| 16 | weak_alias(dummy1, __init_ssp); |
| 17 | |
| 18 | #define AUX_CNT 38 |
| 19 | |
| 20 | #ifdef __GNUC__ |
| 21 | __attribute__((__noinline__)) |
| 22 | #endif |
| 23 | void __init_libc(char **envp, char *pn) |
| 24 | { |
| 25 | 	size_t i, *auxv, aux[AUX_CNT] = { 0 }; |
| 26 | 	__environ = envp; |
| 27 | 	for (i=0; envp[i]; i++); |
| 28 | 	libc.auxv = auxv = (void *)(envp+i+1); |
| 29 | 	for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT) aux[auxv[i]] = auxv[i+1]; |
| 30 | 	__hwcap = aux[AT_HWCAP]; |
| 31 | 	if (aux[AT_SYSINFO]) __sysinfo = aux[AT_SYSINFO]; |
| 32 | 	libc.page_size = aux[AT_PAGESZ]; |
| 33 | |
| 34 | 	if (!pn) pn = (void*)aux[AT_EXECFN]; |
| 35 | 	if (!pn) pn = ""; |
| 36 | 	__progname = __progname_full = pn; |
| 37 | 	for (i=0; pn[i]; i++) if (pn[i]=='/') __progname = pn+i+1; |
| 38 | |
| 39 | 	__init_tls(aux); |
| 40 | 	__init_ssp((void *)aux[AT_RANDOM]); |
| 41 | |
| 42 | 	if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID] |
| 43 | 		&& !aux[AT_SECURE]) return; |
| 44 | |
| 45 | 	struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} }; |
| 46 | 	int r = |
| 47 | #ifdef SYS_poll |
| 48 | 	__syscall(SYS_poll, pfd, 3, 0); |
| 49 | #else |
| 50 | 	__syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8); |
| 51 | #endif |
| 52 | 	if (r<0) a_crash(); |
| 53 | 	for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL) |
| 54 | 		if (__sys_open("/dev/null", O_RDWR)<0) |
| 55 | 			a_crash(); |
| 56 | 	libc.secure = 1; |
| 57 | } |
| 58 | |
| 59 | static void libc_start_init(void) |
| 60 | { |
| 61 | 	_init(); |
| 62 | 	uintptr_t a = (uintptr_t)&__init_array_start; |
| 63 | 	for (; a<(uintptr_t)&__init_array_end; a+=sizeof(void(*)())) |
| 64 | 		(*(void (**)(void))a)(); |
| 65 | } |
| 66 | |
| 67 | weak_alias(libc_start_init, __libc_start_init); |
| 68 | |
| 69 | typedef int lsm2_fn(int (*)(int,char **,char **), int, char **); |
| 70 | static lsm2_fn libc_start_main_stage2; |
| 71 | |
| 72 | int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv, |
| 73 | 	void (*init_dummy)(), void(*fini_dummy)(), void(*ldso_dummy)()) |
| 74 | { |
| 75 | 	char **envp = argv+argc+1; |
| 76 | |
| 77 | 	/* External linkage, and explicit noinline attribute if available, |
| 78 | 	 * are used to prevent the stack frame used during init from |
| 79 | 	 * persisting for the entire process lifetime. */ |
| 80 | 	__init_libc(envp, argv[0]); |
| 81 | |
| 82 | 	/* Barrier against hoisting application code or anything using ssp |
| 83 | 	 * or thread pointer prior to its initialization above. */ |
| 84 | 	lsm2_fn *stage2 = libc_start_main_stage2; |
| 85 | 	__asm__ ( "" : "+r"(stage2) : : "memory" ); |
| 86 | 	return stage2(main, argc, argv); |
| 87 | } |
| 88 | |
| 89 | static int libc_start_main_stage2(int (*main)(int,char **,char **), int argc, char **argv) |
| 90 | { |
| 91 | 	char **envp = argv+argc+1; |
| 92 | 	__libc_start_init(); |
| 93 | |
| 94 | 	/* Pass control to the application */ |
| 95 | 	exit(main(argc, argv, envp)); |
| 96 | 	return 0; |
| 97 | } |