diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 195 |
1 files changed, 114 insertions, 81 deletions
@@ -768,7 +768,6 @@ static int de_thread(struct task_struct *tsk) | |||
768 | struct signal_struct *sig = tsk->signal; | 768 | struct signal_struct *sig = tsk->signal; |
769 | struct sighand_struct *oldsighand = tsk->sighand; | 769 | struct sighand_struct *oldsighand = tsk->sighand; |
770 | spinlock_t *lock = &oldsighand->siglock; | 770 | spinlock_t *lock = &oldsighand->siglock; |
771 | int count; | ||
772 | 771 | ||
773 | if (thread_group_empty(tsk)) | 772 | if (thread_group_empty(tsk)) |
774 | goto no_thread_group; | 773 | goto no_thread_group; |
@@ -785,13 +784,13 @@ static int de_thread(struct task_struct *tsk) | |||
785 | spin_unlock_irq(lock); | 784 | spin_unlock_irq(lock); |
786 | return -EAGAIN; | 785 | return -EAGAIN; |
787 | } | 786 | } |
787 | |||
788 | sig->group_exit_task = tsk; | 788 | sig->group_exit_task = tsk; |
789 | zap_other_threads(tsk); | 789 | sig->notify_count = zap_other_threads(tsk); |
790 | if (!thread_group_leader(tsk)) | ||
791 | sig->notify_count--; | ||
790 | 792 | ||
791 | /* Account for the thread group leader hanging around: */ | 793 | while (sig->notify_count) { |
792 | count = thread_group_leader(tsk) ? 1 : 2; | ||
793 | sig->notify_count = count; | ||
794 | while (atomic_read(&sig->count) > count) { | ||
795 | __set_current_state(TASK_UNINTERRUPTIBLE); | 794 | __set_current_state(TASK_UNINTERRUPTIBLE); |
796 | spin_unlock_irq(lock); | 795 | spin_unlock_irq(lock); |
797 | schedule(); | 796 | schedule(); |
@@ -1662,12 +1661,15 @@ static int coredump_wait(int exit_code, struct core_state *core_state) | |||
1662 | struct task_struct *tsk = current; | 1661 | struct task_struct *tsk = current; |
1663 | struct mm_struct *mm = tsk->mm; | 1662 | struct mm_struct *mm = tsk->mm; |
1664 | struct completion *vfork_done; | 1663 | struct completion *vfork_done; |
1665 | int core_waiters; | 1664 | int core_waiters = -EBUSY; |
1666 | 1665 | ||
1667 | init_completion(&core_state->startup); | 1666 | init_completion(&core_state->startup); |
1668 | core_state->dumper.task = tsk; | 1667 | core_state->dumper.task = tsk; |
1669 | core_state->dumper.next = NULL; | 1668 | core_state->dumper.next = NULL; |
1670 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); | 1669 | |
1670 | down_write(&mm->mmap_sem); | ||
1671 | if (!mm->core_state) | ||
1672 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); | ||
1671 | up_write(&mm->mmap_sem); | 1673 | up_write(&mm->mmap_sem); |
1672 | 1674 | ||
1673 | if (unlikely(core_waiters < 0)) | 1675 | if (unlikely(core_waiters < 0)) |
@@ -1787,21 +1789,61 @@ static void wait_for_dump_helpers(struct file *file) | |||
1787 | } | 1789 | } |
1788 | 1790 | ||
1789 | 1791 | ||
1792 | /* | ||
1793 | * uhm_pipe_setup | ||
1794 | * helper function to customize the process used | ||
1795 | * to collect the core in userspace. Specifically | ||
1796 | * it sets up a pipe and installs it as fd 0 (stdin) | ||
1797 | * for the process. Returns 0 on success, or | ||
1798 | * PTR_ERR on failure. | ||
1799 | * Note that it also sets the core limit to 1. This | ||
1800 | * is a special value that we use to trap recursive | ||
1801 | * core dumps | ||
1802 | */ | ||
1803 | static int umh_pipe_setup(struct subprocess_info *info) | ||
1804 | { | ||
1805 | struct file *rp, *wp; | ||
1806 | struct fdtable *fdt; | ||
1807 | struct coredump_params *cp = (struct coredump_params *)info->data; | ||
1808 | struct files_struct *cf = current->files; | ||
1809 | |||
1810 | wp = create_write_pipe(0); | ||
1811 | if (IS_ERR(wp)) | ||
1812 | return PTR_ERR(wp); | ||
1813 | |||
1814 | rp = create_read_pipe(wp, 0); | ||
1815 | if (IS_ERR(rp)) { | ||
1816 | free_write_pipe(wp); | ||
1817 | return PTR_ERR(rp); | ||
1818 | } | ||
1819 | |||
1820 | cp->file = wp; | ||
1821 | |||
1822 | sys_close(0); | ||
1823 | fd_install(0, rp); | ||
1824 | spin_lock(&cf->file_lock); | ||
1825 | fdt = files_fdtable(cf); | ||
1826 | FD_SET(0, fdt->open_fds); | ||
1827 | FD_CLR(0, fdt->close_on_exec); | ||
1828 | spin_unlock(&cf->file_lock); | ||
1829 | |||
1830 | /* and disallow core files too */ | ||
1831 | current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; | ||
1832 | |||
1833 | return 0; | ||
1834 | } | ||
1835 | |||
1790 | void do_coredump(long signr, int exit_code, struct pt_regs *regs) | 1836 | void do_coredump(long signr, int exit_code, struct pt_regs *regs) |
1791 | { | 1837 | { |
1792 | struct core_state core_state; | 1838 | struct core_state core_state; |
1793 | char corename[CORENAME_MAX_SIZE + 1]; | 1839 | char corename[CORENAME_MAX_SIZE + 1]; |
1794 | struct mm_struct *mm = current->mm; | 1840 | struct mm_struct *mm = current->mm; |
1795 | struct linux_binfmt * binfmt; | 1841 | struct linux_binfmt * binfmt; |
1796 | struct inode * inode; | ||
1797 | const struct cred *old_cred; | 1842 | const struct cred *old_cred; |
1798 | struct cred *cred; | 1843 | struct cred *cred; |
1799 | int retval = 0; | 1844 | int retval = 0; |
1800 | int flag = 0; | 1845 | int flag = 0; |
1801 | int ispipe = 0; | 1846 | int ispipe; |
1802 | char **helper_argv = NULL; | ||
1803 | int helper_argc = 0; | ||
1804 | int dump_count = 0; | ||
1805 | static atomic_t core_dump_count = ATOMIC_INIT(0); | 1847 | static atomic_t core_dump_count = ATOMIC_INIT(0); |
1806 | struct coredump_params cprm = { | 1848 | struct coredump_params cprm = { |
1807 | .signr = signr, | 1849 | .signr = signr, |
@@ -1820,23 +1862,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
1820 | binfmt = mm->binfmt; | 1862 | binfmt = mm->binfmt; |
1821 | if (!binfmt || !binfmt->core_dump) | 1863 | if (!binfmt || !binfmt->core_dump) |
1822 | goto fail; | 1864 | goto fail; |
1823 | 1865 | if (!__get_dumpable(cprm.mm_flags)) | |
1824 | cred = prepare_creds(); | ||
1825 | if (!cred) { | ||
1826 | retval = -ENOMEM; | ||
1827 | goto fail; | 1866 | goto fail; |
1828 | } | ||
1829 | 1867 | ||
1830 | down_write(&mm->mmap_sem); | 1868 | cred = prepare_creds(); |
1831 | /* | 1869 | if (!cred) |
1832 | * If another thread got here first, or we are not dumpable, bail out. | ||
1833 | */ | ||
1834 | if (mm->core_state || !__get_dumpable(cprm.mm_flags)) { | ||
1835 | up_write(&mm->mmap_sem); | ||
1836 | put_cred(cred); | ||
1837 | goto fail; | 1870 | goto fail; |
1838 | } | ||
1839 | |||
1840 | /* | 1871 | /* |
1841 | * We cannot trust fsuid as being the "true" uid of the | 1872 | * We cannot trust fsuid as being the "true" uid of the |
1842 | * process nor do we know its entire history. We only know it | 1873 | * process nor do we know its entire history. We only know it |
@@ -1849,10 +1880,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
1849 | } | 1880 | } |
1850 | 1881 | ||
1851 | retval = coredump_wait(exit_code, &core_state); | 1882 | retval = coredump_wait(exit_code, &core_state); |
1852 | if (retval < 0) { | 1883 | if (retval < 0) |
1853 | put_cred(cred); | 1884 | goto fail_creds; |
1854 | goto fail; | ||
1855 | } | ||
1856 | 1885 | ||
1857 | old_cred = override_creds(cred); | 1886 | old_cred = override_creds(cred); |
1858 | 1887 | ||
@@ -1870,19 +1899,19 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
1870 | ispipe = format_corename(corename, signr); | 1899 | ispipe = format_corename(corename, signr); |
1871 | unlock_kernel(); | 1900 | unlock_kernel(); |
1872 | 1901 | ||
1873 | if ((!ispipe) && (cprm.limit < binfmt->min_coredump)) | ||
1874 | goto fail_unlock; | ||
1875 | |||
1876 | if (ispipe) { | 1902 | if (ispipe) { |
1877 | if (cprm.limit == 0) { | 1903 | int dump_count; |
1904 | char **helper_argv; | ||
1905 | |||
1906 | if (cprm.limit == 1) { | ||
1878 | /* | 1907 | /* |
1879 | * Normally core limits are irrelevant to pipes, since | 1908 | * Normally core limits are irrelevant to pipes, since |
1880 | * we're not writing to the file system, but we use | 1909 | * we're not writing to the file system, but we use |
1881 | * cprm.limit of 0 here as a speacial value. Any | 1910 | * cprm.limit of 1 here as a speacial value. Any |
1882 | * non-zero limit gets set to RLIM_INFINITY below, but | 1911 | * non-1 limit gets set to RLIM_INFINITY below, but |
1883 | * a limit of 0 skips the dump. This is a consistent | 1912 | * a limit of 0 skips the dump. This is a consistent |
1884 | * way to catch recursive crashes. We can still crash | 1913 | * way to catch recursive crashes. We can still crash |
1885 | * if the core_pattern binary sets RLIM_CORE = !0 | 1914 | * if the core_pattern binary sets RLIM_CORE = !1 |
1886 | * but it runs as root, and can do lots of stupid things | 1915 | * but it runs as root, and can do lots of stupid things |
1887 | * Note that we use task_tgid_vnr here to grab the pid | 1916 | * Note that we use task_tgid_vnr here to grab the pid |
1888 | * of the process group leader. That way we get the | 1917 | * of the process group leader. That way we get the |
@@ -1890,11 +1919,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
1890 | * core_pattern process dies. | 1919 | * core_pattern process dies. |
1891 | */ | 1920 | */ |
1892 | printk(KERN_WARNING | 1921 | printk(KERN_WARNING |
1893 | "Process %d(%s) has RLIMIT_CORE set to 0\n", | 1922 | "Process %d(%s) has RLIMIT_CORE set to 1\n", |
1894 | task_tgid_vnr(current), current->comm); | 1923 | task_tgid_vnr(current), current->comm); |
1895 | printk(KERN_WARNING "Aborting core\n"); | 1924 | printk(KERN_WARNING "Aborting core\n"); |
1896 | goto fail_unlock; | 1925 | goto fail_unlock; |
1897 | } | 1926 | } |
1927 | cprm.limit = RLIM_INFINITY; | ||
1898 | 1928 | ||
1899 | dump_count = atomic_inc_return(&core_dump_count); | 1929 | dump_count = atomic_inc_return(&core_dump_count); |
1900 | if (core_pipe_limit && (core_pipe_limit < dump_count)) { | 1930 | if (core_pipe_limit && (core_pipe_limit < dump_count)) { |
@@ -1904,71 +1934,74 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
1904 | goto fail_dropcount; | 1934 | goto fail_dropcount; |
1905 | } | 1935 | } |
1906 | 1936 | ||
1907 | helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); | 1937 | helper_argv = argv_split(GFP_KERNEL, corename+1, NULL); |
1908 | if (!helper_argv) { | 1938 | if (!helper_argv) { |
1909 | printk(KERN_WARNING "%s failed to allocate memory\n", | 1939 | printk(KERN_WARNING "%s failed to allocate memory\n", |
1910 | __func__); | 1940 | __func__); |
1911 | goto fail_dropcount; | 1941 | goto fail_dropcount; |
1912 | } | 1942 | } |
1913 | 1943 | ||
1914 | cprm.limit = RLIM_INFINITY; | 1944 | retval = call_usermodehelper_fns(helper_argv[0], helper_argv, |
1915 | 1945 | NULL, UMH_WAIT_EXEC, umh_pipe_setup, | |
1916 | /* SIGPIPE can happen, but it's just never processed */ | 1946 | NULL, &cprm); |
1917 | if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL, | 1947 | argv_free(helper_argv); |
1918 | &cprm.file)) { | 1948 | if (retval) { |
1919 | printk(KERN_INFO "Core dump to %s pipe failed\n", | 1949 | printk(KERN_INFO "Core dump to %s pipe failed\n", |
1920 | corename); | 1950 | corename); |
1921 | goto fail_dropcount; | 1951 | goto close_fail; |
1922 | } | 1952 | } |
1923 | } else | 1953 | } else { |
1954 | struct inode *inode; | ||
1955 | |||
1956 | if (cprm.limit < binfmt->min_coredump) | ||
1957 | goto fail_unlock; | ||
1958 | |||
1924 | cprm.file = filp_open(corename, | 1959 | cprm.file = filp_open(corename, |
1925 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, | 1960 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, |
1926 | 0600); | 1961 | 0600); |
1927 | if (IS_ERR(cprm.file)) | 1962 | if (IS_ERR(cprm.file)) |
1928 | goto fail_dropcount; | 1963 | goto fail_unlock; |
1929 | inode = cprm.file->f_path.dentry->d_inode; | ||
1930 | if (inode->i_nlink > 1) | ||
1931 | goto close_fail; /* multiple links - don't dump */ | ||
1932 | if (!ispipe && d_unhashed(cprm.file->f_path.dentry)) | ||
1933 | goto close_fail; | ||
1934 | |||
1935 | /* AK: actually i see no reason to not allow this for named pipes etc., | ||
1936 | but keep the previous behaviour for now. */ | ||
1937 | if (!ispipe && !S_ISREG(inode->i_mode)) | ||
1938 | goto close_fail; | ||
1939 | /* | ||
1940 | * Dont allow local users get cute and trick others to coredump | ||
1941 | * into their pre-created files: | ||
1942 | * Note, this is not relevant for pipes | ||
1943 | */ | ||
1944 | if (!ispipe && (inode->i_uid != current_fsuid())) | ||
1945 | goto close_fail; | ||
1946 | if (!cprm.file->f_op) | ||
1947 | goto close_fail; | ||
1948 | if (!cprm.file->f_op->write) | ||
1949 | goto close_fail; | ||
1950 | if (!ispipe && | ||
1951 | do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file) != 0) | ||
1952 | goto close_fail; | ||
1953 | 1964 | ||
1954 | retval = binfmt->core_dump(&cprm); | 1965 | inode = cprm.file->f_path.dentry->d_inode; |
1966 | if (inode->i_nlink > 1) | ||
1967 | goto close_fail; | ||
1968 | if (d_unhashed(cprm.file->f_path.dentry)) | ||
1969 | goto close_fail; | ||
1970 | /* | ||
1971 | * AK: actually i see no reason to not allow this for named | ||
1972 | * pipes etc, but keep the previous behaviour for now. | ||
1973 | */ | ||
1974 | if (!S_ISREG(inode->i_mode)) | ||
1975 | goto close_fail; | ||
1976 | /* | ||
1977 | * Dont allow local users get cute and trick others to coredump | ||
1978 | * into their pre-created files. | ||
1979 | */ | ||
1980 | if (inode->i_uid != current_fsuid()) | ||
1981 | goto close_fail; | ||
1982 | if (!cprm.file->f_op || !cprm.file->f_op->write) | ||
1983 | goto close_fail; | ||
1984 | if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file)) | ||
1985 | goto close_fail; | ||
1986 | } | ||
1955 | 1987 | ||
1988 | retval = binfmt->core_dump(&cprm); | ||
1956 | if (retval) | 1989 | if (retval) |
1957 | current->signal->group_exit_code |= 0x80; | 1990 | current->signal->group_exit_code |= 0x80; |
1958 | close_fail: | 1991 | |
1959 | if (ispipe && core_pipe_limit) | 1992 | if (ispipe && core_pipe_limit) |
1960 | wait_for_dump_helpers(cprm.file); | 1993 | wait_for_dump_helpers(cprm.file); |
1961 | filp_close(cprm.file, NULL); | 1994 | close_fail: |
1995 | if (cprm.file) | ||
1996 | filp_close(cprm.file, NULL); | ||
1962 | fail_dropcount: | 1997 | fail_dropcount: |
1963 | if (dump_count) | 1998 | if (ispipe) |
1964 | atomic_dec(&core_dump_count); | 1999 | atomic_dec(&core_dump_count); |
1965 | fail_unlock: | 2000 | fail_unlock: |
1966 | if (helper_argv) | 2001 | coredump_finish(mm); |
1967 | argv_free(helper_argv); | ||
1968 | |||
1969 | revert_creds(old_cred); | 2002 | revert_creds(old_cred); |
2003 | fail_creds: | ||
1970 | put_cred(cred); | 2004 | put_cred(cred); |
1971 | coredump_finish(mm); | ||
1972 | fail: | 2005 | fail: |
1973 | return; | 2006 | return; |
1974 | } | 2007 | } |