diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 158 |
1 files changed, 91 insertions, 67 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 8571296b7ddb..259fda25eb6b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1722,7 +1722,6 @@ exit_err: | |||
1722 | goto exit; | 1722 | goto exit; |
1723 | } | 1723 | } |
1724 | 1724 | ||
1725 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
1726 | /* | 1725 | /* |
1727 | * WARNING: we don't require any capability here so be very careful | 1726 | * WARNING: we don't require any capability here so be very careful |
1728 | * in what is allowed for modification from userspace. | 1727 | * in what is allowed for modification from userspace. |
@@ -1818,6 +1817,7 @@ out: | |||
1818 | return error; | 1817 | return error; |
1819 | } | 1818 | } |
1820 | 1819 | ||
1820 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
1821 | static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data_size) | 1821 | static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data_size) |
1822 | { | 1822 | { |
1823 | struct prctl_mm_map prctl_map = { .exe_fd = (u32)-1, }; | 1823 | struct prctl_mm_map prctl_map = { .exe_fd = (u32)-1, }; |
@@ -1902,10 +1902,41 @@ out: | |||
1902 | } | 1902 | } |
1903 | #endif /* CONFIG_CHECKPOINT_RESTORE */ | 1903 | #endif /* CONFIG_CHECKPOINT_RESTORE */ |
1904 | 1904 | ||
1905 | static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr, | ||
1906 | unsigned long len) | ||
1907 | { | ||
1908 | /* | ||
1909 | * This doesn't move the auxiliary vector itself since it's pinned to | ||
1910 | * mm_struct, but it permits filling the vector with new values. It's | ||
1911 | * up to the caller to provide sane values here, otherwise userspace | ||
1912 | * tools which use this vector might be unhappy. | ||
1913 | */ | ||
1914 | unsigned long user_auxv[AT_VECTOR_SIZE]; | ||
1915 | |||
1916 | if (len > sizeof(user_auxv)) | ||
1917 | return -EINVAL; | ||
1918 | |||
1919 | if (copy_from_user(user_auxv, (const void __user *)addr, len)) | ||
1920 | return -EFAULT; | ||
1921 | |||
1922 | /* Make sure the last entry is always AT_NULL */ | ||
1923 | user_auxv[AT_VECTOR_SIZE - 2] = 0; | ||
1924 | user_auxv[AT_VECTOR_SIZE - 1] = 0; | ||
1925 | |||
1926 | BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); | ||
1927 | |||
1928 | task_lock(current); | ||
1929 | memcpy(mm->saved_auxv, user_auxv, len); | ||
1930 | task_unlock(current); | ||
1931 | |||
1932 | return 0; | ||
1933 | } | ||
1934 | |||
1905 | static int prctl_set_mm(int opt, unsigned long addr, | 1935 | static int prctl_set_mm(int opt, unsigned long addr, |
1906 | unsigned long arg4, unsigned long arg5) | 1936 | unsigned long arg4, unsigned long arg5) |
1907 | { | 1937 | { |
1908 | struct mm_struct *mm = current->mm; | 1938 | struct mm_struct *mm = current->mm; |
1939 | struct prctl_mm_map prctl_map; | ||
1909 | struct vm_area_struct *vma; | 1940 | struct vm_area_struct *vma; |
1910 | int error; | 1941 | int error; |
1911 | 1942 | ||
@@ -1925,6 +1956,9 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
1925 | if (opt == PR_SET_MM_EXE_FILE) | 1956 | if (opt == PR_SET_MM_EXE_FILE) |
1926 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); | 1957 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); |
1927 | 1958 | ||
1959 | if (opt == PR_SET_MM_AUXV) | ||
1960 | return prctl_set_auxv(mm, addr, arg4); | ||
1961 | |||
1928 | if (addr >= TASK_SIZE || addr < mmap_min_addr) | 1962 | if (addr >= TASK_SIZE || addr < mmap_min_addr) |
1929 | return -EINVAL; | 1963 | return -EINVAL; |
1930 | 1964 | ||
@@ -1933,42 +1967,64 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
1933 | down_read(&mm->mmap_sem); | 1967 | down_read(&mm->mmap_sem); |
1934 | vma = find_vma(mm, addr); | 1968 | vma = find_vma(mm, addr); |
1935 | 1969 | ||
1970 | prctl_map.start_code = mm->start_code; | ||
1971 | prctl_map.end_code = mm->end_code; | ||
1972 | prctl_map.start_data = mm->start_data; | ||
1973 | prctl_map.end_data = mm->end_data; | ||
1974 | prctl_map.start_brk = mm->start_brk; | ||
1975 | prctl_map.brk = mm->brk; | ||
1976 | prctl_map.start_stack = mm->start_stack; | ||
1977 | prctl_map.arg_start = mm->arg_start; | ||
1978 | prctl_map.arg_end = mm->arg_end; | ||
1979 | prctl_map.env_start = mm->env_start; | ||
1980 | prctl_map.env_end = mm->env_end; | ||
1981 | prctl_map.auxv = NULL; | ||
1982 | prctl_map.auxv_size = 0; | ||
1983 | prctl_map.exe_fd = -1; | ||
1984 | |||
1936 | switch (opt) { | 1985 | switch (opt) { |
1937 | case PR_SET_MM_START_CODE: | 1986 | case PR_SET_MM_START_CODE: |
1938 | mm->start_code = addr; | 1987 | prctl_map.start_code = addr; |
1939 | break; | 1988 | break; |
1940 | case PR_SET_MM_END_CODE: | 1989 | case PR_SET_MM_END_CODE: |
1941 | mm->end_code = addr; | 1990 | prctl_map.end_code = addr; |
1942 | break; | 1991 | break; |
1943 | case PR_SET_MM_START_DATA: | 1992 | case PR_SET_MM_START_DATA: |
1944 | mm->start_data = addr; | 1993 | prctl_map.start_data = addr; |
1945 | break; | 1994 | break; |
1946 | case PR_SET_MM_END_DATA: | 1995 | case PR_SET_MM_END_DATA: |
1947 | mm->end_data = addr; | 1996 | prctl_map.end_data = addr; |
1997 | break; | ||
1998 | case PR_SET_MM_START_STACK: | ||
1999 | prctl_map.start_stack = addr; | ||
1948 | break; | 2000 | break; |
1949 | |||
1950 | case PR_SET_MM_START_BRK: | 2001 | case PR_SET_MM_START_BRK: |
1951 | if (addr <= mm->end_data) | 2002 | prctl_map.start_brk = addr; |
1952 | goto out; | ||
1953 | |||
1954 | if (check_data_rlimit(rlimit(RLIMIT_DATA), mm->brk, addr, | ||
1955 | mm->end_data, mm->start_data)) | ||
1956 | goto out; | ||
1957 | |||
1958 | mm->start_brk = addr; | ||
1959 | break; | 2003 | break; |
1960 | |||
1961 | case PR_SET_MM_BRK: | 2004 | case PR_SET_MM_BRK: |
1962 | if (addr <= mm->end_data) | 2005 | prctl_map.brk = addr; |
1963 | goto out; | ||
1964 | |||
1965 | if (check_data_rlimit(rlimit(RLIMIT_DATA), addr, mm->start_brk, | ||
1966 | mm->end_data, mm->start_data)) | ||
1967 | goto out; | ||
1968 | |||
1969 | mm->brk = addr; | ||
1970 | break; | 2006 | break; |
2007 | case PR_SET_MM_ARG_START: | ||
2008 | prctl_map.arg_start = addr; | ||
2009 | break; | ||
2010 | case PR_SET_MM_ARG_END: | ||
2011 | prctl_map.arg_end = addr; | ||
2012 | break; | ||
2013 | case PR_SET_MM_ENV_START: | ||
2014 | prctl_map.env_start = addr; | ||
2015 | break; | ||
2016 | case PR_SET_MM_ENV_END: | ||
2017 | prctl_map.env_end = addr; | ||
2018 | break; | ||
2019 | default: | ||
2020 | goto out; | ||
2021 | } | ||
2022 | |||
2023 | error = validate_prctl_map(&prctl_map); | ||
2024 | if (error) | ||
2025 | goto out; | ||
1971 | 2026 | ||
2027 | switch (opt) { | ||
1972 | /* | 2028 | /* |
1973 | * If command line arguments and environment | 2029 | * If command line arguments and environment |
1974 | * are placed somewhere else on stack, we can | 2030 | * are placed somewhere else on stack, we can |
@@ -1985,52 +2041,20 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
1985 | error = -EFAULT; | 2041 | error = -EFAULT; |
1986 | goto out; | 2042 | goto out; |
1987 | } | 2043 | } |
1988 | if (opt == PR_SET_MM_START_STACK) | ||
1989 | mm->start_stack = addr; | ||
1990 | else if (opt == PR_SET_MM_ARG_START) | ||
1991 | mm->arg_start = addr; | ||
1992 | else if (opt == PR_SET_MM_ARG_END) | ||
1993 | mm->arg_end = addr; | ||
1994 | else if (opt == PR_SET_MM_ENV_START) | ||
1995 | mm->env_start = addr; | ||
1996 | else if (opt == PR_SET_MM_ENV_END) | ||
1997 | mm->env_end = addr; | ||
1998 | break; | ||
1999 | |||
2000 | /* | ||
2001 | * This doesn't move auxiliary vector itself | ||
2002 | * since it's pinned to mm_struct, but allow | ||
2003 | * to fill vector with new values. It's up | ||
2004 | * to a caller to provide sane values here | ||
2005 | * otherwise user space tools which use this | ||
2006 | * vector might be unhappy. | ||
2007 | */ | ||
2008 | case PR_SET_MM_AUXV: { | ||
2009 | unsigned long user_auxv[AT_VECTOR_SIZE]; | ||
2010 | |||
2011 | if (arg4 > sizeof(user_auxv)) | ||
2012 | goto out; | ||
2013 | up_read(&mm->mmap_sem); | ||
2014 | |||
2015 | if (copy_from_user(user_auxv, (const void __user *)addr, arg4)) | ||
2016 | return -EFAULT; | ||
2017 | |||
2018 | /* Make sure the last entry is always AT_NULL */ | ||
2019 | user_auxv[AT_VECTOR_SIZE - 2] = 0; | ||
2020 | user_auxv[AT_VECTOR_SIZE - 1] = 0; | ||
2021 | |||
2022 | BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); | ||
2023 | |||
2024 | task_lock(current); | ||
2025 | memcpy(mm->saved_auxv, user_auxv, arg4); | ||
2026 | task_unlock(current); | ||
2027 | |||
2028 | return 0; | ||
2029 | } | ||
2030 | default: | ||
2031 | goto out; | ||
2032 | } | 2044 | } |
2033 | 2045 | ||
2046 | mm->start_code = prctl_map.start_code; | ||
2047 | mm->end_code = prctl_map.end_code; | ||
2048 | mm->start_data = prctl_map.start_data; | ||
2049 | mm->end_data = prctl_map.end_data; | ||
2050 | mm->start_brk = prctl_map.start_brk; | ||
2051 | mm->brk = prctl_map.brk; | ||
2052 | mm->start_stack = prctl_map.start_stack; | ||
2053 | mm->arg_start = prctl_map.arg_start; | ||
2054 | mm->arg_end = prctl_map.arg_end; | ||
2055 | mm->env_start = prctl_map.env_start; | ||
2056 | mm->env_end = prctl_map.env_end; | ||
2057 | |||
2034 | error = 0; | 2058 | error = 0; |
2035 | out: | 2059 | out: |
2036 | up_read(&mm->mmap_sem); | 2060 | up_read(&mm->mmap_sem); |