Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(575)

Unified Diff: sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc

Issue 278583005: Linux Sandbox: Add support for SECCOMP_RET_TRACE. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Test change Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
index 3b7470b4176ac10e32ea650823061b3e63c4e431..e7e6448853f3366a0991c555fa5824e37c60d6d1 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
@@ -5,7 +5,9 @@
#include <errno.h>
#include <pthread.h>
#include <sched.h>
+#include <signal.h>
#include <sys/prctl.h>
+#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -23,6 +25,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
#include "sandbox/linux/seccomp-bpf/syscall.h"
@@ -1806,6 +1809,121 @@ BPF_TEST(SandboxBPF, PthreadEquality, PthreadPolicyEquality) { PthreadTest(); }
BPF_TEST(SandboxBPF, PthreadBitMask, PthreadPolicyBitMask) { PthreadTest(); }
+// It is possible that libc does not define these, but the kernel supports this.
+// We define them here anyway. The test will give up silently if it gets an
+// EINVAL as a result of these not being supported.
+#ifndef PTRACE_O_TRACESECCOMP
+#define PTRACE_O_TRACESECCOMP 0x00000080
+#endif
+#ifndef PTRACE_EVENT_SECCOMP
+#define PTRACE_EVENT_SECCOMP 8
+#endif
+
+const uint16_t kTraceData = 0xcc;
+
+class TraceAllPolicy : public SandboxBPFPolicy {
+ public:
+ TraceAllPolicy() {}
+ virtual ~TraceAllPolicy() {}
+
+ virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
+ int system_call_number) const OVERRIDE {
+ if (!SandboxBPF::IsValidSyscallNumber(system_call_number)) {
jln (very slow on Chromium) 2014/05/20 03:02:10 This if is not needed anymore (due to a recent CL)
rickyz (Google) 2014/05/20 22:34:01 Done.
+ return ErrorCode(ENOSYS);
+ }
+ return ErrorCode(ErrorCode::ERR_TRACE + kTraceData);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TraceAllPolicy);
+};
+
+SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) {
+ if (SandboxBPF::SupportsSeccompSandbox(-1) !=
+ sandbox::SandboxBPF::STATUS_AVAILABLE) {
+ return;
+ }
+
+ pid_t pid = fork();
+ BPF_ASSERT(pid != -1);
jln (very slow on Chromium) 2014/05/20 03:02:10 BPF_ASSERT_NE()
rickyz (Google) 2014/05/20 22:34:01 Done.
+ if (pid == 0) {
+ pid_t my_pid = getpid();
+ BPF_ASSERT(ptrace(PTRACE_TRACEME, -1, NULL, NULL) != -1);
+ BPF_ASSERT(raise(SIGSTOP) == 0);
jln (very slow on Chromium) 2014/05/20 03:02:10 BPF_ASSERT_EQ() (etc. for the rest of the test).
rickyz (Google) 2014/05/20 22:34:01 Done.
+ SandboxBPF sandbox;
+ sandbox.SetSandboxPolicy(new TraceAllPolicy);
+ BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED));
+
+ // getpid is allowed.
+ BPF_ASSERT(syscall(__NR_getpid) == my_pid);
+
+ // write is skipped and returns a fake value.
+ BPF_ASSERT(write(STDERR_FILENO, "A", 1) == kExpectedReturnValue);
+
+ // kill is rewritten to exit(kExpectedReturnValue).
+ syscall(__NR_kill, my_pid, SIGKILL);
+
+ // Should not be reached.
+ BPF_ASSERT(0);
jln (very slow on Chromium) 2014/05/20 03:02:10 s/0/false/
rickyz (Google) 2014/05/20 22:34:01 Done.
+ }
+
+ int status;
+ BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, WUNTRACED)) != -1);
+ BPF_ASSERT(WIFSTOPPED(status));
+
+ errno = 0;
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESECCOMP) == -1) {
+ // Give up (but don't fail) if PTRACE_O_TRACESECCOMP is not supported.
jln (very slow on Chromium) 2014/05/20 03:02:10 It should now be supported anywhere seccomp-bpf is
rickyz (Google) 2014/05/20 22:34:01 Yeah, I don't see any release with seccomp-bpf and
+ BPF_ASSERT(errno == EINVAL);
+ BPF_ASSERT(ptrace(PTRACE_CONT, pid, NULL, SIGKILL) != -1);
+ return;
+ }
+
+ BPF_ASSERT(ptrace(PTRACE_CONT, pid, NULL, NULL) != -1);
+ while (true) {
+ BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, 0)) != -1);
+ if (WIFEXITED(status) || WIFSIGNALED(status)) {
+ BPF_ASSERT(WIFEXITED(status) &&
+ WEXITSTATUS(status) == kExpectedReturnValue);
+ break;
+ }
+
+ if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
+ (status >> 16) != PTRACE_EVENT_SECCOMP) {
+ BPF_ASSERT(ptrace(PTRACE_CONT, pid, NULL, NULL) != -1);
+ continue;
+ }
+
+ unsigned long data;
+ BPF_ASSERT(ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data) != -1);
+ BPF_ASSERT(data == kTraceData);
+
+ struct pt_regs regs;
+ BPF_ASSERT(ptrace(PTRACE_GETREGS, pid, NULL, &regs) != -1);
+ switch (SECCOMP_PT_SYSCALL(regs)) {
+ case __NR_write:
+ // Skip write, make it return kExpectedReturnValue.
+ SECCOMP_PT_SYSCALL(regs) = -1;
+ SECCOMP_PT_RESULT(regs) = kExpectedReturnValue;
+ BPF_ASSERT(ptrace(PTRACE_SETREGS, pid, NULL, &regs) != -1);
+ break;
+
+ case __NR_kill:
+ // Rewrite to exit(kExpectedReturnValue).
+ SECCOMP_PT_SYSCALL(regs) = __NR_exit;
+ SECCOMP_PT_PARM1(regs) = kExpectedReturnValue;
+ BPF_ASSERT(ptrace(PTRACE_SETREGS, pid, NULL, &regs) != -1);
+ break;
+
+ default:
+ // Allow all other syscalls.
+ break;
+ }
+
+ BPF_ASSERT(ptrace(PTRACE_CONT, pid, NULL, NULL) != -1);
+ }
+}
+
} // namespace
} // namespace sandbox

Powered by Google App Engine
This is Rietveld 408576698