diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 125 |
1 files changed, 100 insertions, 25 deletions
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/fs_struct.h> | 55 | #include <linux/fs_struct.h> |
56 | #include <linux/pipe_fs_i.h> | 56 | #include <linux/pipe_fs_i.h> |
57 | #include <linux/oom.h> | 57 | #include <linux/oom.h> |
58 | #include <linux/compat.h> | ||
58 | 59 | ||
59 | #include <asm/uaccess.h> | 60 | #include <asm/uaccess.h> |
60 | #include <asm/mmu_context.h> | 61 | #include <asm/mmu_context.h> |
@@ -166,8 +167,13 @@ out: | |||
166 | } | 167 | } |
167 | 168 | ||
168 | #ifdef CONFIG_MMU | 169 | #ifdef CONFIG_MMU |
169 | 170 | /* | |
170 | void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) | 171 | * The nascent bprm->mm is not visible until exec_mmap() but it can |
172 | * use a lot of memory, account these pages in current->mm temporary | ||
173 | * for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we | ||
174 | * change the counter back via acct_arg_size(0). | ||
175 | */ | ||
176 | static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) | ||
171 | { | 177 | { |
172 | struct mm_struct *mm = current->mm; | 178 | struct mm_struct *mm = current->mm; |
173 | long diff = (long)(pages - bprm->vma_pages); | 179 | long diff = (long)(pages - bprm->vma_pages); |
@@ -186,7 +192,7 @@ void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) | |||
186 | #endif | 192 | #endif |
187 | } | 193 | } |
188 | 194 | ||
189 | struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, | 195 | static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, |
190 | int write) | 196 | int write) |
191 | { | 197 | { |
192 | struct page *page; | 198 | struct page *page; |
@@ -305,11 +311,11 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len) | |||
305 | 311 | ||
306 | #else | 312 | #else |
307 | 313 | ||
308 | void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) | 314 | static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) |
309 | { | 315 | { |
310 | } | 316 | } |
311 | 317 | ||
312 | struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, | 318 | static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, |
313 | int write) | 319 | int write) |
314 | { | 320 | { |
315 | struct page *page; | 321 | struct page *page; |
@@ -398,22 +404,56 @@ err: | |||
398 | return err; | 404 | return err; |
399 | } | 405 | } |
400 | 406 | ||
407 | struct user_arg_ptr { | ||
408 | #ifdef CONFIG_COMPAT | ||
409 | bool is_compat; | ||
410 | #endif | ||
411 | union { | ||
412 | const char __user *const __user *native; | ||
413 | #ifdef CONFIG_COMPAT | ||
414 | compat_uptr_t __user *compat; | ||
415 | #endif | ||
416 | } ptr; | ||
417 | }; | ||
418 | |||
419 | static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) | ||
420 | { | ||
421 | const char __user *native; | ||
422 | |||
423 | #ifdef CONFIG_COMPAT | ||
424 | if (unlikely(argv.is_compat)) { | ||
425 | compat_uptr_t compat; | ||
426 | |||
427 | if (get_user(compat, argv.ptr.compat + nr)) | ||
428 | return ERR_PTR(-EFAULT); | ||
429 | |||
430 | return compat_ptr(compat); | ||
431 | } | ||
432 | #endif | ||
433 | |||
434 | if (get_user(native, argv.ptr.native + nr)) | ||
435 | return ERR_PTR(-EFAULT); | ||
436 | |||
437 | return native; | ||
438 | } | ||
439 | |||
401 | /* | 440 | /* |
402 | * count() counts the number of strings in array ARGV. | 441 | * count() counts the number of strings in array ARGV. |
403 | */ | 442 | */ |
404 | static int count(const char __user * const __user * argv, int max) | 443 | static int count(struct user_arg_ptr argv, int max) |
405 | { | 444 | { |
406 | int i = 0; | 445 | int i = 0; |
407 | 446 | ||
408 | if (argv != NULL) { | 447 | if (argv.ptr.native != NULL) { |
409 | for (;;) { | 448 | for (;;) { |
410 | const char __user * p; | 449 | const char __user *p = get_user_arg_ptr(argv, i); |
411 | 450 | ||
412 | if (get_user(p, argv)) | ||
413 | return -EFAULT; | ||
414 | if (!p) | 451 | if (!p) |
415 | break; | 452 | break; |
416 | argv++; | 453 | |
454 | if (IS_ERR(p)) | ||
455 | return -EFAULT; | ||
456 | |||
417 | if (i++ >= max) | 457 | if (i++ >= max) |
418 | return -E2BIG; | 458 | return -E2BIG; |
419 | 459 | ||
@@ -430,7 +470,7 @@ static int count(const char __user * const __user * argv, int max) | |||
430 | * processes's memory to the new process's stack. The call to get_user_pages() | 470 | * processes's memory to the new process's stack. The call to get_user_pages() |
431 | * ensures the destination page is created and not swapped out. | 471 | * ensures the destination page is created and not swapped out. |
432 | */ | 472 | */ |
433 | static int copy_strings(int argc, const char __user *const __user *argv, | 473 | static int copy_strings(int argc, struct user_arg_ptr argv, |
434 | struct linux_binprm *bprm) | 474 | struct linux_binprm *bprm) |
435 | { | 475 | { |
436 | struct page *kmapped_page = NULL; | 476 | struct page *kmapped_page = NULL; |
@@ -443,16 +483,18 @@ static int copy_strings(int argc, const char __user *const __user *argv, | |||
443 | int len; | 483 | int len; |
444 | unsigned long pos; | 484 | unsigned long pos; |
445 | 485 | ||
446 | if (get_user(str, argv+argc) || | 486 | ret = -EFAULT; |
447 | !(len = strnlen_user(str, MAX_ARG_STRLEN))) { | 487 | str = get_user_arg_ptr(argv, argc); |
448 | ret = -EFAULT; | 488 | if (IS_ERR(str)) |
449 | goto out; | 489 | goto out; |
450 | } | ||
451 | 490 | ||
452 | if (!valid_arg_len(bprm, len)) { | 491 | len = strnlen_user(str, MAX_ARG_STRLEN); |
453 | ret = -E2BIG; | 492 | if (!len) |
493 | goto out; | ||
494 | |||
495 | ret = -E2BIG; | ||
496 | if (!valid_arg_len(bprm, len)) | ||
454 | goto out; | 497 | goto out; |
455 | } | ||
456 | 498 | ||
457 | /* We're going to work our way backwords. */ | 499 | /* We're going to work our way backwords. */ |
458 | pos = bprm->p; | 500 | pos = bprm->p; |
@@ -519,14 +561,19 @@ out: | |||
519 | /* | 561 | /* |
520 | * Like copy_strings, but get argv and its values from kernel memory. | 562 | * Like copy_strings, but get argv and its values from kernel memory. |
521 | */ | 563 | */ |
522 | int copy_strings_kernel(int argc, const char *const *argv, | 564 | int copy_strings_kernel(int argc, const char *const *__argv, |
523 | struct linux_binprm *bprm) | 565 | struct linux_binprm *bprm) |
524 | { | 566 | { |
525 | int r; | 567 | int r; |
526 | mm_segment_t oldfs = get_fs(); | 568 | mm_segment_t oldfs = get_fs(); |
569 | struct user_arg_ptr argv = { | ||
570 | .ptr.native = (const char __user *const __user *)__argv, | ||
571 | }; | ||
572 | |||
527 | set_fs(KERNEL_DS); | 573 | set_fs(KERNEL_DS); |
528 | r = copy_strings(argc, (const char __user *const __user *)argv, bprm); | 574 | r = copy_strings(argc, argv, bprm); |
529 | set_fs(oldfs); | 575 | set_fs(oldfs); |
576 | |||
530 | return r; | 577 | return r; |
531 | } | 578 | } |
532 | EXPORT_SYMBOL(copy_strings_kernel); | 579 | EXPORT_SYMBOL(copy_strings_kernel); |
@@ -1379,10 +1426,10 @@ EXPORT_SYMBOL(search_binary_handler); | |||
1379 | /* | 1426 | /* |
1380 | * sys_execve() executes a new program. | 1427 | * sys_execve() executes a new program. |
1381 | */ | 1428 | */ |
1382 | int do_execve(const char * filename, | 1429 | static int do_execve_common(const char *filename, |
1383 | const char __user *const __user *argv, | 1430 | struct user_arg_ptr argv, |
1384 | const char __user *const __user *envp, | 1431 | struct user_arg_ptr envp, |
1385 | struct pt_regs * regs) | 1432 | struct pt_regs *regs) |
1386 | { | 1433 | { |
1387 | struct linux_binprm *bprm; | 1434 | struct linux_binprm *bprm; |
1388 | struct file *file; | 1435 | struct file *file; |
@@ -1489,6 +1536,34 @@ out_ret: | |||
1489 | return retval; | 1536 | return retval; |
1490 | } | 1537 | } |
1491 | 1538 | ||
1539 | int do_execve(const char *filename, | ||
1540 | const char __user *const __user *__argv, | ||
1541 | const char __user *const __user *__envp, | ||
1542 | struct pt_regs *regs) | ||
1543 | { | ||
1544 | struct user_arg_ptr argv = { .ptr.native = __argv }; | ||
1545 | struct user_arg_ptr envp = { .ptr.native = __envp }; | ||
1546 | return do_execve_common(filename, argv, envp, regs); | ||
1547 | } | ||
1548 | |||
1549 | #ifdef CONFIG_COMPAT | ||
1550 | int compat_do_execve(char *filename, | ||
1551 | compat_uptr_t __user *__argv, | ||
1552 | compat_uptr_t __user *__envp, | ||
1553 | struct pt_regs *regs) | ||
1554 | { | ||
1555 | struct user_arg_ptr argv = { | ||
1556 | .is_compat = true, | ||
1557 | .ptr.compat = __argv, | ||
1558 | }; | ||
1559 | struct user_arg_ptr envp = { | ||
1560 | .is_compat = true, | ||
1561 | .ptr.compat = __envp, | ||
1562 | }; | ||
1563 | return do_execve_common(filename, argv, envp, regs); | ||
1564 | } | ||
1565 | #endif | ||
1566 | |||
1492 | void set_binfmt(struct linux_binfmt *new) | 1567 | void set_binfmt(struct linux_binfmt *new) |
1493 | { | 1568 | { |
1494 | struct mm_struct *mm = current->mm; | 1569 | struct mm_struct *mm = current->mm; |