diff --git a/sandboxed_api/sandbox2/util/BUILD.bazel b/sandboxed_api/sandbox2/util/BUILD.bazel index 108fd54..cd9912c 100644 --- a/sandboxed_api/sandbox2/util/BUILD.bazel +++ b/sandboxed_api/sandbox2/util/BUILD.bazel @@ -81,6 +81,17 @@ cc_test( ], ) +cc_library( + name = "syscall_trap", + srcs = ["syscall_trap.cc"], + hdrs = ["syscall_trap.h"], + copts = sapi_platform_copts(), + deps = [ + "//sandboxed_api:config", + "@com_google_absl//absl/log:check", + ], +) + cc_library( name = "maps_parser", srcs = ["maps_parser.cc"], diff --git a/sandboxed_api/sandbox2/util/CMakeLists.txt b/sandboxed_api/sandbox2/util/CMakeLists.txt index 0bbc072..fc7821d 100644 --- a/sandboxed_api/sandbox2/util/CMakeLists.txt +++ b/sandboxed_api/sandbox2/util/CMakeLists.txt @@ -50,6 +50,18 @@ target_link_libraries(sandbox2_util_maps_parser PUBLIC absl::statusor ) +# sandboxed_api/sandbox2/util:syscall_trap +add_library(sandbox2_util_syscall_trap ${SAPI_LIB_TYPE} + syscall_trap.cc + syscall_trap.h +) +add_library(sandbox2::syscall_trap ALIAS sandbox2_util_syscall_trap) +target_link_libraries(sandbox2_util_syscall_trap + PRIVATE absl::check + sapi::base + sapi::config +) + if(BUILD_TESTING AND SAPI_BUILD_TESTING) # sandboxed_api/sandbox2/util:minielf_test add_executable(sandbox2_minielf_test diff --git a/sandboxed_api/sandbox2/util/syscall_trap.cc b/sandboxed_api/sandbox2/util/syscall_trap.cc new file mode 100644 index 0000000..5a7fec3 --- /dev/null +++ b/sandboxed_api/sandbox2/util/syscall_trap.cc @@ -0,0 +1,130 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sandboxed_api/sandbox2/util/syscall_trap.h" + +#include + +#include "absl/log/check.h" +#include "sandboxed_api/config.h" + +namespace sandbox2 { +namespace { + +#if defined(SAPI_X86_64) +constexpr int kRegResult = REG_RAX; +constexpr int kRegSyscall = REG_RAX; +constexpr std::array kRegArgs = {REG_RDI, REG_RSI, REG_RDX, + REG_R10, REG_R8, REG_R9}; +#elif defined(SAPI_PPC64_LE) +constexpr int kRegResult = 3; +constexpr int kRegSyscall = 0; +constexpr std::array kRegArgs = {3, 4, 5, 6, 7, 8}; +#elif defined(SAPI_ARM64) +constexpr int kRegResult = 0; +constexpr int kRegSyscall = 8; +constexpr std::array kRegArgs = {0, 1, 2, 3, 4, 5}; +#elif defined(SAPI_ARM) +constexpr int kRegResult = 0; +constexpr int kRegSyscall = 8; +constexpr std::array kRegArgs = {0, 1, 2, 3, 4, 5}; +#endif + +#ifndef SYS_SECCOMP +constexpr int SYS_SECCOMP = 1; +#endif + +SyscallTrap* g_instance = nullptr; + +} // namespace + +void SyscallTrap::SignalHandler(int nr, siginfo_t* info, void* context) { + return g_instance->SignalHandlerImpl(nr, info, context); +} + +void SyscallTrap::InvokeOldAct(int nr, siginfo_t* info, void* context) { + if (oldact_.sa_flags & SA_SIGINFO) { + if (oldact_.sa_sigaction) { + oldact_.sa_sigaction(nr, info, context); + } + } else if (oldact_.sa_handler == SIG_IGN) { + return; + } else if (oldact_.sa_handler == SIG_DFL) { + sigaction(SIGSYS, &oldact_, nullptr); + raise(SIGSYS); + } else if (oldact_.sa_handler) { + oldact_.sa_handler(nr); + } +} + +void SyscallTrap::SignalHandlerImpl(int nr, siginfo_t* info, void* context) { + int old_errno = errno; + if (nr != SIGSYS) { + InvokeOldAct(nr, info, context); + errno = old_errno; + return; + } + if (info->si_code != SYS_SECCOMP) { + InvokeOldAct(nr, info, context); + errno = old_errno; + return; + } + auto* uctx = static_cast(context); + if (!uctx) { + errno = old_errno; + return; + } + +#if defined(SAPI_X86_64) + auto* registers = uctx->uc_mcontext.gregs; +#elif defined(SAPI_PPC64_LE) + auto* registers = uctx->uc_mcontext.gp_regs; +#elif defined(SAPI_ARM64) + auto* registers = uctx->uc_mcontext.regs; +#elif defined(SAPI_ARM) + auto* registers = &uctx->uc_mcontext.arm_r0; +#endif + int syscall_nr = registers[kRegSyscall]; + Args args = {registers[kRegArgs[0]], registers[kRegArgs[1]], + registers[kRegArgs[2]], registers[kRegArgs[3]], + registers[kRegArgs[4]], registers[kRegArgs[5]]}; + uintptr_t rv; + if (!handler_(syscall_nr, args, &rv)) { + InvokeOldAct(nr, info, context); + errno = old_errno; + return; + } + registers[kRegResult] = rv; +} + +bool SyscallTrap::Install(bool (*handler)(int nr, Args args, + uintptr_t* result)) { + if (g_instance) { + return false; + } + g_instance = new SyscallTrap(handler); + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGSYS); + + struct sigaction act = {}; + act.sa_sigaction = &SignalHandler; + act.sa_flags = SA_SIGINFO; + + CHECK_EQ(sigaction(SIGSYS, &act, &g_instance->oldact_), 0); + CHECK_EQ(sigprocmask(SIG_UNBLOCK, &mask, nullptr), 0); + return true; +} + +} // namespace sandbox2 diff --git a/sandboxed_api/sandbox2/util/syscall_trap.h b/sandboxed_api/sandbox2/util/syscall_trap.h new file mode 100644 index 0000000..bdb209e --- /dev/null +++ b/sandboxed_api/sandbox2/util/syscall_trap.h @@ -0,0 +1,48 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SANDBOXED_API_SANDBOX2_UTIL_SYSCALL_TRAP_H_ +#define SANDBOXED_API_SANDBOX2_UTIL_SYSCALL_TRAP_H_ + +#include + +#include + +namespace sandbox2 { + +// Helper class for intercepting syscalls via SECCCOMP_RET_TRAP. +class SyscallTrap { + public: + static constexpr int kSyscallArgs = 6; + using Args = std::array; + + // Installs the syscall trap handler. + // Returns false if the handler could not be installed. + static bool Install(bool (*handler)(int nr, Args args, uintptr_t* result)); + + private: + static void SignalHandler(int nr, siginfo_t* info, void* context); + + explicit SyscallTrap(bool (*handler)(int nr, Args args, uintptr_t* result)) + : handler_(handler) {} + void InvokeOldAct(int nr, siginfo_t* info, void* context); + void SignalHandlerImpl(int nr, siginfo_t* info, void* context); + + struct sigaction oldact_; + bool (*handler_)(int nr, Args args, uintptr_t* result); +}; + +} // namespace sandbox2 + +#endif // SANDBOXED_API_SANDBOX2_UTIL_SYSCALL_TRAP_H_