-
Notifications
You must be signed in to change notification settings - Fork 606
i#1973: musl: Scan stack for kernel arguments when used as library #7266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
1affc20
9a41e6d
0a5730a
a5ce285
6d6c523
10b7f0e
fe3e877
6b12174
8875f7d
fb03426
f561bea
2d352c5
6cc679a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -788,6 +788,82 @@ static init_fn_t | |
| #else | ||
| /* If we're a normal shared object, then we override _init. | ||
| */ | ||
|
|
||
| # if defined(MUSL) | ||
| # define EFAULT 14 | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # define AT_EXECFN 31 | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| static int | ||
| check_address_readable(void *addr) | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| return dynamorio_syscall(SYS_rt_sigprocmask, ~0L, addr, NULL, | ||
| sizeof(kernel_sigset_t)) != EFAULT; | ||
| } | ||
|
|
||
| /* When entering the entry point, the stack layout looks like | ||
| * sp => argc | ||
| * argv | ||
| * NULL (end of argv) | ||
| * envp | ||
| * NULL (end of envp) | ||
| * auxv | ||
| * search_auxvector() walks towards the higher address and locate one of the | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * auxvector entry, then walk backwards and find the beginning of auxvector. */ | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| static void * | ||
| search_auxvector(void *sp) | ||
| { | ||
| /* XXX: Check whether 64 * PAGE_SIZE is an appropriate limit */ | ||
| for (size_t offset = 0; offset < PAGE_SIZE * 64; offset += sizeof(ulong)) { | ||
| ELF_AUXV_TYPE *p = sp + offset; | ||
|
|
||
| if (((uintptr_t)(&p->a_un) & (PAGE_SIZE - 1)) == 0 && | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| !check_address_readable(&p->a_un)) | ||
| return NULL; | ||
|
|
||
| /* Check for AT_EXECFN entry in the auxvector, which contains pathname | ||
| * of the program and should be a readable address. */ | ||
| if (p->a_type == AT_EXECFN && check_address_readable((void *)p->a_un.a_val)) { | ||
|
||
| for (; (void *)p > sp; p--) { | ||
| /* The maximum key in auxvector is much smaller than 0x400. | ||
| * This assumes envp contains much higher addresses. An auxvector | ||
| * entry with zero as key indicates the end, thus the only case | ||
| * that it's encountered when searching towards auxvector's | ||
| * start is an empty envp. */ | ||
| if ((p->a_type == 0 || p->a_type >= 0x400) && p->a_un.a_val == 0) | ||
| return p + 1; | ||
| } | ||
| return NULL; /* shouldn't reach here */ | ||
| } | ||
| } | ||
|
|
||
| return NULL; | ||
| } | ||
|
|
||
| static void | ||
| search_kernel_args_on_stack(int *argc, char ***argv, char ***envp) | ||
| { | ||
| ulong *sp; | ||
| GET_STACK_PTR(sp); | ||
|
|
||
| ulong *auxv = search_auxvector(sp); | ||
|
|
||
| ASSERT_MESSAGE(CHKLVL_ASSERTS, "failed to find auxv", auxv != NULL); | ||
|
|
||
| ulong *p = &auxv[-2]; | ||
| for (; p[-1] && &p[-1] > sp; p--) | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ; | ||
|
|
||
| ASSERT_MESSAGE(CHKLVL_ASSERTS, "failed to find envp", p != sp); | ||
|
|
||
| *envp = (char **)p; | ||
|
|
||
| /* XXX: It's hard to determine the start of argv b/c argc locates immediately | ||
| * before it. Luckily, our_init only makes use of envp. argc and argv are | ||
| * zeroed. */ | ||
| *argc = 0; | ||
| *argv = NULL; | ||
| } | ||
| # endif | ||
ziyao233 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| INITIALIZER_ATTRIBUTES int | ||
| _init(int argc, char **argv, char **envp) | ||
| { | ||
|
|
@@ -803,6 +879,11 @@ _init(int argc, char **argv, char **envp) | |
| envp = NULL; | ||
| } | ||
| ASSERT_MESSAGE(CHKLVL_ASSERTS, "failed to find envp", envp != NULL); | ||
| # endif | ||
| # ifdef MUSL | ||
| /* i#1973: musl passes nothing to library init routines. We scan the stack | ||
| * to find the arguments passed by kernel. */ | ||
| search_kernel_args_on_stack(&argc, &argv, &envp); | ||
| # endif | ||
| return our_init(argc, argv, envp); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that get_kernel_args() in loader_android.c for older Android finds argc, argv, and envp inside a structure pointed at by TLS which I believe is specific to Android.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC the stack layouts on starting a process between normal Linux kernels and Android ones should be the same, thus it should be okay to reuse it for Android.