binfmt_flat: clean up create_flat_tables() and stack accesses
In addition to better code clarity, this brings proper usage of user memory accessors everywhere the stack is touched. This is essential for making this work on MMU systems. Signed-off-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Greg Ungerer <gerg@linux-m68k.org> Signed-off-by: Greg Ungerer <gerg@linux-m68k.org>
This commit is contained in:
parent
687fd7738e
commit
a97d157d00
103
fs/binfmt_flat.c
103
fs/binfmt_flat.c
|
@ -103,50 +103,58 @@ static int flat_core_dump(struct coredump_params *cprm)
|
||||||
/*
|
/*
|
||||||
* create_flat_tables() parses the env- and arg-strings in new user
|
* create_flat_tables() parses the env- and arg-strings in new user
|
||||||
* memory and creates the pointer tables from them, and puts their
|
* memory and creates the pointer tables from them, and puts their
|
||||||
* addresses on the "stack", returning the new stack pointer value.
|
* addresses on the "stack", recording the new stack pointer value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned long create_flat_tables(
|
static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
|
||||||
unsigned long pp,
|
|
||||||
struct linux_binprm *bprm)
|
|
||||||
{
|
{
|
||||||
unsigned long *argv, *envp;
|
char __user *p;
|
||||||
unsigned long *sp;
|
unsigned long __user *sp;
|
||||||
char *p = (char *)pp;
|
long i, len;
|
||||||
int argc = bprm->argc;
|
|
||||||
int envc = bprm->envc;
|
|
||||||
char uninitialized_var(dummy);
|
|
||||||
|
|
||||||
sp = (unsigned long *)p;
|
p = (char __user *)arg_start;
|
||||||
sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
|
sp = (unsigned long __user *)current->mm->start_stack;
|
||||||
sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
|
|
||||||
argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
|
|
||||||
envp = argv + (argc + 1);
|
|
||||||
|
|
||||||
|
sp -= bprm->envc + 1;
|
||||||
|
sp -= bprm->argc + 1;
|
||||||
|
sp -= flat_argvp_envp_on_stack() ? 2 : 0;
|
||||||
|
sp -= 1; /* &argc */
|
||||||
|
|
||||||
|
current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
|
||||||
|
sp = (unsigned long __user *)current->mm->start_stack;
|
||||||
|
|
||||||
|
__put_user(bprm->argc, sp++);
|
||||||
if (flat_argvp_envp_on_stack()) {
|
if (flat_argvp_envp_on_stack()) {
|
||||||
put_user((unsigned long) envp, sp + 2);
|
unsigned long argv, envp;
|
||||||
put_user((unsigned long) argv, sp + 1);
|
argv = (unsigned long)(sp + 2);
|
||||||
|
envp = (unsigned long)(sp + 2 + bprm->argc + 1);
|
||||||
|
__put_user(argv, sp++);
|
||||||
|
__put_user(envp, sp++);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_user(argc, sp);
|
current->mm->arg_start = (unsigned long)p;
|
||||||
current->mm->arg_start = (unsigned long) p;
|
for (i = bprm->argc; i > 0; i--) {
|
||||||
while (argc-- > 0) {
|
__put_user((unsigned long)p, sp++);
|
||||||
put_user((unsigned long) p, argv++);
|
len = strnlen_user(p, MAX_ARG_STRLEN);
|
||||||
do {
|
if (!len || len > MAX_ARG_STRLEN)
|
||||||
get_user(dummy, p); p++;
|
return -EINVAL;
|
||||||
} while (dummy);
|
p += len;
|
||||||
}
|
}
|
||||||
put_user((unsigned long) NULL, argv);
|
__put_user(0, sp++);
|
||||||
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
|
current->mm->arg_end = (unsigned long)p;
|
||||||
while (envc-- > 0) {
|
|
||||||
put_user((unsigned long)p, envp); envp++;
|
current->mm->env_start = (unsigned long) p;
|
||||||
do {
|
for (i = bprm->envc; i > 0; i--) {
|
||||||
get_user(dummy, p); p++;
|
__put_user((unsigned long)p, sp++);
|
||||||
} while (dummy);
|
len = strnlen_user(p, MAX_ARG_STRLEN);
|
||||||
|
if (!len || len > MAX_ARG_STRLEN)
|
||||||
|
return -EINVAL;
|
||||||
|
p += len;
|
||||||
}
|
}
|
||||||
put_user((unsigned long) NULL, envp);
|
__put_user(0, sp++);
|
||||||
current->mm->env_end = (unsigned long) p;
|
current->mm->env_end = (unsigned long)p;
|
||||||
return (unsigned long)sp;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
@ -846,7 +854,7 @@ static int load_flat_binary(struct linux_binprm *bprm)
|
||||||
{
|
{
|
||||||
struct lib_info libinfo;
|
struct lib_info libinfo;
|
||||||
struct pt_regs *regs = current_pt_regs();
|
struct pt_regs *regs = current_pt_regs();
|
||||||
unsigned long sp, stack_len;
|
unsigned long stack_len;
|
||||||
unsigned long start_addr;
|
unsigned long start_addr;
|
||||||
int res;
|
int res;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -860,11 +868,10 @@ static int load_flat_binary(struct linux_binprm *bprm)
|
||||||
* pedantic and include space for the argv/envp array as it may have
|
* pedantic and include space for the argv/envp array as it may have
|
||||||
* a lot of entries.
|
* a lot of entries.
|
||||||
*/
|
*/
|
||||||
#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
|
stack_len = PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
|
||||||
stack_len = TOP_OF_ARGS - bprm->p; /* the strings */
|
|
||||||
stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
|
stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
|
||||||
stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
|
stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
|
||||||
stack_len += FLAT_STACK_ALIGN - 1; /* reserve for upcoming alignment */
|
stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
|
||||||
|
|
||||||
res = load_flat_file(bprm, &libinfo, 0, &stack_len);
|
res = load_flat_file(bprm, &libinfo, 0, &stack_len);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
|
@ -882,16 +889,18 @@ static int load_flat_binary(struct linux_binprm *bprm)
|
||||||
|
|
||||||
set_binfmt(&flat_format);
|
set_binfmt(&flat_format);
|
||||||
|
|
||||||
sp = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
|
/* Stash our initial stack pointer into the mm structure */
|
||||||
pr_debug("sp=%lx\n", sp);
|
current->mm->start_stack =
|
||||||
|
((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
|
||||||
|
pr_debug("sp=%lx\n", current->mm->start_stack);
|
||||||
|
|
||||||
/* copy the arg pages onto the stack */
|
/* copy the arg pages onto the stack */
|
||||||
res = transfer_args_to_stack(bprm, &sp);
|
res = transfer_args_to_stack(bprm, ¤t->mm->start_stack);
|
||||||
|
if (!res)
|
||||||
|
res = create_flat_tables(bprm, current->mm->start_stack);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
sp = create_flat_tables(sp, bprm);
|
|
||||||
|
|
||||||
/* Fake some return addresses to ensure the call chain will
|
/* Fake some return addresses to ensure the call chain will
|
||||||
* initialise library in order for us. We are required to call
|
* initialise library in order for us. We are required to call
|
||||||
* lib 1 first, then 2, ... and finally the main program (id 0).
|
* lib 1 first, then 2, ... and finally the main program (id 0).
|
||||||
|
@ -902,15 +911,15 @@ static int load_flat_binary(struct linux_binprm *bprm)
|
||||||
for (i = MAX_SHARED_LIBS-1; i > 0; i--) {
|
for (i = MAX_SHARED_LIBS-1; i > 0; i--) {
|
||||||
if (libinfo.lib_list[i].loaded) {
|
if (libinfo.lib_list[i].loaded) {
|
||||||
/* Push previos first to call address */
|
/* Push previos first to call address */
|
||||||
--sp; put_user(start_addr, (unsigned long *)sp);
|
unsigned long __user *sp;
|
||||||
|
current->mm->start_stack -= sizeof(unsigned long);
|
||||||
|
sp = (unsigned long __user *)current->mm->start_stack;
|
||||||
|
__put_user(start_addr, sp);
|
||||||
start_addr = libinfo.lib_list[i].entry;
|
start_addr = libinfo.lib_list[i].entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Stash our initial stack pointer into the mm structure */
|
|
||||||
current->mm->start_stack = sp;
|
|
||||||
|
|
||||||
#ifdef FLAT_PLAT_INIT
|
#ifdef FLAT_PLAT_INIT
|
||||||
FLAT_PLAT_INIT(regs);
|
FLAT_PLAT_INIT(regs);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue