mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Handle S2 unwinding by trapping ptrace
PiperOrigin-RevId: 491893277 Change-Id: I427a2e485173c73fffead43e29511460c58c4f04
This commit is contained in:
parent
bd5769d40a
commit
ee58a410d9
|
@ -77,7 +77,7 @@ endif()
|
||||||
if(SAPI_DOWNLOAD_LIBUNWIND)
|
if(SAPI_DOWNLOAD_LIBUNWIND)
|
||||||
include(cmake/libunwind.cmake)
|
include(cmake/libunwind.cmake)
|
||||||
endif()
|
endif()
|
||||||
sapi_check_target(unwind_ptrace_wrapped)
|
sapi_check_target(unwind_ptrace)
|
||||||
|
|
||||||
if(SAPI_DOWNLOAD_PROTOBUF)
|
if(SAPI_DOWNLOAD_PROTOBUF)
|
||||||
include(cmake/protobuf.cmake)
|
include(cmake/protobuf.cmake)
|
||||||
|
|
|
@ -110,7 +110,7 @@ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(unwind_ptrace_wrapped STATIC
|
add_library(unwind_ptrace STATIC
|
||||||
# internal_headers
|
# internal_headers
|
||||||
${libunwind_SOURCE_DIR}/include/compiler.h
|
${libunwind_SOURCE_DIR}/include/compiler.h
|
||||||
${libunwind_SOURCE_DIR}/include/config.h
|
${libunwind_SOURCE_DIR}/include/config.h
|
||||||
|
@ -185,35 +185,22 @@ add_library(unwind_ptrace_wrapped STATIC
|
||||||
# source_ptrace
|
# source_ptrace
|
||||||
${_unwind_ptrace_srcs}
|
${_unwind_ptrace_srcs}
|
||||||
)
|
)
|
||||||
add_library(unwind::unwind_ptrace_wrapped ALIAS unwind_ptrace_wrapped)
|
add_library(unwind::unwind_ptrace ALIAS unwind_ptrace)
|
||||||
target_include_directories(unwind_ptrace_wrapped PUBLIC
|
target_include_directories(unwind_ptrace PUBLIC
|
||||||
${libunwind_SOURCE_DIR}/include
|
${libunwind_SOURCE_DIR}/include
|
||||||
${libunwind_SOURCE_DIR}/include/tdep
|
${libunwind_SOURCE_DIR}/include/tdep
|
||||||
${libunwind_SOURCE_DIR}/include/tdep-${_unwind_cpu}
|
${libunwind_SOURCE_DIR}/include/tdep-${_unwind_cpu}
|
||||||
${libunwind_SOURCE_DIR}/src
|
${libunwind_SOURCE_DIR}/src
|
||||||
)
|
)
|
||||||
target_compile_options(unwind_ptrace_wrapped PRIVATE
|
target_compile_options(unwind_ptrace PRIVATE
|
||||||
-fno-common
|
-fno-common
|
||||||
-Wno-cpp
|
-Wno-cpp
|
||||||
)
|
)
|
||||||
target_compile_definitions(unwind_ptrace_wrapped
|
target_compile_definitions(unwind_ptrace
|
||||||
PRIVATE -DHAVE_CONFIG_H
|
PRIVATE -DHAVE_CONFIG_H
|
||||||
-D_GNU_SOURCE
|
-D_GNU_SOURCE
|
||||||
-DNO_FRAME_POINTER
|
-DNO_FRAME_POINTER
|
||||||
PUBLIC -D_UPT_accessors=_UPT_accessors_wrapped
|
|
||||||
-D_UPT_create=_UPT_create_wrapped
|
|
||||||
-D_UPT_destroy=_UPT_destroy_wrapped
|
|
||||||
|
|
||||||
-D_U${_unwind_cpu}_create_addr_space=_U${_unwind_cpu}_create_addr_space_wrapped
|
|
||||||
-D_U${_unwind_cpu}_destroy_addr_space=_U${_unwind_cpu}_destroy_addr_space_wrapped
|
|
||||||
-D_U${_unwind_cpu}_get_proc_name=_U${_unwind_cpu}_get_proc_name_wrapped
|
|
||||||
-D_U${_unwind_cpu}_get_reg=_U${_unwind_cpu}_get_reg_wrapped
|
|
||||||
-D_U${_unwind_cpu}_init_remote=_U${_unwind_cpu}_init_remote_wrapped
|
|
||||||
-D_U${_unwind_cpu}_step=_U${_unwind_cpu}_step_wrapped
|
|
||||||
|
|
||||||
-Dptrace=ptrace_wrapped
|
|
||||||
)
|
)
|
||||||
target_link_libraries(unwind_ptrace_wrapped PRIVATE
|
target_link_libraries(unwind_ptrace PRIVATE
|
||||||
sapi::base
|
sapi::base
|
||||||
sandbox2::ptrace_hook
|
|
||||||
)
|
)
|
||||||
|
|
13
sandboxed_api/bazel/external/libunwind.BUILD
vendored
13
sandboxed_api/bazel/external/libunwind.BUILD
vendored
|
@ -106,7 +106,7 @@ filegroup(
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "unwind-ptrace-wrapped",
|
name = "unwind-ptrace",
|
||||||
srcs = [
|
srcs = [
|
||||||
"src/mi/Gdyn-remote.c",
|
"src/mi/Gdyn-remote.c",
|
||||||
"src/ptrace/_UPT_access_fpreg.c",
|
"src/ptrace/_UPT_access_fpreg.c",
|
||||||
|
@ -138,20 +138,9 @@ cc_library(
|
||||||
"-DNO_FRAME_POINTER",
|
"-DNO_FRAME_POINTER",
|
||||||
"-fno-common",
|
"-fno-common",
|
||||||
"-Wno-cpp", # Warning in src/ptrace/_UPT_get_dyn_info_list_addr.c
|
"-Wno-cpp", # Warning in src/ptrace/_UPT_get_dyn_info_list_addr.c
|
||||||
"-D_UPT_accessors=_UPT_accessors_wrapped",
|
|
||||||
"-D_UPT_create=_UPT_create_wrapped",
|
|
||||||
"-D_UPT_destroy=_UPT_destroy_wrapped",
|
|
||||||
"-D_Ux86_64_create_addr_space=_Ux86_64_create_addr_space_wrapped",
|
|
||||||
"-D_Ux86_64_destroy_addr_space=_Ux86_64_destroy_addr_space_wrapped",
|
|
||||||
"-D_Ux86_64_get_proc_name=_Ux86_64_get_proc_name_wrapped",
|
|
||||||
"-D_Ux86_64_get_reg=_Ux86_64_get_reg_wrapped",
|
|
||||||
"-D_Ux86_64_init_remote=_Ux86_64_init_remote_wrapped",
|
|
||||||
"-D_Ux86_64_step=_Ux86_64_step_wrapped",
|
|
||||||
"-Dptrace=ptrace_wrapped",
|
|
||||||
],
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
":included_sources",
|
":included_sources",
|
||||||
"@com_google_sandboxed_api//sandboxed_api/sandbox2/unwind:ptrace_hook",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1246,6 +1246,12 @@ PolicyBuilder& PolicyBuilder::AddNetworkProxyHandlerPolicy() {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PolicyBuilder& PolicyBuilder::TrapPtrace() {
|
||||||
|
AddPolicyOnSyscall(__NR_ptrace, {TRAP(0)});
|
||||||
|
user_policy_handles_ptrace_ = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
PolicyBuilder& PolicyBuilder::SetRootWritable() {
|
PolicyBuilder& PolicyBuilder::SetRootWritable() {
|
||||||
EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
|
EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
|
||||||
mounts_.SetRootWritable();
|
mounts_.SetRootWritable();
|
||||||
|
|
|
@ -605,6 +605,9 @@ class PolicyBuilder final {
|
||||||
// Allows a limited version of madvise
|
// Allows a limited version of madvise
|
||||||
PolicyBuilder& AllowLimitedMadvise();
|
PolicyBuilder& AllowLimitedMadvise();
|
||||||
|
|
||||||
|
// Traps instead of denying ptrace.
|
||||||
|
PolicyBuilder& TrapPtrace();
|
||||||
|
|
||||||
// Appends code to block a specific syscall and setting errno at the end of
|
// Appends code to block a specific syscall and setting errno at the end of
|
||||||
// the policy - decision taken by user policy take precedence.
|
// the policy - decision taken by user policy take precedence.
|
||||||
PolicyBuilder& OverridableBlockSyscallWithErrno(uint32_t num, int error);
|
PolicyBuilder& OverridableBlockSyscallWithErrno(uint32_t num, int error);
|
||||||
|
|
|
@ -120,6 +120,7 @@ absl::StatusOr<std::unique_ptr<Policy>> StackTracePeer::GetPolicy(
|
||||||
.AllowSyscall(__NR_madvise)
|
.AllowSyscall(__NR_madvise)
|
||||||
|
|
||||||
// Required for our ptrace replacement.
|
// Required for our ptrace replacement.
|
||||||
|
.TrapPtrace()
|
||||||
.AddPolicyOnSyscall(
|
.AddPolicyOnSyscall(
|
||||||
__NR_process_vm_readv,
|
__NR_process_vm_readv,
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,8 +28,10 @@ cc_library(
|
||||||
srcs = ["ptrace_hook.cc"],
|
srcs = ["ptrace_hook.cc"],
|
||||||
hdrs = ["ptrace_hook.h"],
|
hdrs = ["ptrace_hook.h"],
|
||||||
copts = sapi_platform_copts(),
|
copts = sapi_platform_copts(),
|
||||||
visibility = ["@org_gnu_libunwind//:__subpackages__"],
|
deps = [
|
||||||
deps = ["@com_google_absl//absl/strings"],
|
"//sandboxed_api/sandbox2/util:syscall_trap",
|
||||||
|
"@com_google_absl//absl/strings",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
|
@ -39,19 +41,6 @@ cc_library(
|
||||||
copts = sapi_platform_copts([
|
copts = sapi_platform_copts([
|
||||||
# TODO(cblichmann): Remove this, fix bazel/external/libunwind.BUILD
|
# TODO(cblichmann): Remove this, fix bazel/external/libunwind.BUILD
|
||||||
"-Iexternal/org_gnu_libunwind/include",
|
"-Iexternal/org_gnu_libunwind/include",
|
||||||
] + [
|
|
||||||
"-D{symbol}={symbol}_wrapped".format(symbol = symbol)
|
|
||||||
for symbol in [
|
|
||||||
"_UPT_accessors",
|
|
||||||
"_UPT_create",
|
|
||||||
"_UPT_destroy",
|
|
||||||
"_Ux86_64_create_addr_space",
|
|
||||||
"_Ux86_64_destroy_addr_space",
|
|
||||||
"_Ux86_64_get_proc_name",
|
|
||||||
"_Ux86_64_get_reg",
|
|
||||||
"_Ux86_64_init_remote",
|
|
||||||
"_Ux86_64_step",
|
|
||||||
]
|
|
||||||
]),
|
]),
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
|
@ -68,7 +57,7 @@ cc_library(
|
||||||
"@com_google_absl//absl/cleanup",
|
"@com_google_absl//absl/cleanup",
|
||||||
"@com_google_absl//absl/status:statusor",
|
"@com_google_absl//absl/status:statusor",
|
||||||
"@com_google_absl//absl/strings",
|
"@com_google_absl//absl/strings",
|
||||||
"@org_gnu_libunwind//:unwind-ptrace-wrapped",
|
"@org_gnu_libunwind//:unwind-ptrace",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ add_library(sandbox2_ptrace_hook STATIC
|
||||||
add_library(sandbox2::ptrace_hook ALIAS sandbox2_ptrace_hook)
|
add_library(sandbox2::ptrace_hook ALIAS sandbox2_ptrace_hook)
|
||||||
target_link_libraries(sandbox2_ptrace_hook
|
target_link_libraries(sandbox2_ptrace_hook
|
||||||
PRIVATE sapi::base
|
PRIVATE sapi::base
|
||||||
|
sandbox2::syscall_trap
|
||||||
PUBLIC absl::strings
|
PUBLIC absl::strings
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ target_link_libraries(sandbox2_unwind PRIVATE
|
||||||
sapi::file_helpers
|
sapi::file_helpers
|
||||||
sapi::raw_logging
|
sapi::raw_logging
|
||||||
sapi::status
|
sapi::status
|
||||||
unwind::unwind_ptrace_wrapped
|
unwind::unwind_ptrace
|
||||||
)
|
)
|
||||||
|
|
||||||
# sandboxed_api/sandbox2/unwind:unwind_proto
|
# sandboxed_api/sandbox2/unwind:unwind_proto
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <elf.h> // For NT_PRSTATUS
|
#include <elf.h> // For NT_PRSTATUS
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#include <syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -25,6 +26,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "sandboxed_api/sandbox2/util/syscall_trap.h"
|
||||||
|
|
||||||
// Android doesn't use an enum for __ptrace_request, use int instead.
|
// Android doesn't use an enum for __ptrace_request, use int instead.
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
using PtraceRequest = int;
|
using PtraceRequest = int;
|
||||||
|
@ -45,38 +48,23 @@ constexpr size_t kRegSize = sizeof(RegType);
|
||||||
// limit).
|
// limit).
|
||||||
auto* g_registers = new std::vector<RegType>();
|
auto* g_registers = new std::vector<RegType>();
|
||||||
|
|
||||||
// Whether ptrace() emulation is in effect. This can only be enabled (per
|
// Hooks ptrace.
|
||||||
// thread), never disabled.
|
|
||||||
thread_local bool g_emulate_ptrace = false;
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void EnablePtraceEmulationWithUserRegs(absl::string_view regs) {
|
|
||||||
g_registers->resize((regs.size() + 1) / kRegSize);
|
|
||||||
memcpy(&g_registers->front(), regs.data(), regs.size());
|
|
||||||
g_emulate_ptrace = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replaces the libc version of ptrace.
|
|
||||||
// This wrapper makes use of process_vm_readv to read process memory instead of
|
// This wrapper makes use of process_vm_readv to read process memory instead of
|
||||||
// issuing ptrace syscalls. Accesses to registers will be emulated, for this the
|
// issuing ptrace syscalls. Accesses to registers will be emulated, for this the
|
||||||
// register values should be set via EnablePtraceEmulationWithUserRegs().
|
// register values should be set via EnablePtraceEmulationWithUserRegs().
|
||||||
extern "C" long int ptrace_wrapped( // NOLINT
|
long int ptrace_hook( // NOLINT
|
||||||
PtraceRequest request, pid_t pid, void* addr, void* data) {
|
PtraceRequest request, pid_t pid, void* addr, void* data) {
|
||||||
if (!g_emulate_ptrace) {
|
|
||||||
return ptrace(request, pid, addr, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case PTRACE_PEEKDATA: {
|
case PTRACE_PEEKDATA: {
|
||||||
long int read_data; // NOLINT
|
RegType read_data;
|
||||||
iovec local = {.iov_base = &read_data, .iov_len = sizeof(read_data)};
|
iovec local = {.iov_base = &read_data, .iov_len = sizeof(read_data)};
|
||||||
iovec remote = {.iov_base = addr, .iov_len = sizeof(read_data)};
|
iovec remote = {.iov_base = addr, .iov_len = sizeof(read_data)};
|
||||||
|
|
||||||
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) <= 0) {
|
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) <= 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return read_data;
|
*reinterpret_cast<RegType*>(data) = read_data;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case PTRACE_PEEKUSER: {
|
case PTRACE_PEEKUSER: {
|
||||||
// Make sure read is in-bounds and aligned.
|
// Make sure read is in-bounds and aligned.
|
||||||
|
@ -85,7 +73,8 @@ extern "C" long int ptrace_wrapped( // NOLINT
|
||||||
offset % kRegSize != 0) {
|
offset % kRegSize != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (*g_registers)[offset / kRegSize];
|
*reinterpret_cast<RegType*>(data) = (*g_registers)[offset / kRegSize];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case PTRACE_GETREGSET: {
|
case PTRACE_GETREGSET: {
|
||||||
// Only return general-purpose registers.
|
// Only return general-purpose registers.
|
||||||
|
@ -100,11 +89,26 @@ extern "C" long int ptrace_wrapped( // NOLINT
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ptrace_wrapped(): operation not permitted: %d\n",
|
fprintf(stderr, "ptrace_hook(): operation not permitted: %d\n", request);
|
||||||
request);
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void EnablePtraceEmulationWithUserRegs(absl::string_view regs) {
|
||||||
|
g_registers->resize((regs.size() + 1) / kRegSize);
|
||||||
|
memcpy(&g_registers->front(), regs.data(), regs.size());
|
||||||
|
SyscallTrap::Install([](int nr, SyscallTrap::Args args, uintptr_t* rv) {
|
||||||
|
if (nr != __NR_ptrace) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*rv = ptrace_hook(
|
||||||
|
static_cast<PtraceRequest>(args[0]), static_cast<pid_t>(args[1]),
|
||||||
|
reinterpret_cast<void*>(args[2]), reinterpret_cast<void*>(args[3]));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sandbox2
|
} // namespace sandbox2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user