aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2017-07-10 18:52:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-10 19:32:36 -0400
commit67c6777a5d331dda32a4c4a1bf0cac85bdaaaed8 (patch)
treec5ae9869b8e0a3e81091bb08597ea54346655824
parenta73dc5370e153ac63718d850bddf0c9aa9d871e6 (diff)
binfmt_elf: safely increment argv pointers
When building the argv/envp pointers, the envp is needlessly pre-incremented instead of just continuing after the argv pointers are finished. In some (likely impossible) race where the strings could be changed from userspace between copy_strings() and here, it might be possible to confuse the envp position. Instead, just use sp like everything else. Link: http://lkml.kernel.org/r/20170622173838.GA43308@beast Signed-off-by: Kees Cook <keescook@chromium.org> Cc: Rik van Riel <riel@redhat.com> Cc: Daniel Micay <danielmicay@gmail.com> Cc: Qualys Security Advisory <qsa@qualys.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Dmitry Safonov <dsafonov@virtuozzo.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Grzegorz Andrejczuk <grzegorz.andrejczuk@intel.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/binfmt_elf.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 7465c3ea5dd5..879ff9c7ffd0 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -163,8 +163,6 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
163 unsigned long p = bprm->p; 163 unsigned long p = bprm->p;
164 int argc = bprm->argc; 164 int argc = bprm->argc;
165 int envc = bprm->envc; 165 int envc = bprm->envc;
166 elf_addr_t __user *argv;
167 elf_addr_t __user *envp;
168 elf_addr_t __user *sp; 166 elf_addr_t __user *sp;
169 elf_addr_t __user *u_platform; 167 elf_addr_t __user *u_platform;
170 elf_addr_t __user *u_base_platform; 168 elf_addr_t __user *u_base_platform;
@@ -304,38 +302,38 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
304 /* Now, let's put argc (and argv, envp if appropriate) on the stack */ 302 /* Now, let's put argc (and argv, envp if appropriate) on the stack */
305 if (__put_user(argc, sp++)) 303 if (__put_user(argc, sp++))
306 return -EFAULT; 304 return -EFAULT;
307 argv = sp;
308 envp = argv + argc + 1;
309 305
310 /* Populate argv and envp */ 306 /* Populate list of argv pointers back to argv strings. */
311 p = current->mm->arg_end = current->mm->arg_start; 307 p = current->mm->arg_end = current->mm->arg_start;
312 while (argc-- > 0) { 308 while (argc-- > 0) {
313 size_t len; 309 size_t len;
314 if (__put_user((elf_addr_t)p, argv++)) 310 if (__put_user((elf_addr_t)p, sp++))
315 return -EFAULT; 311 return -EFAULT;
316 len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); 312 len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
317 if (!len || len > MAX_ARG_STRLEN) 313 if (!len || len > MAX_ARG_STRLEN)
318 return -EINVAL; 314 return -EINVAL;
319 p += len; 315 p += len;
320 } 316 }
321 if (__put_user(0, argv)) 317 if (__put_user(0, sp++))
322 return -EFAULT; 318 return -EFAULT;
323 current->mm->arg_end = current->mm->env_start = p; 319 current->mm->arg_end = p;
320
321 /* Populate list of envp pointers back to envp strings. */
322 current->mm->env_end = current->mm->env_start = p;
324 while (envc-- > 0) { 323 while (envc-- > 0) {
325 size_t len; 324 size_t len;
326 if (__put_user((elf_addr_t)p, envp++)) 325 if (__put_user((elf_addr_t)p, sp++))
327 return -EFAULT; 326 return -EFAULT;
328 len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); 327 len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
329 if (!len || len > MAX_ARG_STRLEN) 328 if (!len || len > MAX_ARG_STRLEN)
330 return -EINVAL; 329 return -EINVAL;
331 p += len; 330 p += len;
332 } 331 }
333 if (__put_user(0, envp)) 332 if (__put_user(0, sp++))
334 return -EFAULT; 333 return -EFAULT;
335 current->mm->env_end = p; 334 current->mm->env_end = p;
336 335
337 /* Put the elf_info on the stack in the right place. */ 336 /* Put the elf_info on the stack in the right place. */
338 sp = (elf_addr_t __user *)envp + 1;
339 if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) 337 if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t)))
340 return -EFAULT; 338 return -EFAULT;
341 return 0; 339 return 0;