summaryrefslogtreecommitdiffstats
path: root/kernel/seccomp.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2015-05-06 16:12:30 +0200
committerDavid S. Miller <davem@davemloft.net>2015-05-09 23:35:05 +0200
commitac67eb2c5347bd9976308c0e0cf1d9e7ca690342 (patch)
tree0a4b80cd5adb5f5ce8ed3f74644da7ed029b1f77 /kernel/seccomp.c
parentnet: filter: add __GFP_NOWARN flag for larger kmem allocs (diff)
downloadlinux-ac67eb2c5347bd9976308c0e0cf1d9e7ca690342.tar.xz
linux-ac67eb2c5347bd9976308c0e0cf1d9e7ca690342.zip
seccomp, filter: add and use bpf_prog_create_from_user from seccomp
Seccomp has always been a special candidate when it comes to preparation of its filters in seccomp_prepare_filter(). Due to the extra checks and filter rewrite it partially duplicates code and has BPF internals exposed. This patch adds a generic API inside the BPF code code that seccomp can use and thus keep it's filter preparation code minimal and better maintainable. The other side-effect is that now classic JITs can add seccomp support as well by only providing a BPF_LDX | BPF_W | BPF_ABS translation. Tested with seccomp and BPF test suites. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Cc: Nicolas Schichan <nschichan@freebox.fr> Cc: Alexei Starovoitov <ast@plumgrid.com> Cc: Kees Cook <keescook@chromium.org> Acked-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/seccomp.c')
-rw-r--r--kernel/seccomp.c42
1 files changed, 12 insertions, 30 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 93d40f7f3683..245df6b32b81 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -346,15 +346,13 @@ static inline void seccomp_sync_threads(void)
*/
static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
{
- struct seccomp_filter *filter;
- struct bpf_prog *prog;
- unsigned long fsize;
+ struct seccomp_filter *sfilter;
+ int ret;
if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
return ERR_PTR(-EINVAL);
BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
- fsize = bpf_classic_proglen(fprog);
/*
* Installing a seccomp filter requires that the task has
@@ -367,37 +365,21 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
CAP_SYS_ADMIN) != 0)
return ERR_PTR(-EACCES);
- prog = bpf_prog_alloc(bpf_prog_size(fprog->len), 0);
- if (!prog)
- return ERR_PTR(-ENOMEM);
-
- /* Copy the instructions from fprog. */
- if (copy_from_user(prog->insns, fprog->filter, fsize)) {
- __bpf_prog_free(prog);
- return ERR_PTR(-EFAULT);
- }
-
- prog->len = fprog->len;
-
- /* bpf_prepare_filter() already takes care of freeing
- * memory in case something goes wrong.
- */
- prog = bpf_prepare_filter(prog, seccomp_check_filter);
- if (IS_ERR(prog))
- return ERR_CAST(prog);
-
/* Allocate a new seccomp_filter */
- filter = kzalloc(sizeof(struct seccomp_filter),
- GFP_KERNEL|__GFP_NOWARN);
- if (!filter) {
- bpf_prog_destroy(prog);
+ sfilter = kzalloc(sizeof(*sfilter), GFP_KERNEL | __GFP_NOWARN);
+ if (!sfilter)
return ERR_PTR(-ENOMEM);
+
+ ret = bpf_prog_create_from_user(&sfilter->prog, fprog,
+ seccomp_check_filter);
+ if (ret < 0) {
+ kfree(sfilter);
+ return ERR_PTR(ret);
}
- filter->prog = prog;
- atomic_set(&filter->usage, 1);
+ atomic_set(&sfilter->usage, 1);
- return filter;
+ return sfilter;
}
/**