diff options
author | Kees Cook <keescook@chromium.org> | 2016-06-01 22:29:15 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2016-06-14 13:54:41 -0400 |
commit | ce6526e8afa4b6ad0ab134a4cc50c9c863319637 (patch) | |
tree | c3074e4661ee9432faf518fd2eef8527c5811730 /kernel | |
parent | 8112c4f140fa03f9ee68aad2cc79afa7df5418d3 (diff) |
seccomp: recheck the syscall after RET_TRACE
When RET_TRACE triggers, a tracer may change a syscall into something that
should be filtered by seccomp. This re-runs seccomp after a trace event
to make sure things continue to pass.
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/seccomp.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 14a37d71b612..54d15eb2b701 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -556,7 +556,8 @@ void secure_computing_strict(int this_syscall) | |||
556 | #else | 556 | #else |
557 | 557 | ||
558 | #ifdef CONFIG_SECCOMP_FILTER | 558 | #ifdef CONFIG_SECCOMP_FILTER |
559 | static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) | 559 | static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, |
560 | const bool recheck_after_trace) | ||
560 | { | 561 | { |
561 | u32 filter_ret, action; | 562 | u32 filter_ret, action; |
562 | int data; | 563 | int data; |
@@ -588,6 +589,10 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) | |||
588 | goto skip; | 589 | goto skip; |
589 | 590 | ||
590 | case SECCOMP_RET_TRACE: | 591 | case SECCOMP_RET_TRACE: |
592 | /* We've been put in this state by the ptracer already. */ | ||
593 | if (recheck_after_trace) | ||
594 | return 0; | ||
595 | |||
591 | /* ENOSYS these calls if there is no tracer attached. */ | 596 | /* ENOSYS these calls if there is no tracer attached. */ |
592 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { | 597 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { |
593 | syscall_set_return_value(current, | 598 | syscall_set_return_value(current, |
@@ -611,6 +616,15 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) | |||
611 | if (this_syscall < 0) | 616 | if (this_syscall < 0) |
612 | goto skip; | 617 | goto skip; |
613 | 618 | ||
619 | /* | ||
620 | * Recheck the syscall, since it may have changed. This | ||
621 | * intentionally uses a NULL struct seccomp_data to force | ||
622 | * a reload of all registers. This does not goto skip since | ||
623 | * a skip would have already been reported. | ||
624 | */ | ||
625 | if (__seccomp_filter(this_syscall, NULL, true)) | ||
626 | return -1; | ||
627 | |||
614 | return 0; | 628 | return 0; |
615 | 629 | ||
616 | case SECCOMP_RET_ALLOW: | 630 | case SECCOMP_RET_ALLOW: |
@@ -629,7 +643,8 @@ skip: | |||
629 | return -1; | 643 | return -1; |
630 | } | 644 | } |
631 | #else | 645 | #else |
632 | static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) | 646 | static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, |
647 | const bool recheck_after_trace) | ||
633 | { | 648 | { |
634 | BUG(); | 649 | BUG(); |
635 | } | 650 | } |
@@ -652,7 +667,7 @@ int __secure_computing(const struct seccomp_data *sd) | |||
652 | __secure_computing_strict(this_syscall); /* may call do_exit */ | 667 | __secure_computing_strict(this_syscall); /* may call do_exit */ |
653 | return 0; | 668 | return 0; |
654 | case SECCOMP_MODE_FILTER: | 669 | case SECCOMP_MODE_FILTER: |
655 | return __seccomp_filter(this_syscall, sd); | 670 | return __seccomp_filter(this_syscall, sd, false); |
656 | default: | 671 | default: |
657 | BUG(); | 672 | BUG(); |
658 | } | 673 | } |