diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 213 |
1 files changed, 149 insertions, 64 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 6df42624e454..9ff89cb9657a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/personality.h> | 36 | #include <linux/personality.h> |
37 | #include <linux/ptrace.h> | 37 | #include <linux/ptrace.h> |
38 | #include <linux/fs_struct.h> | 38 | #include <linux/fs_struct.h> |
39 | #include <linux/file.h> | ||
40 | #include <linux/mount.h> | ||
39 | #include <linux/gfp.h> | 41 | #include <linux/gfp.h> |
40 | #include <linux/syscore_ops.h> | 42 | #include <linux/syscore_ops.h> |
41 | #include <linux/version.h> | 43 | #include <linux/version.h> |
@@ -1378,8 +1380,8 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1378 | memcpy(u->nodename, tmp, len); | 1380 | memcpy(u->nodename, tmp, len); |
1379 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); | 1381 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); |
1380 | errno = 0; | 1382 | errno = 0; |
1383 | uts_proc_notify(UTS_PROC_HOSTNAME); | ||
1381 | } | 1384 | } |
1382 | uts_proc_notify(UTS_PROC_HOSTNAME); | ||
1383 | up_write(&uts_sem); | 1385 | up_write(&uts_sem); |
1384 | return errno; | 1386 | return errno; |
1385 | } | 1387 | } |
@@ -1429,8 +1431,8 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1429 | memcpy(u->domainname, tmp, len); | 1431 | memcpy(u->domainname, tmp, len); |
1430 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); | 1432 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); |
1431 | errno = 0; | 1433 | errno = 0; |
1434 | uts_proc_notify(UTS_PROC_DOMAINNAME); | ||
1432 | } | 1435 | } |
1433 | uts_proc_notify(UTS_PROC_DOMAINNAME); | ||
1434 | up_write(&uts_sem); | 1436 | up_write(&uts_sem); |
1435 | return errno; | 1437 | return errno; |
1436 | } | 1438 | } |
@@ -1784,77 +1786,102 @@ SYSCALL_DEFINE1(umask, int, mask) | |||
1784 | } | 1786 | } |
1785 | 1787 | ||
1786 | #ifdef CONFIG_CHECKPOINT_RESTORE | 1788 | #ifdef CONFIG_CHECKPOINT_RESTORE |
1789 | static bool vma_flags_mismatch(struct vm_area_struct *vma, | ||
1790 | unsigned long required, | ||
1791 | unsigned long banned) | ||
1792 | { | ||
1793 | return (vma->vm_flags & required) != required || | ||
1794 | (vma->vm_flags & banned); | ||
1795 | } | ||
1796 | |||
1797 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | ||
1798 | { | ||
1799 | struct file *exe_file; | ||
1800 | struct dentry *dentry; | ||
1801 | int err; | ||
1802 | |||
1803 | /* | ||
1804 | * Setting new mm::exe_file is only allowed when no VM_EXECUTABLE vma's | ||
1805 | * remain. So perform a quick test first. | ||
1806 | */ | ||
1807 | if (mm->num_exe_file_vmas) | ||
1808 | return -EBUSY; | ||
1809 | |||
1810 | exe_file = fget(fd); | ||
1811 | if (!exe_file) | ||
1812 | return -EBADF; | ||
1813 | |||
1814 | dentry = exe_file->f_path.dentry; | ||
1815 | |||
1816 | /* | ||
1817 | * Because the original mm->exe_file points to executable file, make | ||
1818 | * sure that this one is executable as well, to avoid breaking an | ||
1819 | * overall picture. | ||
1820 | */ | ||
1821 | err = -EACCES; | ||
1822 | if (!S_ISREG(dentry->d_inode->i_mode) || | ||
1823 | exe_file->f_path.mnt->mnt_flags & MNT_NOEXEC) | ||
1824 | goto exit; | ||
1825 | |||
1826 | err = inode_permission(dentry->d_inode, MAY_EXEC); | ||
1827 | if (err) | ||
1828 | goto exit; | ||
1829 | |||
1830 | /* | ||
1831 | * The symlink can be changed only once, just to disallow arbitrary | ||
1832 | * transitions malicious software might bring in. This means one | ||
1833 | * could make a snapshot over all processes running and monitor | ||
1834 | * /proc/pid/exe changes to notice unusual activity if needed. | ||
1835 | */ | ||
1836 | down_write(&mm->mmap_sem); | ||
1837 | if (likely(!mm->exe_file)) | ||
1838 | set_mm_exe_file(mm, exe_file); | ||
1839 | else | ||
1840 | err = -EBUSY; | ||
1841 | up_write(&mm->mmap_sem); | ||
1842 | |||
1843 | exit: | ||
1844 | fput(exe_file); | ||
1845 | return err; | ||
1846 | } | ||
1847 | |||
1787 | static int prctl_set_mm(int opt, unsigned long addr, | 1848 | static int prctl_set_mm(int opt, unsigned long addr, |
1788 | unsigned long arg4, unsigned long arg5) | 1849 | unsigned long arg4, unsigned long arg5) |
1789 | { | 1850 | { |
1790 | unsigned long rlim = rlimit(RLIMIT_DATA); | 1851 | unsigned long rlim = rlimit(RLIMIT_DATA); |
1791 | unsigned long vm_req_flags; | ||
1792 | unsigned long vm_bad_flags; | ||
1793 | struct vm_area_struct *vma; | ||
1794 | int error = 0; | ||
1795 | struct mm_struct *mm = current->mm; | 1852 | struct mm_struct *mm = current->mm; |
1853 | struct vm_area_struct *vma; | ||
1854 | int error; | ||
1796 | 1855 | ||
1797 | if (arg4 | arg5) | 1856 | if (arg5 || (arg4 && opt != PR_SET_MM_AUXV)) |
1798 | return -EINVAL; | 1857 | return -EINVAL; |
1799 | 1858 | ||
1800 | if (!capable(CAP_SYS_RESOURCE)) | 1859 | if (!capable(CAP_SYS_RESOURCE)) |
1801 | return -EPERM; | 1860 | return -EPERM; |
1802 | 1861 | ||
1862 | if (opt == PR_SET_MM_EXE_FILE) | ||
1863 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); | ||
1864 | |||
1803 | if (addr >= TASK_SIZE) | 1865 | if (addr >= TASK_SIZE) |
1804 | return -EINVAL; | 1866 | return -EINVAL; |
1805 | 1867 | ||
1868 | error = -EINVAL; | ||
1869 | |||
1806 | down_read(&mm->mmap_sem); | 1870 | down_read(&mm->mmap_sem); |
1807 | vma = find_vma(mm, addr); | 1871 | vma = find_vma(mm, addr); |
1808 | 1872 | ||
1809 | if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) { | ||
1810 | /* It must be existing VMA */ | ||
1811 | if (!vma || vma->vm_start > addr) | ||
1812 | goto out; | ||
1813 | } | ||
1814 | |||
1815 | error = -EINVAL; | ||
1816 | switch (opt) { | 1873 | switch (opt) { |
1817 | case PR_SET_MM_START_CODE: | 1874 | case PR_SET_MM_START_CODE: |
1875 | mm->start_code = addr; | ||
1876 | break; | ||
1818 | case PR_SET_MM_END_CODE: | 1877 | case PR_SET_MM_END_CODE: |
1819 | vm_req_flags = VM_READ | VM_EXEC; | 1878 | mm->end_code = addr; |
1820 | vm_bad_flags = VM_WRITE | VM_MAYSHARE; | ||
1821 | |||
1822 | if ((vma->vm_flags & vm_req_flags) != vm_req_flags || | ||
1823 | (vma->vm_flags & vm_bad_flags)) | ||
1824 | goto out; | ||
1825 | |||
1826 | if (opt == PR_SET_MM_START_CODE) | ||
1827 | mm->start_code = addr; | ||
1828 | else | ||
1829 | mm->end_code = addr; | ||
1830 | break; | 1879 | break; |
1831 | |||
1832 | case PR_SET_MM_START_DATA: | 1880 | case PR_SET_MM_START_DATA: |
1833 | case PR_SET_MM_END_DATA: | 1881 | mm->start_data = addr; |
1834 | vm_req_flags = VM_READ | VM_WRITE; | ||
1835 | vm_bad_flags = VM_EXEC | VM_MAYSHARE; | ||
1836 | |||
1837 | if ((vma->vm_flags & vm_req_flags) != vm_req_flags || | ||
1838 | (vma->vm_flags & vm_bad_flags)) | ||
1839 | goto out; | ||
1840 | |||
1841 | if (opt == PR_SET_MM_START_DATA) | ||
1842 | mm->start_data = addr; | ||
1843 | else | ||
1844 | mm->end_data = addr; | ||
1845 | break; | 1882 | break; |
1846 | 1883 | case PR_SET_MM_END_DATA: | |
1847 | case PR_SET_MM_START_STACK: | 1884 | mm->end_data = addr; |
1848 | |||
1849 | #ifdef CONFIG_STACK_GROWSUP | ||
1850 | vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP; | ||
1851 | #else | ||
1852 | vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN; | ||
1853 | #endif | ||
1854 | if ((vma->vm_flags & vm_req_flags) != vm_req_flags) | ||
1855 | goto out; | ||
1856 | |||
1857 | mm->start_stack = addr; | ||
1858 | break; | 1885 | break; |
1859 | 1886 | ||
1860 | case PR_SET_MM_START_BRK: | 1887 | case PR_SET_MM_START_BRK: |
@@ -1881,16 +1908,77 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
1881 | mm->brk = addr; | 1908 | mm->brk = addr; |
1882 | break; | 1909 | break; |
1883 | 1910 | ||
1911 | /* | ||
1912 | * If command line arguments and environment | ||
1913 | * are placed somewhere else on stack, we can | ||
1914 | * set them up here, ARG_START/END to setup | ||
1915 | * command line argumets and ENV_START/END | ||
1916 | * for environment. | ||
1917 | */ | ||
1918 | case PR_SET_MM_START_STACK: | ||
1919 | case PR_SET_MM_ARG_START: | ||
1920 | case PR_SET_MM_ARG_END: | ||
1921 | case PR_SET_MM_ENV_START: | ||
1922 | case PR_SET_MM_ENV_END: | ||
1923 | if (!vma) { | ||
1924 | error = -EFAULT; | ||
1925 | goto out; | ||
1926 | } | ||
1927 | #ifdef CONFIG_STACK_GROWSUP | ||
1928 | if (vma_flags_mismatch(vma, VM_READ | VM_WRITE | VM_GROWSUP, 0)) | ||
1929 | #else | ||
1930 | if (vma_flags_mismatch(vma, VM_READ | VM_WRITE | VM_GROWSDOWN, 0)) | ||
1931 | #endif | ||
1932 | goto out; | ||
1933 | if (opt == PR_SET_MM_START_STACK) | ||
1934 | mm->start_stack = addr; | ||
1935 | else if (opt == PR_SET_MM_ARG_START) | ||
1936 | mm->arg_start = addr; | ||
1937 | else if (opt == PR_SET_MM_ARG_END) | ||
1938 | mm->arg_end = addr; | ||
1939 | else if (opt == PR_SET_MM_ENV_START) | ||
1940 | mm->env_start = addr; | ||
1941 | else if (opt == PR_SET_MM_ENV_END) | ||
1942 | mm->env_end = addr; | ||
1943 | break; | ||
1944 | |||
1945 | /* | ||
1946 | * This doesn't move auxiliary vector itself | ||
1947 | * since it's pinned to mm_struct, but allow | ||
1948 | * to fill vector with new values. It's up | ||
1949 | * to a caller to provide sane values here | ||
1950 | * otherwise user space tools which use this | ||
1951 | * vector might be unhappy. | ||
1952 | */ | ||
1953 | case PR_SET_MM_AUXV: { | ||
1954 | unsigned long user_auxv[AT_VECTOR_SIZE]; | ||
1955 | |||
1956 | if (arg4 > sizeof(user_auxv)) | ||
1957 | goto out; | ||
1958 | up_read(&mm->mmap_sem); | ||
1959 | |||
1960 | if (copy_from_user(user_auxv, (const void __user *)addr, arg4)) | ||
1961 | return -EFAULT; | ||
1962 | |||
1963 | /* Make sure the last entry is always AT_NULL */ | ||
1964 | user_auxv[AT_VECTOR_SIZE - 2] = 0; | ||
1965 | user_auxv[AT_VECTOR_SIZE - 1] = 0; | ||
1966 | |||
1967 | BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); | ||
1968 | |||
1969 | task_lock(current); | ||
1970 | memcpy(mm->saved_auxv, user_auxv, arg4); | ||
1971 | task_unlock(current); | ||
1972 | |||
1973 | return 0; | ||
1974 | } | ||
1884 | default: | 1975 | default: |
1885 | error = -EINVAL; | ||
1886 | goto out; | 1976 | goto out; |
1887 | } | 1977 | } |
1888 | 1978 | ||
1889 | error = 0; | 1979 | error = 0; |
1890 | |||
1891 | out: | 1980 | out: |
1892 | up_read(&mm->mmap_sem); | 1981 | up_read(&mm->mmap_sem); |
1893 | |||
1894 | return error; | 1982 | return error; |
1895 | } | 1983 | } |
1896 | #else /* CONFIG_CHECKPOINT_RESTORE */ | 1984 | #else /* CONFIG_CHECKPOINT_RESTORE */ |
@@ -2114,7 +2202,6 @@ int orderly_poweroff(bool force) | |||
2114 | NULL | 2202 | NULL |
2115 | }; | 2203 | }; |
2116 | int ret = -ENOMEM; | 2204 | int ret = -ENOMEM; |
2117 | struct subprocess_info *info; | ||
2118 | 2205 | ||
2119 | if (argv == NULL) { | 2206 | if (argv == NULL) { |
2120 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", | 2207 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", |
@@ -2122,18 +2209,16 @@ int orderly_poweroff(bool force) | |||
2122 | goto out; | 2209 | goto out; |
2123 | } | 2210 | } |
2124 | 2211 | ||
2125 | info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC); | 2212 | ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_NO_WAIT, |
2126 | if (info == NULL) { | 2213 | NULL, argv_cleanup, NULL); |
2127 | argv_free(argv); | 2214 | out: |
2128 | goto out; | 2215 | if (likely(!ret)) |
2129 | } | 2216 | return 0; |
2130 | |||
2131 | call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL); | ||
2132 | 2217 | ||
2133 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); | 2218 | if (ret == -ENOMEM) |
2219 | argv_free(argv); | ||
2134 | 2220 | ||
2135 | out: | 2221 | if (force) { |
2136 | if (ret && force) { | ||
2137 | printk(KERN_WARNING "Failed to start orderly shutdown: " | 2222 | printk(KERN_WARNING "Failed to start orderly shutdown: " |
2138 | "forcing the issue\n"); | 2223 | "forcing the issue\n"); |
2139 | 2224 | ||