summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2016-06-01 22:29:15 -0400
committerKees Cook <keescook@chromium.org>2016-06-14 13:54:41 -0400
commitce6526e8afa4b6ad0ab134a4cc50c9c863319637 (patch)
treec3074e4661ee9432faf518fd2eef8527c5811730 /kernel
parent8112c4f140fa03f9ee68aad2cc79afa7df5418d3 (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.c21
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
559static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) 559static 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
632static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) 646static 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 }