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