move seccomp from /proc to a prctl
This reduces the memory footprint and it enforces that only the current task can enable seccomp on itself (this is a requirement for a strightforward [modulo preempt ;) ] TIF_NOTSC implementation). Signed-off-by: Andrea Arcangeli <andrea@cpushare.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
be0ef957c9
commit
1d9d02feee
5 changed files with 51 additions and 74 deletions
|
@ -67,7 +67,6 @@
|
||||||
#include <linux/mount.h>
|
#include <linux/mount.h>
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
#include <linux/seccomp.h>
|
|
||||||
#include <linux/cpuset.h>
|
#include <linux/cpuset.h>
|
||||||
#include <linux/audit.h>
|
#include <linux/audit.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
|
@ -817,71 +816,6 @@ static const struct file_operations proc_loginuid_operations = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECCOMP
|
|
||||||
static ssize_t seccomp_read(struct file *file, char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
|
|
||||||
char __buf[20];
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (!tsk)
|
|
||||||
return -ESRCH;
|
|
||||||
/* no need to print the trailing zero, so use only len */
|
|
||||||
len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
|
|
||||||
put_task_struct(tsk);
|
|
||||||
|
|
||||||
return simple_read_from_buffer(buf, count, ppos, __buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t seccomp_write(struct file *file, const char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
|
|
||||||
char __buf[20], *end;
|
|
||||||
unsigned int seccomp_mode;
|
|
||||||
ssize_t result;
|
|
||||||
|
|
||||||
result = -ESRCH;
|
|
||||||
if (!tsk)
|
|
||||||
goto out_no_task;
|
|
||||||
|
|
||||||
/* can set it only once to be even more secure */
|
|
||||||
result = -EPERM;
|
|
||||||
if (unlikely(tsk->seccomp.mode))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
result = -EFAULT;
|
|
||||||
memset(__buf, 0, sizeof(__buf));
|
|
||||||
count = min(count, sizeof(__buf) - 1);
|
|
||||||
if (copy_from_user(__buf, buf, count))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
seccomp_mode = simple_strtoul(__buf, &end, 0);
|
|
||||||
if (*end == '\n')
|
|
||||||
end++;
|
|
||||||
result = -EINVAL;
|
|
||||||
if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
|
|
||||||
tsk->seccomp.mode = seccomp_mode;
|
|
||||||
set_tsk_thread_flag(tsk, TIF_SECCOMP);
|
|
||||||
} else
|
|
||||||
goto out;
|
|
||||||
result = -EIO;
|
|
||||||
if (unlikely(!(end - __buf)))
|
|
||||||
goto out;
|
|
||||||
result = end - __buf;
|
|
||||||
out:
|
|
||||||
put_task_struct(tsk);
|
|
||||||
out_no_task:
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations proc_seccomp_operations = {
|
|
||||||
.read = seccomp_read,
|
|
||||||
.write = seccomp_write,
|
|
||||||
};
|
|
||||||
#endif /* CONFIG_SECCOMP */
|
|
||||||
|
|
||||||
#ifdef CONFIG_FAULT_INJECTION
|
#ifdef CONFIG_FAULT_INJECTION
|
||||||
static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
|
static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
|
@ -2042,9 +1976,6 @@ static const struct pid_entry tgid_base_stuff[] = {
|
||||||
REG("numa_maps", S_IRUGO, numa_maps),
|
REG("numa_maps", S_IRUGO, numa_maps),
|
||||||
#endif
|
#endif
|
||||||
REG("mem", S_IRUSR|S_IWUSR, mem),
|
REG("mem", S_IRUSR|S_IWUSR, mem),
|
||||||
#ifdef CONFIG_SECCOMP
|
|
||||||
REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
|
|
||||||
#endif
|
|
||||||
LNK("cwd", cwd),
|
LNK("cwd", cwd),
|
||||||
LNK("root", root),
|
LNK("root", root),
|
||||||
LNK("exe", exe),
|
LNK("exe", exe),
|
||||||
|
@ -2329,9 +2260,6 @@ static const struct pid_entry tid_base_stuff[] = {
|
||||||
REG("numa_maps", S_IRUGO, numa_maps),
|
REG("numa_maps", S_IRUGO, numa_maps),
|
||||||
#endif
|
#endif
|
||||||
REG("mem", S_IRUSR|S_IWUSR, mem),
|
REG("mem", S_IRUSR|S_IWUSR, mem),
|
||||||
#ifdef CONFIG_SECCOMP
|
|
||||||
REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
|
|
||||||
#endif
|
|
||||||
LNK("cwd", cwd),
|
LNK("cwd", cwd),
|
||||||
LNK("root", root),
|
LNK("root", root),
|
||||||
LNK("exe", exe),
|
LNK("exe", exe),
|
||||||
|
|
|
@ -59,4 +59,8 @@
|
||||||
# define PR_ENDIAN_LITTLE 1 /* True little endian mode */
|
# define PR_ENDIAN_LITTLE 1 /* True little endian mode */
|
||||||
# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */
|
# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */
|
||||||
|
|
||||||
|
/* Get/set process seccomp mode */
|
||||||
|
#define PR_GET_SECCOMP 21
|
||||||
|
#define PR_SET_SECCOMP 22
|
||||||
|
|
||||||
#endif /* _LINUX_PRCTL_H */
|
#endif /* _LINUX_PRCTL_H */
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
#ifdef CONFIG_SECCOMP
|
#ifdef CONFIG_SECCOMP
|
||||||
|
|
||||||
#define NR_SECCOMP_MODES 1
|
|
||||||
|
|
||||||
#include <linux/thread_info.h>
|
#include <linux/thread_info.h>
|
||||||
#include <asm/seccomp.h>
|
#include <asm/seccomp.h>
|
||||||
|
|
||||||
|
@ -23,6 +21,9 @@ static inline int has_secure_computing(struct thread_info *ti)
|
||||||
return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP));
|
return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern long prctl_get_seccomp(void);
|
||||||
|
extern long prctl_set_seccomp(unsigned long);
|
||||||
|
|
||||||
#else /* CONFIG_SECCOMP */
|
#else /* CONFIG_SECCOMP */
|
||||||
|
|
||||||
typedef struct { } seccomp_t;
|
typedef struct { } seccomp_t;
|
||||||
|
@ -34,6 +35,16 @@ static inline int has_secure_computing(struct thread_info *ti)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline long prctl_get_seccomp(void)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long prctl_set_seccomp(unsigned long arg2)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_SECCOMP */
|
#endif /* CONFIG_SECCOMP */
|
||||||
|
|
||||||
#endif /* _LINUX_SECCOMP_H */
|
#endif /* _LINUX_SECCOMP_H */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
/* #define SECCOMP_DEBUG 1 */
|
/* #define SECCOMP_DEBUG 1 */
|
||||||
|
#define NR_SECCOMP_MODES 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Secure computing mode 1 allows only read/write/exit/sigreturn.
|
* Secure computing mode 1 allows only read/write/exit/sigreturn.
|
||||||
|
@ -54,3 +55,28 @@ void __secure_computing(int this_syscall)
|
||||||
#endif
|
#endif
|
||||||
do_exit(SIGKILL);
|
do_exit(SIGKILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long prctl_get_seccomp(void)
|
||||||
|
{
|
||||||
|
return current->seccomp.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
long prctl_set_seccomp(unsigned long seccomp_mode)
|
||||||
|
{
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
/* can set it only once to be even more secure */
|
||||||
|
ret = -EPERM;
|
||||||
|
if (unlikely(current->seccomp.mode))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = -EINVAL;
|
||||||
|
if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
|
||||||
|
current->seccomp.mode = seccomp_mode;
|
||||||
|
set_thread_flag(TIF_SECCOMP);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/cn_proc.h>
|
#include <linux/cn_proc.h>
|
||||||
#include <linux/getcpu.h>
|
#include <linux/getcpu.h>
|
||||||
#include <linux/task_io_accounting_ops.h>
|
#include <linux/task_io_accounting_ops.h>
|
||||||
|
#include <linux/seccomp.h>
|
||||||
|
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
|
@ -2242,6 +2243,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||||
error = SET_ENDIAN(current, arg2);
|
error = SET_ENDIAN(current, arg2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PR_GET_SECCOMP:
|
||||||
|
error = prctl_get_seccomp();
|
||||||
|
break;
|
||||||
|
case PR_SET_SECCOMP:
|
||||||
|
error = prctl_set_seccomp(arg2);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue