diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 60 |
1 files changed, 33 insertions, 27 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 9ff89cb9657a..e0c8ffc50d7f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -1786,27 +1786,13 @@ SYSCALL_DEFINE1(umask, int, mask) | |||
| 1786 | } | 1786 | } |
| 1787 | 1787 | ||
| 1788 | #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) | 1789 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) |
| 1798 | { | 1790 | { |
| 1791 | struct vm_area_struct *vma; | ||
| 1799 | struct file *exe_file; | 1792 | struct file *exe_file; |
| 1800 | struct dentry *dentry; | 1793 | struct dentry *dentry; |
| 1801 | int err; | 1794 | int err; |
| 1802 | 1795 | ||
| 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); | 1796 | exe_file = fget(fd); |
| 1811 | if (!exe_file) | 1797 | if (!exe_file) |
| 1812 | return -EBADF; | 1798 | return -EBADF; |
| @@ -1827,17 +1813,30 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | |||
| 1827 | if (err) | 1813 | if (err) |
| 1828 | goto exit; | 1814 | goto exit; |
| 1829 | 1815 | ||
| 1816 | down_write(&mm->mmap_sem); | ||
| 1817 | |||
| 1818 | /* | ||
| 1819 | * Forbid mm->exe_file change if there are mapped other files. | ||
| 1820 | */ | ||
| 1821 | err = -EBUSY; | ||
| 1822 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
| 1823 | if (vma->vm_file && !path_equal(&vma->vm_file->f_path, | ||
| 1824 | &exe_file->f_path)) | ||
| 1825 | goto exit_unlock; | ||
| 1826 | } | ||
| 1827 | |||
| 1830 | /* | 1828 | /* |
| 1831 | * The symlink can be changed only once, just to disallow arbitrary | 1829 | * The symlink can be changed only once, just to disallow arbitrary |
| 1832 | * transitions malicious software might bring in. This means one | 1830 | * transitions malicious software might bring in. This means one |
| 1833 | * could make a snapshot over all processes running and monitor | 1831 | * could make a snapshot over all processes running and monitor |
| 1834 | * /proc/pid/exe changes to notice unusual activity if needed. | 1832 | * /proc/pid/exe changes to notice unusual activity if needed. |
| 1835 | */ | 1833 | */ |
| 1836 | down_write(&mm->mmap_sem); | 1834 | err = -EPERM; |
| 1837 | if (likely(!mm->exe_file)) | 1835 | if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags)) |
| 1838 | set_mm_exe_file(mm, exe_file); | 1836 | goto exit_unlock; |
| 1839 | else | 1837 | |
| 1840 | err = -EBUSY; | 1838 | set_mm_exe_file(mm, exe_file); |
| 1839 | exit_unlock: | ||
| 1841 | up_write(&mm->mmap_sem); | 1840 | up_write(&mm->mmap_sem); |
| 1842 | 1841 | ||
| 1843 | exit: | 1842 | exit: |
| @@ -1862,7 +1861,7 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
| 1862 | if (opt == PR_SET_MM_EXE_FILE) | 1861 | if (opt == PR_SET_MM_EXE_FILE) |
| 1863 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); | 1862 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); |
| 1864 | 1863 | ||
| 1865 | if (addr >= TASK_SIZE) | 1864 | if (addr >= TASK_SIZE || addr < mmap_min_addr) |
| 1866 | return -EINVAL; | 1865 | return -EINVAL; |
| 1867 | 1866 | ||
| 1868 | error = -EINVAL; | 1867 | error = -EINVAL; |
| @@ -1924,12 +1923,6 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
| 1924 | error = -EFAULT; | 1923 | error = -EFAULT; |
| 1925 | goto out; | 1924 | goto out; |
| 1926 | } | 1925 | } |
| 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) | 1926 | if (opt == PR_SET_MM_START_STACK) |
| 1934 | mm->start_stack = addr; | 1927 | mm->start_stack = addr; |
| 1935 | else if (opt == PR_SET_MM_ARG_START) | 1928 | else if (opt == PR_SET_MM_ARG_START) |
| @@ -1981,12 +1974,22 @@ out: | |||
| 1981 | up_read(&mm->mmap_sem); | 1974 | up_read(&mm->mmap_sem); |
| 1982 | return error; | 1975 | return error; |
| 1983 | } | 1976 | } |
| 1977 | |||
| 1978 | static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) | ||
| 1979 | { | ||
| 1980 | return put_user(me->clear_child_tid, tid_addr); | ||
| 1981 | } | ||
| 1982 | |||
| 1984 | #else /* CONFIG_CHECKPOINT_RESTORE */ | 1983 | #else /* CONFIG_CHECKPOINT_RESTORE */ |
| 1985 | static int prctl_set_mm(int opt, unsigned long addr, | 1984 | static int prctl_set_mm(int opt, unsigned long addr, |
| 1986 | unsigned long arg4, unsigned long arg5) | 1985 | unsigned long arg4, unsigned long arg5) |
| 1987 | { | 1986 | { |
| 1988 | return -EINVAL; | 1987 | return -EINVAL; |
| 1989 | } | 1988 | } |
| 1989 | static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) | ||
| 1990 | { | ||
| 1991 | return -EINVAL; | ||
| 1992 | } | ||
| 1990 | #endif | 1993 | #endif |
| 1991 | 1994 | ||
| 1992 | SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | 1995 | SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, |
| @@ -2141,6 +2144,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 2141 | case PR_SET_MM: | 2144 | case PR_SET_MM: |
| 2142 | error = prctl_set_mm(arg2, arg3, arg4, arg5); | 2145 | error = prctl_set_mm(arg2, arg3, arg4, arg5); |
| 2143 | break; | 2146 | break; |
| 2147 | case PR_GET_TID_ADDRESS: | ||
| 2148 | error = prctl_get_tid_address(me, (int __user **)arg2); | ||
| 2149 | break; | ||
| 2144 | case PR_SET_CHILD_SUBREAPER: | 2150 | case PR_SET_CHILD_SUBREAPER: |
| 2145 | me->signal->is_child_subreaper = !!arg2; | 2151 | me->signal->is_child_subreaper = !!arg2; |
| 2146 | error = 0; | 2152 | error = 0; |
