From b0bc17e45606744cf42e35e069b30315c4c38e4d Mon Sep 17 00:00:00 2001 From: Wiktor Garbacz Date: Fri, 7 Jan 2022 05:25:42 -0800 Subject: [PATCH] Fix Regs::SkipSyscallReturnValue for Aarch64 Add a test. PiperOrigin-RevId: 420271649 Change-Id: Ifc857ec5351a0fc70547c98f57c22cf792d5d9f9 --- sandboxed_api/sandbox2/BUILD.bazel | 16 +++++ sandboxed_api/sandbox2/CMakeLists.txt | 38 ++++++++--- sandboxed_api/sandbox2/regs.cc | 4 +- sandboxed_api/sandbox2/regs_test.cc | 98 +++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 sandboxed_api/sandbox2/regs_test.cc diff --git a/sandboxed_api/sandbox2/BUILD.bazel b/sandboxed_api/sandbox2/BUILD.bazel index 63063ae..072ce02 100644 --- a/sandboxed_api/sandbox2/BUILD.bazel +++ b/sandboxed_api/sandbox2/BUILD.bazel @@ -53,6 +53,22 @@ cc_library( ], ) +cc_test( + name = "regs_test", + srcs = ["regs_test.cc"], + copts = sapi_platform_copts(), + tags = ["no_qemu_user_mode"], + deps = [ + ":regs", + ":sanitizer", + ":util", + "//sandboxed_api/sandbox2/util:bpf_helper", + "//sandboxed_api/util:status_matchers", + "@com_google_glog//:glog", + "@com_google_googletest//:gtest_main", + ], +) + cc_library( name = "syscall", srcs = [ diff --git a/sandboxed_api/sandbox2/CMakeLists.txt b/sandboxed_api/sandbox2/CMakeLists.txt index 639a7b2..2867512 100644 --- a/sandboxed_api/sandbox2/CMakeLists.txt +++ b/sandboxed_api/sandbox2/CMakeLists.txt @@ -35,15 +35,16 @@ add_library(sandbox2_regs ${SAPI_LIB_TYPE} regs.h ) add_library(sandbox2::regs ALIAS sandbox2_regs) -target_link_libraries(sandbox2_regs PRIVATE - absl::core_headers - absl::strings - sapi::config - sapi::strerror - sandbox2::syscall - sandbox2::violation_proto - sapi::base - sapi::status +target_link_libraries(sandbox2_regs + PUBLIC absl::status + sapi::config + sandbox2::syscall + sandbox2::violation_proto + PRIVATE absl::core_headers + absl::strings + sapi::strerror + sapi::base + sapi::status ) # sandboxed_api/sandbox2:syscall @@ -609,6 +610,25 @@ target_link_libraries(sandbox2_violation_proto PRIVATE if(SAPI_ENABLE_TESTS) add_subdirectory(testcases) + # sandboxed_api/sandbox2:regs_test + add_executable(sandbox2_regs_test + regs_test.cc + ) + set_target_properties(sandbox2_regs_test PROPERTIES + OUTPUT_NAME regs_test + ) + target_link_libraries(sandbox2_regs_test PRIVATE + glog::glog + sapi::config + sapi::status_matchers + sandbox2::bpf_helper + sandbox2::regs + sandbox2::sanitizer + sandbox2::util + sapi::test_main + ) + gtest_discover_tests_xcompile(sandbox2_regs_test) + # sandboxed_api/sandbox2:syscall_test add_executable(sandbox2_syscall_test syscall_test.cc diff --git a/sandboxed_api/sandbox2/regs.cc b/sandboxed_api/sandbox2/regs.cc index 8744d6f..338772f 100644 --- a/sandboxed_api/sandbox2/regs.cc +++ b/sandboxed_api/sandbox2/regs.cc @@ -118,8 +118,8 @@ absl::Status Regs::SkipSyscallReturnValue(uintptr_t value) { user_regs_.gpr[0] = -1; user_regs_.gpr[3] = value; #elif defined(SAPI_ARM64) - user_regs_.regs[0] = -1; - syscall_number_ = value; + syscall_number_ = -1; + user_regs_.regs[0] = value; #elif defined(SAPI_ARM) user_regs_.orig_x0 = -1; user_regs_.regs[7] = value; diff --git a/sandboxed_api/sandbox2/regs_test.cc b/sandboxed_api/sandbox2/regs_test.cc new file mode 100644 index 0000000..b7bc4e9 --- /dev/null +++ b/sandboxed_api/sandbox2/regs_test.cc @@ -0,0 +1,98 @@ +#include "sandboxed_api/sandbox2/regs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "sandboxed_api/sandbox2/sanitizer.h" +#include "sandboxed_api/sandbox2/util.h" +#include "sandboxed_api/sandbox2/util/bpf_helper.h" +#include "sandboxed_api/util/status_matchers.h" + +namespace sandbox2 { +namespace { + +using ::sapi::IsOk; + +#define __WPTRACEEVENT(x) ((x & 0xff0000) >> 16) + +TEST(RegsTest, SkipSyscallWorks) { + std::vector policy = { + LOAD_SYSCALL_NR, + JEQ32(__NR_getpid, TRACE(0)), + ALLOW, + }; + sock_fprog prog = { + .len = policy.size(), + .filter = policy.data(), + }; + // Create socketpair for synchronization + int sv[2]; + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0); + // Fork a child process to run the syscalls in. + pid_t ppid = util::Syscall(__NR_gettid); + pid_t pid = fork(); + ASSERT_NE(pid, -1); + char c = 'C'; + if (pid == 0) { + // Get ready for being ptraced. + sanitizer::WaitForSanitizer(); + CHECK_EQ(prctl(PR_SET_DUMPABLE, 1), 0); + prctl(PR_SET_PTRACER, ppid); + CHECK_EQ(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), 0); + CHECK_EQ(prctl(PR_SET_KEEPCAPS, 0), 0); + // Notify parent that we're ready for ptrace. + CHECK_EQ(write(sv[0], &c, 1), 1); + // Apply seccomp policy + CHECK_EQ(util::Syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0, + reinterpret_cast(&prog)), + 0); + // Wait for tracer to be attached. + CHECK_EQ(read(sv[0], &c, 1), 1); + // Run the test syscall + errno = 0; + util::Syscall(__NR_getpid, 123, reinterpret_cast(&c), 1); + _Exit(errno == ENOENT ? 0 : 1); + } + // Wait for child to be ready for ptrace + ASSERT_EQ(read(sv[1], &c, 1), 1); + ASSERT_EQ(ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACESECCOMP), 0); + // Notify child it has been ptraced. + ASSERT_EQ(write(sv[1], &c, 1), 1); + // Wait for seccomp TRACE stop + int status; + ASSERT_EQ(waitpid(pid, &status, __WNOTHREAD | __WALL | WUNTRACED), pid); + ASSERT_TRUE(WIFSTOPPED(status)); + ASSERT_EQ(__WPTRACEEVENT(status), PTRACE_EVENT_SECCOMP); + // Fetch the registers + Regs regs(pid); + ASSERT_THAT(regs.Fetch(), IsOk()); + // Check syscall arguments + Syscall syscall = regs.ToSyscall(sapi::host_cpu::Architecture()); + EXPECT_EQ(syscall.nr(), __NR_getpid); + EXPECT_EQ(syscall.args()[0], 123); + EXPECT_EQ(syscall.args()[1], reinterpret_cast(&c)); + EXPECT_EQ(syscall.args()[2], 1); + // Skip syscall + ASSERT_THAT(regs.SkipSyscallReturnValue(-ENOENT), IsOk()); + // Continue&detach the child process + ASSERT_EQ(ptrace(PTRACE_DETACH, pid, 0, 0), 0); + // Wait for the child to exit + ASSERT_EQ(waitpid(pid, &status, __WNOTHREAD | __WALL | WUNTRACED), pid); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(WEXITSTATUS(status), 0); +} + +} // namespace +} // namespace sandbox2