aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c62
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 */
1888static int validate_prctl_map(struct prctl_mm_map *prctl_map) 1890static 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;
1971out: 1954out:
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;
2220out: 2225out:
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