Fix Regs::SkipSyscallReturnValue for Aarch64

Add a test.

PiperOrigin-RevId: 420271649
Change-Id: Ifc857ec5351a0fc70547c98f57c22cf792d5d9f9
This commit is contained in:
Wiktor Garbacz 2022-01-07 05:25:42 -08:00 committed by Copybara-Service
parent d54338db3e
commit b0bc17e456
4 changed files with 145 additions and 11 deletions

View File

@ -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( cc_library(
name = "syscall", name = "syscall",
srcs = [ srcs = [

View File

@ -35,13 +35,14 @@ add_library(sandbox2_regs ${SAPI_LIB_TYPE}
regs.h regs.h
) )
add_library(sandbox2::regs ALIAS sandbox2_regs) add_library(sandbox2::regs ALIAS sandbox2_regs)
target_link_libraries(sandbox2_regs PRIVATE target_link_libraries(sandbox2_regs
absl::core_headers PUBLIC absl::status
absl::strings
sapi::config sapi::config
sapi::strerror
sandbox2::syscall sandbox2::syscall
sandbox2::violation_proto sandbox2::violation_proto
PRIVATE absl::core_headers
absl::strings
sapi::strerror
sapi::base sapi::base
sapi::status sapi::status
) )
@ -609,6 +610,25 @@ target_link_libraries(sandbox2_violation_proto PRIVATE
if(SAPI_ENABLE_TESTS) if(SAPI_ENABLE_TESTS)
add_subdirectory(testcases) 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 # sandboxed_api/sandbox2:syscall_test
add_executable(sandbox2_syscall_test add_executable(sandbox2_syscall_test
syscall_test.cc syscall_test.cc

View File

@ -118,8 +118,8 @@ absl::Status Regs::SkipSyscallReturnValue(uintptr_t value) {
user_regs_.gpr[0] = -1; user_regs_.gpr[0] = -1;
user_regs_.gpr[3] = value; user_regs_.gpr[3] = value;
#elif defined(SAPI_ARM64) #elif defined(SAPI_ARM64)
user_regs_.regs[0] = -1; syscall_number_ = -1;
syscall_number_ = value; user_regs_.regs[0] = value;
#elif defined(SAPI_ARM) #elif defined(SAPI_ARM)
user_regs_.orig_x0 = -1; user_regs_.orig_x0 = -1;
user_regs_.regs[7] = value; user_regs_.regs[7] = value;

View File

@ -0,0 +1,98 @@
#include "sandboxed_api/sandbox2/regs.h"
#include <linux/audit.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <cerrno>
#include <cstdlib>
#include <glog/logging.h>
#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<sock_filter> 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<uintptr_t>(&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<uintptr_t>(&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<uintptr_t>(&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