diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 62 |
1 files changed, 34 insertions, 28 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index bdbfe8d37418..2969304c29fe 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1882,13 +1882,14 @@ exit_err: | |||
1882 | } | 1882 | } |
1883 | 1883 | ||
1884 | /* | 1884 | /* |
1885 | * Check arithmetic relations of passed addresses. | ||
1886 | * | ||
1885 | * WARNING: we don't require any capability here so be very careful | 1887 | * WARNING: we don't require any capability here so be very careful |
1886 | * in what is allowed for modification from userspace. | 1888 | * in what is allowed for modification from userspace. |
1887 | */ | 1889 | */ |
1888 | static int validate_prctl_map(struct prctl_mm_map *prctl_map) | 1890 | static int validate_prctl_map_addr(struct prctl_mm_map *prctl_map) |
1889 | { | 1891 | { |
1890 | unsigned long mmap_max_addr = TASK_SIZE; | 1892 | unsigned long mmap_max_addr = TASK_SIZE; |
1891 | struct mm_struct *mm = current->mm; | ||
1892 | int error = -EINVAL, i; | 1893 | int error = -EINVAL, i; |
1893 | 1894 | ||
1894 | static const unsigned char offsets[] = { | 1895 | static const unsigned char offsets[] = { |
@@ -1949,24 +1950,6 @@ static int validate_prctl_map(struct prctl_mm_map *prctl_map) | |||
1949 | prctl_map->start_data)) | 1950 | prctl_map->start_data)) |
1950 | goto out; | 1951 | goto out; |
1951 | 1952 | ||
1952 | /* | ||
1953 | * Someone is trying to cheat the auxv vector. | ||
1954 | */ | ||
1955 | if (prctl_map->auxv_size) { | ||
1956 | if (!prctl_map->auxv || prctl_map->auxv_size > sizeof(mm->saved_auxv)) | ||
1957 | goto out; | ||
1958 | } | ||
1959 | |||
1960 | /* | ||
1961 | * Finally, make sure the caller has the rights to | ||
1962 | * change /proc/pid/exe link: only local sys admin should | ||
1963 | * be allowed to. | ||
1964 | */ | ||
1965 | if (prctl_map->exe_fd != (u32)-1) { | ||
1966 | if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) | ||
1967 | goto out; | ||
1968 | } | ||
1969 | |||
1970 | error = 0; | 1953 | error = 0; |
1971 | out: | 1954 | out: |
1972 | return error; | 1955 | return error; |
@@ -1993,11 +1976,18 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data | |||
1993 | if (copy_from_user(&prctl_map, addr, sizeof(prctl_map))) | 1976 | if (copy_from_user(&prctl_map, addr, sizeof(prctl_map))) |
1994 | return -EFAULT; | 1977 | return -EFAULT; |
1995 | 1978 | ||
1996 | error = validate_prctl_map(&prctl_map); | 1979 | error = validate_prctl_map_addr(&prctl_map); |
1997 | if (error) | 1980 | if (error) |
1998 | return error; | 1981 | return error; |
1999 | 1982 | ||
2000 | if (prctl_map.auxv_size) { | 1983 | if (prctl_map.auxv_size) { |
1984 | /* | ||
1985 | * Someone is trying to cheat the auxv vector. | ||
1986 | */ | ||
1987 | if (!prctl_map.auxv || | ||
1988 | prctl_map.auxv_size > sizeof(mm->saved_auxv)) | ||
1989 | return -EINVAL; | ||
1990 | |||
2001 | memset(user_auxv, 0, sizeof(user_auxv)); | 1991 | memset(user_auxv, 0, sizeof(user_auxv)); |
2002 | if (copy_from_user(user_auxv, | 1992 | if (copy_from_user(user_auxv, |
2003 | (const void __user *)prctl_map.auxv, | 1993 | (const void __user *)prctl_map.auxv, |
@@ -2010,6 +2000,14 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data | |||
2010 | } | 2000 | } |
2011 | 2001 | ||
2012 | if (prctl_map.exe_fd != (u32)-1) { | 2002 | if (prctl_map.exe_fd != (u32)-1) { |
2003 | /* | ||
2004 | * Make sure the caller has the rights to | ||
2005 | * change /proc/pid/exe link: only local sys admin should | ||
2006 | * be allowed to. | ||
2007 | */ | ||
2008 | if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) | ||
2009 | return -EINVAL; | ||
2010 | |||
2013 | error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd); | 2011 | error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd); |
2014 | if (error) | 2012 | if (error) |
2015 | return error; | 2013 | return error; |
@@ -2097,7 +2095,11 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
2097 | unsigned long arg4, unsigned long arg5) | 2095 | unsigned long arg4, unsigned long arg5) |
2098 | { | 2096 | { |
2099 | struct mm_struct *mm = current->mm; | 2097 | struct mm_struct *mm = current->mm; |
2100 | struct prctl_mm_map prctl_map; | 2098 | struct prctl_mm_map prctl_map = { |
2099 | .auxv = NULL, | ||
2100 | .auxv_size = 0, | ||
2101 | .exe_fd = -1, | ||
2102 | }; | ||
2101 | struct vm_area_struct *vma; | 2103 | struct vm_area_struct *vma; |
2102 | int error; | 2104 | int error; |
2103 | 2105 | ||
@@ -2125,9 +2127,15 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
2125 | 2127 | ||
2126 | error = -EINVAL; | 2128 | error = -EINVAL; |
2127 | 2129 | ||
2128 | down_write(&mm->mmap_sem); | 2130 | /* |
2131 | * arg_lock protects concurent updates of arg boundaries, we need | ||
2132 | * mmap_sem for a) concurrent sys_brk, b) finding VMA for addr | ||
2133 | * validation. | ||
2134 | */ | ||
2135 | down_read(&mm->mmap_sem); | ||
2129 | vma = find_vma(mm, addr); | 2136 | vma = find_vma(mm, addr); |
2130 | 2137 | ||
2138 | spin_lock(&mm->arg_lock); | ||
2131 | prctl_map.start_code = mm->start_code; | 2139 | prctl_map.start_code = mm->start_code; |
2132 | prctl_map.end_code = mm->end_code; | 2140 | prctl_map.end_code = mm->end_code; |
2133 | prctl_map.start_data = mm->start_data; | 2141 | prctl_map.start_data = mm->start_data; |
@@ -2139,9 +2147,6 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
2139 | prctl_map.arg_end = mm->arg_end; | 2147 | prctl_map.arg_end = mm->arg_end; |
2140 | prctl_map.env_start = mm->env_start; | 2148 | prctl_map.env_start = mm->env_start; |
2141 | prctl_map.env_end = mm->env_end; | 2149 | prctl_map.env_end = mm->env_end; |
2142 | prctl_map.auxv = NULL; | ||
2143 | prctl_map.auxv_size = 0; | ||
2144 | prctl_map.exe_fd = -1; | ||
2145 | 2150 | ||
2146 | switch (opt) { | 2151 | switch (opt) { |
2147 | case PR_SET_MM_START_CODE: | 2152 | case PR_SET_MM_START_CODE: |
@@ -2181,7 +2186,7 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
2181 | goto out; | 2186 | goto out; |
2182 | } | 2187 | } |
2183 | 2188 | ||
2184 | error = validate_prctl_map(&prctl_map); | 2189 | error = validate_prctl_map_addr(&prctl_map); |
2185 | if (error) | 2190 | if (error) |
2186 | goto out; | 2191 | goto out; |
2187 | 2192 | ||
@@ -2218,7 +2223,8 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
2218 | 2223 | ||
2219 | error = 0; | 2224 | error = 0; |
2220 | out: | 2225 | out: |
2221 | up_write(&mm->mmap_sem); | 2226 | spin_unlock(&mm->arg_lock); |
2227 | up_read(&mm->mmap_sem); | ||
2222 | return error; | 2228 | return error; |
2223 | } | 2229 | } |
2224 | 2230 | ||