aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Schichan <nschichan@freebox.fr>2015-05-06 10:12:28 -0400
committerDavid S. Miller <davem@davemloft.net>2015-05-09 17:35:05 -0400
commitd9e12f42e58da475379b9080708b94f2095904af (patch)
tree91f92e7c45d77d993b39751df26989d53fe5698f
parent4ae92bc77ac8e620f7c8d59b5882a4cb0d1c4ef1 (diff)
seccomp: simplify seccomp_prepare_filter and reuse bpf_prepare_filter
Remove the calls to bpf_check_classic(), bpf_convert_filter() and bpf_migrate_runtime() and let bpf_prepare_filter() take care of that instead. seccomp_check_filter() is passed to bpf_prepare_filter() so that it gets called from there, after bpf_check_classic(). We can now remove exposure of two internal classic BPF functions previously used by seccomp. The export of bpf_check_classic() symbol, previously known as sk_chk_filter(), was there since pre git times, and no in-tree module was using it, therefore remove it. Joint work with Daniel Borkmann. Signed-off-by: Nicolas Schichan <nschichan@freebox.fr> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> 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>
-rw-r--r--include/linux/filter.h4
-rw-r--r--kernel/seccomp.c68
-rw-r--r--net/core/filter.c8
3 files changed, 26 insertions, 54 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 91996247cb55..0dcb44bcfc5f 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -363,9 +363,6 @@ int sk_filter(struct sock *sk, struct sk_buff *skb);
363void bpf_prog_select_runtime(struct bpf_prog *fp); 363void bpf_prog_select_runtime(struct bpf_prog *fp);
364void bpf_prog_free(struct bpf_prog *fp); 364void bpf_prog_free(struct bpf_prog *fp);
365 365
366int bpf_convert_filter(struct sock_filter *prog, int len,
367 struct bpf_insn *new_prog, int *new_len);
368
369struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags); 366struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags);
370struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, 367struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
371 gfp_t gfp_extra_flags); 368 gfp_t gfp_extra_flags);
@@ -387,7 +384,6 @@ int sk_detach_filter(struct sock *sk);
387typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter, 384typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter,
388 unsigned int flen); 385 unsigned int flen);
389 386
390int bpf_check_classic(const struct sock_filter *filter, unsigned int flen);
391struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, 387struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp,
392 bpf_aux_classic_check_t trans); 388 bpf_aux_classic_check_t trans);
393 389
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 4f44028943e6..93d40f7f3683 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -347,15 +347,14 @@ static inline void seccomp_sync_threads(void)
347static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) 347static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
348{ 348{
349 struct seccomp_filter *filter; 349 struct seccomp_filter *filter;
350 unsigned long fp_size; 350 struct bpf_prog *prog;
351 struct sock_filter *fp; 351 unsigned long fsize;
352 int new_len;
353 long ret;
354 352
355 if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) 353 if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
356 return ERR_PTR(-EINVAL); 354 return ERR_PTR(-EINVAL);
355
357 BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter)); 356 BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
358 fp_size = fprog->len * sizeof(struct sock_filter); 357 fsize = bpf_classic_proglen(fprog);
359 358
360 /* 359 /*
361 * Installing a seccomp filter requires that the task has 360 * Installing a seccomp filter requires that the task has
@@ -368,60 +367,37 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
368 CAP_SYS_ADMIN) != 0) 367 CAP_SYS_ADMIN) != 0)
369 return ERR_PTR(-EACCES); 368 return ERR_PTR(-EACCES);
370 369
371 fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); 370 prog = bpf_prog_alloc(bpf_prog_size(fprog->len), 0);
372 if (!fp) 371 if (!prog)
373 return ERR_PTR(-ENOMEM); 372 return ERR_PTR(-ENOMEM);
374 373
375 /* Copy the instructions from fprog. */ 374 /* Copy the instructions from fprog. */
376 ret = -EFAULT; 375 if (copy_from_user(prog->insns, fprog->filter, fsize)) {
377 if (copy_from_user(fp, fprog->filter, fp_size)) 376 __bpf_prog_free(prog);
378 goto free_prog; 377 return ERR_PTR(-EFAULT);
379 378 }
380 /* Check and rewrite the fprog via the skb checker */
381 ret = bpf_check_classic(fp, fprog->len);
382 if (ret)
383 goto free_prog;
384 379
385 /* Check and rewrite the fprog for seccomp use */ 380 prog->len = fprog->len;
386 ret = seccomp_check_filter(fp, fprog->len);
387 if (ret)
388 goto free_prog;
389 381
390 /* Convert 'sock_filter' insns to 'bpf_insn' insns */ 382 /* bpf_prepare_filter() already takes care of freeing
391 ret = bpf_convert_filter(fp, fprog->len, NULL, &new_len); 383 * memory in case something goes wrong.
392 if (ret) 384 */
393 goto free_prog; 385 prog = bpf_prepare_filter(prog, seccomp_check_filter);
386 if (IS_ERR(prog))
387 return ERR_CAST(prog);
394 388
395 /* Allocate a new seccomp_filter */ 389 /* Allocate a new seccomp_filter */
396 ret = -ENOMEM;
397 filter = kzalloc(sizeof(struct seccomp_filter), 390 filter = kzalloc(sizeof(struct seccomp_filter),
398 GFP_KERNEL|__GFP_NOWARN); 391 GFP_KERNEL|__GFP_NOWARN);
399 if (!filter) 392 if (!filter) {
400 goto free_prog; 393 bpf_prog_destroy(prog);
401 394 return ERR_PTR(-ENOMEM);
402 filter->prog = bpf_prog_alloc(bpf_prog_size(new_len), __GFP_NOWARN); 395 }
403 if (!filter->prog)
404 goto free_filter;
405
406 ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len);
407 if (ret)
408 goto free_filter_prog;
409 396
410 kfree(fp); 397 filter->prog = prog;
411 atomic_set(&filter->usage, 1); 398 atomic_set(&filter->usage, 1);
412 filter->prog->len = new_len;
413
414 bpf_prog_select_runtime(filter->prog);
415 399
416 return filter; 400 return filter;
417
418free_filter_prog:
419 __bpf_prog_free(filter->prog);
420free_filter:
421 kfree(filter);
422free_prog:
423 kfree(fp);
424 return ERR_PTR(ret);
425} 401}
426 402
427/** 403/**
diff --git a/net/core/filter.c b/net/core/filter.c
index e670494f1d83..f887084740cd 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -355,8 +355,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
355 * for socket filters: ctx == 'struct sk_buff *', for seccomp: 355 * for socket filters: ctx == 'struct sk_buff *', for seccomp:
356 * ctx == 'struct seccomp_data *'. 356 * ctx == 'struct seccomp_data *'.
357 */ 357 */
358int bpf_convert_filter(struct sock_filter *prog, int len, 358static int bpf_convert_filter(struct sock_filter *prog, int len,
359 struct bpf_insn *new_prog, int *new_len) 359 struct bpf_insn *new_prog, int *new_len)
360{ 360{
361 int new_flen = 0, pass = 0, target, i; 361 int new_flen = 0, pass = 0, target, i;
362 struct bpf_insn *new_insn; 362 struct bpf_insn *new_insn;
@@ -751,7 +751,8 @@ static bool chk_code_allowed(u16 code_to_probe)
751 * 751 *
752 * Returns 0 if the rule set is legal or -EINVAL if not. 752 * Returns 0 if the rule set is legal or -EINVAL if not.
753 */ 753 */
754int bpf_check_classic(const struct sock_filter *filter, unsigned int flen) 754static int bpf_check_classic(const struct sock_filter *filter,
755 unsigned int flen)
755{ 756{
756 bool anc_found; 757 bool anc_found;
757 int pc; 758 int pc;
@@ -825,7 +826,6 @@ int bpf_check_classic(const struct sock_filter *filter, unsigned int flen)
825 826
826 return -EINVAL; 827 return -EINVAL;
827} 828}
828EXPORT_SYMBOL(bpf_check_classic);
829 829
830static int bpf_prog_store_orig_filter(struct bpf_prog *fp, 830static int bpf_prog_store_orig_filter(struct bpf_prog *fp,
831 const struct sock_fprog *fprog) 831 const struct sock_fprog *fprog)