diff options
| -rw-r--r-- | fs/proc/base.c | 72 | ||||
| -rw-r--r-- | include/linux/prctl.h | 4 | ||||
| -rw-r--r-- | include/linux/seccomp.h | 15 | ||||
| -rw-r--r-- | kernel/seccomp.c | 26 | ||||
| -rw-r--r-- | kernel/sys.c | 8 |
5 files changed, 51 insertions, 74 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index d0921944e68..ae3627337a9 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -67,7 +67,6 @@ | |||
| 67 | #include <linux/mount.h> | 67 | #include <linux/mount.h> |
| 68 | #include <linux/security.h> | 68 | #include <linux/security.h> |
| 69 | #include <linux/ptrace.h> | 69 | #include <linux/ptrace.h> |
| 70 | #include <linux/seccomp.h> | ||
| 71 | #include <linux/cpuset.h> | 70 | #include <linux/cpuset.h> |
| 72 | #include <linux/audit.h> | 71 | #include <linux/audit.h> |
| 73 | #include <linux/poll.h> | 72 | #include <linux/poll.h> |
| @@ -817,71 +816,6 @@ static const struct file_operations proc_loginuid_operations = { | |||
| 817 | }; | 816 | }; |
| 818 | #endif | 817 | #endif |
| 819 | 818 | ||
| 820 | #ifdef CONFIG_SECCOMP | ||
| 821 | static ssize_t seccomp_read(struct file *file, char __user *buf, | ||
| 822 | size_t count, loff_t *ppos) | ||
| 823 | { | ||
| 824 | struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); | ||
| 825 | char __buf[20]; | ||
| 826 | size_t len; | ||
| 827 | |||
| 828 | if (!tsk) | ||
| 829 | return -ESRCH; | ||
| 830 | /* no need to print the trailing zero, so use only len */ | ||
| 831 | len = sprintf(__buf, "%u\n", tsk->seccomp.mode); | ||
| 832 | put_task_struct(tsk); | ||
| 833 | |||
| 834 | return simple_read_from_buffer(buf, count, ppos, __buf, len); | ||
| 835 | } | ||
| 836 | |||
| 837 | static ssize_t seccomp_write(struct file *file, const char __user *buf, | ||
| 838 | size_t count, loff_t *ppos) | ||
| 839 | { | ||
| 840 | struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); | ||
| 841 | char __buf[20], *end; | ||
| 842 | unsigned int seccomp_mode; | ||
| 843 | ssize_t result; | ||
| 844 | |||
| 845 | result = -ESRCH; | ||
| 846 | if (!tsk) | ||
| 847 | goto out_no_task; | ||
| 848 | |||
| 849 | /* can set it only once to be even more secure */ | ||
| 850 | result = -EPERM; | ||
| 851 | if (unlikely(tsk->seccomp.mode)) | ||
| 852 | goto out; | ||
| 853 | |||
| 854 | result = -EFAULT; | ||
| 855 | memset(__buf, 0, sizeof(__buf)); | ||
| 856 | count = min(count, sizeof(__buf) - 1); | ||
| 857 | if (copy_from_user(__buf, buf, count)) | ||
| 858 | goto out; | ||
| 859 | |||
| 860 | seccomp_mode = simple_strtoul(__buf, &end, 0); | ||
| 861 | if (*end == '\n') | ||
| 862 | end++; | ||
| 863 | result = -EINVAL; | ||
| 864 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { | ||
| 865 | tsk->seccomp.mode = seccomp_mode; | ||
| 866 | set_tsk_thread_flag(tsk, TIF_SECCOMP); | ||
| 867 | } else | ||
| 868 | goto out; | ||
| 869 | result = -EIO; | ||
| 870 | if (unlikely(!(end - __buf))) | ||
| 871 | goto out; | ||
| 872 | result = end - __buf; | ||
| 873 | out: | ||
| 874 | put_task_struct(tsk); | ||
| 875 | out_no_task: | ||
| 876 | return result; | ||
| 877 | } | ||
| 878 | |||
| 879 | static const struct file_operations proc_seccomp_operations = { | ||
| 880 | .read = seccomp_read, | ||
| 881 | .write = seccomp_write, | ||
| 882 | }; | ||
| 883 | #endif /* CONFIG_SECCOMP */ | ||
| 884 | |||
| 885 | #ifdef CONFIG_FAULT_INJECTION | 819 | #ifdef CONFIG_FAULT_INJECTION |
| 886 | static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, | 820 | static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, |
| 887 | size_t count, loff_t *ppos) | 821 | size_t count, loff_t *ppos) |
| @@ -2042,9 +1976,6 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2042 | REG("numa_maps", S_IRUGO, numa_maps), | 1976 | REG("numa_maps", S_IRUGO, numa_maps), |
| 2043 | #endif | 1977 | #endif |
| 2044 | REG("mem", S_IRUSR|S_IWUSR, mem), | 1978 | REG("mem", S_IRUSR|S_IWUSR, mem), |
| 2045 | #ifdef CONFIG_SECCOMP | ||
| 2046 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
| 2047 | #endif | ||
| 2048 | LNK("cwd", cwd), | 1979 | LNK("cwd", cwd), |
| 2049 | LNK("root", root), | 1980 | LNK("root", root), |
| 2050 | LNK("exe", exe), | 1981 | LNK("exe", exe), |
| @@ -2329,9 +2260,6 @@ static const struct pid_entry tid_base_stuff[] = { | |||
| 2329 | REG("numa_maps", S_IRUGO, numa_maps), | 2260 | REG("numa_maps", S_IRUGO, numa_maps), |
| 2330 | #endif | 2261 | #endif |
| 2331 | REG("mem", S_IRUSR|S_IWUSR, mem), | 2262 | REG("mem", S_IRUSR|S_IWUSR, mem), |
| 2332 | #ifdef CONFIG_SECCOMP | ||
| 2333 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
| 2334 | #endif | ||
| 2335 | LNK("cwd", cwd), | 2263 | LNK("cwd", cwd), |
| 2336 | LNK("root", root), | 2264 | LNK("root", root), |
| 2337 | LNK("exe", exe), | 2265 | LNK("exe", exe), |
diff --git a/include/linux/prctl.h b/include/linux/prctl.h index 52a9be41250..e2eff9079fe 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h | |||
| @@ -59,4 +59,8 @@ | |||
| 59 | # define PR_ENDIAN_LITTLE 1 /* True little endian mode */ | 59 | # define PR_ENDIAN_LITTLE 1 /* True little endian mode */ |
| 60 | # define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ | 60 | # define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ |
| 61 | 61 | ||
| 62 | /* Get/set process seccomp mode */ | ||
| 63 | #define PR_GET_SECCOMP 21 | ||
| 64 | #define PR_SET_SECCOMP 22 | ||
| 65 | |||
| 62 | #endif /* _LINUX_PRCTL_H */ | 66 | #endif /* _LINUX_PRCTL_H */ |
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 3e8b1cf5430..d708974dbfe 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #ifdef CONFIG_SECCOMP | 5 | #ifdef CONFIG_SECCOMP |
| 6 | 6 | ||
| 7 | #define NR_SECCOMP_MODES 1 | ||
| 8 | |||
| 9 | #include <linux/thread_info.h> | 7 | #include <linux/thread_info.h> |
| 10 | #include <asm/seccomp.h> | 8 | #include <asm/seccomp.h> |
| 11 | 9 | ||
| @@ -23,6 +21,9 @@ static inline int has_secure_computing(struct thread_info *ti) | |||
| 23 | return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP)); | 21 | return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP)); |
| 24 | } | 22 | } |
| 25 | 23 | ||
| 24 | extern long prctl_get_seccomp(void); | ||
| 25 | extern long prctl_set_seccomp(unsigned long); | ||
| 26 | |||
| 26 | #else /* CONFIG_SECCOMP */ | 27 | #else /* CONFIG_SECCOMP */ |
| 27 | 28 | ||
| 28 | typedef struct { } seccomp_t; | 29 | typedef struct { } seccomp_t; |
| @@ -34,6 +35,16 @@ static inline int has_secure_computing(struct thread_info *ti) | |||
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | static inline long prctl_get_seccomp(void) | ||
| 39 | { | ||
| 40 | return -EINVAL; | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline long prctl_set_seccomp(unsigned long arg2) | ||
| 44 | { | ||
| 45 | return -EINVAL; | ||
| 46 | } | ||
| 47 | |||
| 37 | #endif /* CONFIG_SECCOMP */ | 48 | #endif /* CONFIG_SECCOMP */ |
| 38 | 49 | ||
| 39 | #endif /* _LINUX_SECCOMP_H */ | 50 | #endif /* _LINUX_SECCOMP_H */ |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index c3391b6020e..1dfa8a50972 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
| 11 | 11 | ||
| 12 | /* #define SECCOMP_DEBUG 1 */ | 12 | /* #define SECCOMP_DEBUG 1 */ |
| 13 | #define NR_SECCOMP_MODES 1 | ||
| 13 | 14 | ||
| 14 | /* | 15 | /* |
| 15 | * Secure computing mode 1 allows only read/write/exit/sigreturn. | 16 | * Secure computing mode 1 allows only read/write/exit/sigreturn. |
| @@ -54,3 +55,28 @@ void __secure_computing(int this_syscall) | |||
| 54 | #endif | 55 | #endif |
| 55 | do_exit(SIGKILL); | 56 | do_exit(SIGKILL); |
| 56 | } | 57 | } |
| 58 | |||
| 59 | long prctl_get_seccomp(void) | ||
| 60 | { | ||
| 61 | return current->seccomp.mode; | ||
| 62 | } | ||
| 63 | |||
| 64 | long prctl_set_seccomp(unsigned long seccomp_mode) | ||
| 65 | { | ||
| 66 | long ret; | ||
| 67 | |||
| 68 | /* can set it only once to be even more secure */ | ||
| 69 | ret = -EPERM; | ||
| 70 | if (unlikely(current->seccomp.mode)) | ||
| 71 | goto out; | ||
| 72 | |||
| 73 | ret = -EINVAL; | ||
| 74 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { | ||
| 75 | current->seccomp.mode = seccomp_mode; | ||
| 76 | set_thread_flag(TIF_SECCOMP); | ||
| 77 | ret = 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | out: | ||
| 81 | return ret; | ||
| 82 | } | ||
diff --git a/kernel/sys.c b/kernel/sys.c index ed92e2f0334..4d141ae3e80 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/cn_proc.h> | 31 | #include <linux/cn_proc.h> |
| 32 | #include <linux/getcpu.h> | 32 | #include <linux/getcpu.h> |
| 33 | #include <linux/task_io_accounting_ops.h> | 33 | #include <linux/task_io_accounting_ops.h> |
| 34 | #include <linux/seccomp.h> | ||
| 34 | 35 | ||
| 35 | #include <linux/compat.h> | 36 | #include <linux/compat.h> |
| 36 | #include <linux/syscalls.h> | 37 | #include <linux/syscalls.h> |
| @@ -2242,6 +2243,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 2242 | error = SET_ENDIAN(current, arg2); | 2243 | error = SET_ENDIAN(current, arg2); |
| 2243 | break; | 2244 | break; |
| 2244 | 2245 | ||
| 2246 | case PR_GET_SECCOMP: | ||
| 2247 | error = prctl_get_seccomp(); | ||
| 2248 | break; | ||
| 2249 | case PR_SET_SECCOMP: | ||
| 2250 | error = prctl_set_seccomp(arg2); | ||
| 2251 | break; | ||
| 2252 | |||
| 2245 | default: | 2253 | default: |
| 2246 | error = -EINVAL; | 2254 | error = -EINVAL; |
| 2247 | break; | 2255 | break; |
