summaryrefslogtreecommitdiffstats
path: root/fs/binfmt_flat.c
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2016-07-24 11:30:20 -0400
committerGreg Ungerer <gerg@linux-m68k.org>2016-07-25 02:52:01 -0400
commita97d157d00cd0ccbcfde3da7bbf34ab7c68cf4eb (patch)
tree5df0cbdd1eb58de03738c0e6033549808fd9dbec /fs/binfmt_flat.c
parent687fd7738ec322ea5994a692c20301eed315899d (diff)
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>
Diffstat (limited to 'fs/binfmt_flat.c')
-rw-r--r--fs/binfmt_flat.c117
1 files changed, 63 insertions, 54 deletions
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index a002e1a3b9e8..5dc7968a424f 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -103,50 +103,58 @@ static int flat_core_dump(struct coredump_params *cprm)
103/* 103/*
104 * create_flat_tables() parses the env- and arg-strings in new user 104 * create_flat_tables() parses the env- and arg-strings in new user
105 * memory and creates the pointer tables from them, and puts their 105 * memory and creates the pointer tables from them, and puts their
106 * addresses on the "stack", returning the new stack pointer value. 106 * addresses on the "stack", recording the new stack pointer value.
107 */ 107 */
108 108
109static unsigned long create_flat_tables( 109static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
110 unsigned long pp,
111 struct linux_binprm *bprm)
112{ 110{
113 unsigned long *argv, *envp; 111 char __user *p;
114 unsigned long *sp; 112 unsigned long __user *sp;
115 char *p = (char *)pp; 113 long i, len;
116 int argc = bprm->argc;
117 int envc = bprm->envc;
118 char uninitialized_var(dummy);
119
120 sp = (unsigned long *)p;
121 sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
122 sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
123 argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
124 envp = argv + (argc + 1);
125 114
115 p = (char __user *)arg_start;
116 sp = (unsigned long __user *)current->mm->start_stack;
117
118 sp -= bprm->envc + 1;
119 sp -= bprm->argc + 1;
120 sp -= flat_argvp_envp_on_stack() ? 2 : 0;
121 sp -= 1; /* &argc */
122
123 current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
124 sp = (unsigned long __user *)current->mm->start_stack;
125
126 __put_user(bprm->argc, sp++);
126 if (flat_argvp_envp_on_stack()) { 127 if (flat_argvp_envp_on_stack()) {
127 put_user((unsigned long) envp, sp + 2); 128 unsigned long argv, envp;
128 put_user((unsigned long) argv, sp + 1); 129 argv = (unsigned long)(sp + 2);
129 } 130 envp = (unsigned long)(sp + 2 + bprm->argc + 1);
130 131 __put_user(argv, sp++);
131 put_user(argc, sp); 132 __put_user(envp, sp++);
132 current->mm->arg_start = (unsigned long) p; 133 }
133 while (argc-- > 0) { 134
134 put_user((unsigned long) p, argv++); 135 current->mm->arg_start = (unsigned long)p;
135 do { 136 for (i = bprm->argc; i > 0; i--) {
136 get_user(dummy, p); p++; 137 __put_user((unsigned long)p, sp++);
137 } while (dummy); 138 len = strnlen_user(p, MAX_ARG_STRLEN);
138 } 139 if (!len || len > MAX_ARG_STRLEN)
139 put_user((unsigned long) NULL, argv); 140 return -EINVAL;
140 current->mm->arg_end = current->mm->env_start = (unsigned long) p; 141 p += len;
141 while (envc-- > 0) { 142 }
142 put_user((unsigned long)p, envp); envp++; 143 __put_user(0, sp++);
143 do { 144 current->mm->arg_end = (unsigned long)p;
144 get_user(dummy, p); p++; 145
145 } while (dummy); 146 current->mm->env_start = (unsigned long) p;
146 } 147 for (i = bprm->envc; i > 0; i--) {
147 put_user((unsigned long) NULL, envp); 148 __put_user((unsigned long)p, sp++);
148 current->mm->env_end = (unsigned long) p; 149 len = strnlen_user(p, MAX_ARG_STRLEN);
149 return (unsigned long)sp; 150 if (!len || len > MAX_ARG_STRLEN)
151 return -EINVAL;
152 p += len;
153 }
154 __put_user(0, sp++);
155 current->mm->env_end = (unsigned long)p;
156
157 return 0;
150} 158}
151 159
152/****************************************************************************/ 160/****************************************************************************/
@@ -846,7 +854,7 @@ static int load_flat_binary(struct linux_binprm *bprm)
846{ 854{
847 struct lib_info libinfo; 855 struct lib_info libinfo;
848 struct pt_regs *regs = current_pt_regs(); 856 struct pt_regs *regs = current_pt_regs();
849 unsigned long sp, stack_len; 857 unsigned long stack_len;
850 unsigned long start_addr; 858 unsigned long start_addr;
851 int res; 859 int res;
852 int i, j; 860 int i, j;
@@ -860,11 +868,10 @@ static int load_flat_binary(struct linux_binprm *bprm)
860 * pedantic and include space for the argv/envp array as it may have 868 * pedantic and include space for the argv/envp array as it may have
861 * a lot of entries. 869 * a lot of entries.
862 */ 870 */
863#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *)) 871 stack_len = PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
864 stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ 872 stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
865 stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ 873 stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
866 stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ 874 stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
867 stack_len += FLAT_STACK_ALIGN - 1; /* reserve for upcoming alignment */
868 875
869 res = load_flat_file(bprm, &libinfo, 0, &stack_len); 876 res = load_flat_file(bprm, &libinfo, 0, &stack_len);
870 if (res < 0) 877 if (res < 0)
@@ -882,16 +889,18 @@ static int load_flat_binary(struct linux_binprm *bprm)
882 889
883 set_binfmt(&flat_format); 890 set_binfmt(&flat_format);
884 891
885 sp = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; 892 /* Stash our initial stack pointer into the mm structure */
886 pr_debug("sp=%lx\n", sp); 893 current->mm->start_stack =
894 ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
895 pr_debug("sp=%lx\n", current->mm->start_stack);
887 896
888 /* copy the arg pages onto the stack */ 897 /* copy the arg pages onto the stack */
889 res = transfer_args_to_stack(bprm, &sp); 898 res = transfer_args_to_stack(bprm, &current->mm->start_stack);
899 if (!res)
900 res = create_flat_tables(bprm, current->mm->start_stack);
890 if (res) 901 if (res)
891 return res; 902 return res;
892 903
893 sp = create_flat_tables(sp, bprm);
894
895 /* Fake some return addresses to ensure the call chain will 904 /* Fake some return addresses to ensure the call chain will
896 * initialise library in order for us. We are required to call 905 * initialise library in order for us. We are required to call
897 * lib 1 first, then 2, ... and finally the main program (id 0). 906 * 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)
902 for (i = MAX_SHARED_LIBS-1; i > 0; i--) { 911 for (i = MAX_SHARED_LIBS-1; i > 0; i--) {
903 if (libinfo.lib_list[i].loaded) { 912 if (libinfo.lib_list[i].loaded) {
904 /* Push previos first to call address */ 913 /* Push previos first to call address */
905 --sp; put_user(start_addr, (unsigned long *)sp); 914 unsigned long __user *sp;
915 current->mm->start_stack -= sizeof(unsigned long);
916 sp = (unsigned long __user *)current->mm->start_stack;
917 __put_user(start_addr, sp);
906 start_addr = libinfo.lib_list[i].entry; 918 start_addr = libinfo.lib_list[i].entry;
907 } 919 }
908 } 920 }
909#endif 921#endif
910 922
911 /* Stash our initial stack pointer into the mm structure */
912 current->mm->start_stack = sp;
913
914#ifdef FLAT_PLAT_INIT 923#ifdef FLAT_PLAT_INIT
915 FLAT_PLAT_INIT(regs); 924 FLAT_PLAT_INIT(regs);
916#endif 925#endif