diff options
author | Nicolas Schichan <nschichan@freebox.fr> | 2015-05-06 10:12:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-09 17:35:05 -0400 |
commit | d9e12f42e58da475379b9080708b94f2095904af (patch) | |
tree | 91f92e7c45d77d993b39751df26989d53fe5698f /kernel/seccomp.c | |
parent | 4ae92bc77ac8e620f7c8d59b5882a4cb0d1c4ef1 (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>
Diffstat (limited to 'kernel/seccomp.c')
-rw-r--r-- | kernel/seccomp.c | 68 |
1 files changed, 22 insertions, 46 deletions
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) | |||
347 | static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) | 347 | static 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 | |||
418 | free_filter_prog: | ||
419 | __bpf_prog_free(filter->prog); | ||
420 | free_filter: | ||
421 | kfree(filter); | ||
422 | free_prog: | ||
423 | kfree(fp); | ||
424 | return ERR_PTR(ret); | ||
425 | } | 401 | } |
426 | 402 | ||
427 | /** | 403 | /** |