diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 77 |
1 files changed, 53 insertions, 24 deletions
@@ -181,14 +181,7 @@ static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) | |||
181 | return; | 181 | return; |
182 | 182 | ||
183 | bprm->vma_pages = pages; | 183 | bprm->vma_pages = pages; |
184 | |||
185 | #ifdef SPLIT_RSS_COUNTING | ||
186 | add_mm_counter(mm, MM_ANONPAGES, diff); | ||
187 | #else | ||
188 | spin_lock(&mm->page_table_lock); | ||
189 | add_mm_counter(mm, MM_ANONPAGES, diff); | 184 | add_mm_counter(mm, MM_ANONPAGES, diff); |
190 | spin_unlock(&mm->page_table_lock); | ||
191 | #endif | ||
192 | } | 185 | } |
193 | 186 | ||
194 | static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, | 187 | static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, |
@@ -277,7 +270,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm) | |||
277 | * use STACK_TOP because that can depend on attributes which aren't | 270 | * use STACK_TOP because that can depend on attributes which aren't |
278 | * configured yet. | 271 | * configured yet. |
279 | */ | 272 | */ |
280 | BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP); | 273 | BUILD_BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP); |
281 | vma->vm_end = STACK_TOP_MAX; | 274 | vma->vm_end = STACK_TOP_MAX; |
282 | vma->vm_start = vma->vm_end - PAGE_SIZE; | 275 | vma->vm_start = vma->vm_end - PAGE_SIZE; |
283 | vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; | 276 | vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; |
@@ -1430,9 +1423,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1430 | } | 1423 | } |
1431 | } | 1424 | } |
1432 | read_unlock(&binfmt_lock); | 1425 | read_unlock(&binfmt_lock); |
1426 | #ifdef CONFIG_MODULES | ||
1433 | if (retval != -ENOEXEC || bprm->mm == NULL) { | 1427 | if (retval != -ENOEXEC || bprm->mm == NULL) { |
1434 | break; | 1428 | break; |
1435 | #ifdef CONFIG_MODULES | ||
1436 | } else { | 1429 | } else { |
1437 | #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e)) | 1430 | #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e)) |
1438 | if (printable(bprm->buf[0]) && | 1431 | if (printable(bprm->buf[0]) && |
@@ -1440,9 +1433,13 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1440 | printable(bprm->buf[2]) && | 1433 | printable(bprm->buf[2]) && |
1441 | printable(bprm->buf[3])) | 1434 | printable(bprm->buf[3])) |
1442 | break; /* -ENOEXEC */ | 1435 | break; /* -ENOEXEC */ |
1436 | if (try) | ||
1437 | break; /* -ENOEXEC */ | ||
1443 | request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2])); | 1438 | request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2])); |
1444 | #endif | ||
1445 | } | 1439 | } |
1440 | #else | ||
1441 | break; | ||
1442 | #endif | ||
1446 | } | 1443 | } |
1447 | return retval; | 1444 | return retval; |
1448 | } | 1445 | } |
@@ -1462,6 +1459,23 @@ static int do_execve_common(const char *filename, | |||
1462 | struct files_struct *displaced; | 1459 | struct files_struct *displaced; |
1463 | bool clear_in_exec; | 1460 | bool clear_in_exec; |
1464 | int retval; | 1461 | int retval; |
1462 | const struct cred *cred = current_cred(); | ||
1463 | |||
1464 | /* | ||
1465 | * We move the actual failure in case of RLIMIT_NPROC excess from | ||
1466 | * set*uid() to execve() because too many poorly written programs | ||
1467 | * don't check setuid() return code. Here we additionally recheck | ||
1468 | * whether NPROC limit is still exceeded. | ||
1469 | */ | ||
1470 | if ((current->flags & PF_NPROC_EXCEEDED) && | ||
1471 | atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) { | ||
1472 | retval = -EAGAIN; | ||
1473 | goto out_ret; | ||
1474 | } | ||
1475 | |||
1476 | /* We're below the limit (still or again), so we don't want to make | ||
1477 | * further execve() calls fail. */ | ||
1478 | current->flags &= ~PF_NPROC_EXCEEDED; | ||
1465 | 1479 | ||
1466 | retval = unshare_files(&displaced); | 1480 | retval = unshare_files(&displaced); |
1467 | if (retval) | 1481 | if (retval) |
@@ -1649,15 +1663,26 @@ expand_fail: | |||
1649 | return ret; | 1663 | return ret; |
1650 | } | 1664 | } |
1651 | 1665 | ||
1666 | static void cn_escape(char *str) | ||
1667 | { | ||
1668 | for (; *str; str++) | ||
1669 | if (*str == '/') | ||
1670 | *str = '!'; | ||
1671 | } | ||
1672 | |||
1652 | static int cn_print_exe_file(struct core_name *cn) | 1673 | static int cn_print_exe_file(struct core_name *cn) |
1653 | { | 1674 | { |
1654 | struct file *exe_file; | 1675 | struct file *exe_file; |
1655 | char *pathbuf, *path, *p; | 1676 | char *pathbuf, *path; |
1656 | int ret; | 1677 | int ret; |
1657 | 1678 | ||
1658 | exe_file = get_mm_exe_file(current->mm); | 1679 | exe_file = get_mm_exe_file(current->mm); |
1659 | if (!exe_file) | 1680 | if (!exe_file) { |
1660 | return cn_printf(cn, "(unknown)"); | 1681 | char *commstart = cn->corename + cn->used; |
1682 | ret = cn_printf(cn, "%s (path unknown)", current->comm); | ||
1683 | cn_escape(commstart); | ||
1684 | return ret; | ||
1685 | } | ||
1661 | 1686 | ||
1662 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); | 1687 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); |
1663 | if (!pathbuf) { | 1688 | if (!pathbuf) { |
@@ -1671,9 +1696,7 @@ static int cn_print_exe_file(struct core_name *cn) | |||
1671 | goto free_buf; | 1696 | goto free_buf; |
1672 | } | 1697 | } |
1673 | 1698 | ||
1674 | for (p = path; *p; p++) | 1699 | cn_escape(path); |
1675 | if (*p == '/') | ||
1676 | *p = '!'; | ||
1677 | 1700 | ||
1678 | ret = cn_printf(cn, "%s", path); | 1701 | ret = cn_printf(cn, "%s", path); |
1679 | 1702 | ||
@@ -1745,16 +1768,22 @@ static int format_corename(struct core_name *cn, long signr) | |||
1745 | break; | 1768 | break; |
1746 | } | 1769 | } |
1747 | /* hostname */ | 1770 | /* hostname */ |
1748 | case 'h': | 1771 | case 'h': { |
1772 | char *namestart = cn->corename + cn->used; | ||
1749 | down_read(&uts_sem); | 1773 | down_read(&uts_sem); |
1750 | err = cn_printf(cn, "%s", | 1774 | err = cn_printf(cn, "%s", |
1751 | utsname()->nodename); | 1775 | utsname()->nodename); |
1752 | up_read(&uts_sem); | 1776 | up_read(&uts_sem); |
1777 | cn_escape(namestart); | ||
1753 | break; | 1778 | break; |
1779 | } | ||
1754 | /* executable */ | 1780 | /* executable */ |
1755 | case 'e': | 1781 | case 'e': { |
1782 | char *commstart = cn->corename + cn->used; | ||
1756 | err = cn_printf(cn, "%s", current->comm); | 1783 | err = cn_printf(cn, "%s", current->comm); |
1784 | cn_escape(commstart); | ||
1757 | break; | 1785 | break; |
1786 | } | ||
1758 | case 'E': | 1787 | case 'E': |
1759 | err = cn_print_exe_file(cn); | 1788 | err = cn_print_exe_file(cn); |
1760 | break; | 1789 | break; |
@@ -2118,16 +2147,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2118 | 2147 | ||
2119 | ispipe = format_corename(&cn, signr); | 2148 | ispipe = format_corename(&cn, signr); |
2120 | 2149 | ||
2121 | if (ispipe == -ENOMEM) { | ||
2122 | printk(KERN_WARNING "format_corename failed\n"); | ||
2123 | printk(KERN_WARNING "Aborting core\n"); | ||
2124 | goto fail_corename; | ||
2125 | } | ||
2126 | |||
2127 | if (ispipe) { | 2150 | if (ispipe) { |
2128 | int dump_count; | 2151 | int dump_count; |
2129 | char **helper_argv; | 2152 | char **helper_argv; |
2130 | 2153 | ||
2154 | if (ispipe < 0) { | ||
2155 | printk(KERN_WARNING "format_corename failed\n"); | ||
2156 | printk(KERN_WARNING "Aborting core\n"); | ||
2157 | goto fail_corename; | ||
2158 | } | ||
2159 | |||
2131 | if (cprm.limit == 1) { | 2160 | if (cprm.limit == 1) { |
2132 | /* | 2161 | /* |
2133 | * Normally core limits are irrelevant to pipes, since | 2162 | * Normally core limits are irrelevant to pipes, since |