diff options
author | A. Cody Schuffelen <schuffelen@google.com> | 2024-02-13 04:56:15 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2024-02-13 04:56:15 +0000 |
commit | 0fc0cacf38b3643102b510c6ec0711c6f70c85da (patch) | |
tree | a4ebe56fe319047144b94bf8290bca25bb6c4bd3 | |
parent | 45c743211146d58592c7274622aecf7c6f43df00 (diff) | |
parent | bbaabc5ab384b910d474223313e866d75b3bfcec (diff) | |
download | sandboxed-api-main.tar.gz |
Original change: https://android-review.googlesource.com/c/platform/external/sandboxed-api/+/2951214
Change-Id: I2a7d93bce8fce583c9916a3b11c366ddfdda3234
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
41 files changed, 587 insertions, 158 deletions
diff --git a/.github/workflows/fedora-cmake.yml b/.github/workflows/fedora-cmake.yml index e2a4bb8..9157dd5 100644 --- a/.github/workflows/fedora-cmake.yml +++ b/.github/workflows/fedora-cmake.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: include: - - container: fedora:35 + - container: fedora:38 compiler: gcc compiler-version: 11 # Only used in cache action so far ignore-errors: true # Stack trace test fails on Fedora (issue #118) @@ -56,7 +56,7 @@ jobs: - name: Create Build Environment run: | - $RUN_CMD pip3 install --progress-bar=off absl-py clang + $RUN_CMD pip3 install --progress-bar=off absl-py 'clang>=13,<14' $RUN_CMD cmake -E make_directory $GITHUB_WORKSPACE/build - name: Configure CMake diff --git a/.github/workflows/ubuntu-cmake-contrib.yml b/.github/workflows/ubuntu-cmake-contrib.yml index 193b97d..8d67218 100644 --- a/.github/workflows/ubuntu-cmake-contrib.yml +++ b/.github/workflows/ubuntu-cmake-contrib.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04] + os: [ubuntu-22.04] contrib: - brotli - c-blosc @@ -78,7 +78,7 @@ jobs: - name: Create Build Environment run: | - pip3 install absl-py clang + pip3 install absl-py 'clang>=14,<15' cmake -E make_directory $GITHUB_WORKSPACE/build - name: Configure CMake diff --git a/contrib/zopfli/sandboxed.h b/contrib/zopfli/sandboxed.h index 80442e3..7f25069 100644 --- a/contrib/zopfli/sandboxed.h +++ b/contrib/zopfli/sandboxed.h @@ -31,7 +31,7 @@ class ZopfliSapiSandbox : public ZopfliSandbox { .AllowDynamicStartup() .AllowWrite() .AllowExit() - .AllowMmap() + .AllowMmapWithoutExec() .AllowSystemMalloc() .AllowSyscalls({ __NR_recvmsg, diff --git a/oss-internship-2020/curl/sandbox.h b/oss-internship-2020/curl/sandbox.h index 29bbbc2..49cf7ad 100644 --- a/oss-internship-2020/curl/sandbox.h +++ b/oss-internship-2020/curl/sandbox.h @@ -38,7 +38,7 @@ class CurlSapiSandbox : public curl::CurlSandbox { .AllowFutexOp(FUTEX_WAIT_PRIVATE) .AllowFutexOp(FUTEX_WAKE_PRIVATE) .AllowFutexOp(FUTEX_REQUEUE_PRIVATE) - .AllowMmap() + .AllowMmapWithoutExec() .AllowOpen() .AllowSafeFcntl() .AllowWrite() diff --git a/oss-internship-2020/libpng/sandboxed.h b/oss-internship-2020/libpng/sandboxed.h index c811ddc..d55247e 100644 --- a/oss-internship-2020/libpng/sandboxed.h +++ b/oss-internship-2020/libpng/sandboxed.h @@ -38,7 +38,7 @@ class LibPNGSapiSandbox : public LibPNGSandbox { .AllowOpen() .AllowExit() .AllowStat() - .AllowMmap() + .AllowMmapWithoutExec() .AllowSystemMalloc() .AllowSyscalls({ __NR_futex, diff --git a/oss-internship-2020/libuv/examples/uvcat.cc b/oss-internship-2020/libuv/examples/uvcat.cc index 7b54f76..cc930fa 100644 --- a/oss-internship-2020/libuv/examples/uvcat.cc +++ b/oss-internship-2020/libuv/examples/uvcat.cc @@ -37,7 +37,7 @@ class UVSapiUVCatSandbox : public uv::UVSandbox { .AllowFork() .AllowFutexOp(FUTEX_WAKE_PRIVATE) .AllowFutexOp(FUTEX_WAIT_PRIVATE) - .AllowMmap() + .AllowMmapWithoutExec() .AllowOpen() .AllowEpoll() .AllowSyscall(__NR_eventfd2) diff --git a/oss-internship-2020/libuv/tests/test_os.cc b/oss-internship-2020/libuv/tests/test_os.cc index 1e5da3b..a96a5ce 100644 --- a/oss-internship-2020/libuv/tests/test_os.cc +++ b/oss-internship-2020/libuv/tests/test_os.cc @@ -32,7 +32,7 @@ class UVTestOSSapiSandbox : public uv::UVSandbox { .AllowExit() .AllowFutexOp(FUTEX_WAKE_PRIVATE) .AllowGetIDs() - .AllowMmap() + .AllowMmapWithoutExec() .AllowOpen() .AllowWrite() .AllowSyscalls({__NR_connect, __NR_socket}) diff --git a/sandboxed_api/bazel/sapi.bzl b/sandboxed_api/bazel/sapi.bzl index 4b79e41..386c32b 100644 --- a/sandboxed_api/bazel/sapi.bzl +++ b/sandboxed_api/bazel/sapi.bzl @@ -146,10 +146,10 @@ def _sapi_interface_impl(ctx): # Disable warnings in parsed code extra_flags.append("--extra-arg=-Wno-everything") - extra_flags += ["--extra-arg=-isystem{}".format(d) for d in cpp_toolchain.built_in_include_directories] extra_flags += ["--extra-arg=-D{}".format(d) for d in cc_ctx.defines.to_list()] extra_flags += ["--extra-arg=-isystem{}".format(i) for i in cc_ctx.system_includes.to_list()] extra_flags += ["--extra-arg=-iquote{}".format(i) for i in quote_includes] + extra_flags += ["--extra-arg=-isystem{}".format(d) for d in cpp_toolchain.built_in_include_directories] else: append_all(extra_flags, "-D", cc_ctx.defines.to_list()) append_all(extra_flags, "-isystem", cc_ctx.system_includes.to_list()) @@ -236,6 +236,7 @@ def sapi_library( name, lib, lib_name, + malloc = "@bazel_tools//tools/cpp:malloc", namespace = "", api_version = 1, embed = True, @@ -355,6 +356,7 @@ def sapi_library( # The sandboxing client must have access to all "-Wl,-E", # symbols used in the sandboxed library, so these ] + exported_funcs, # must be both referenced, and exported + malloc = malloc, deps = [ ":" + name + ".lib", "//sandboxed_api:client", diff --git a/sandboxed_api/rpcchannel.cc b/sandboxed_api/rpcchannel.cc index 7eeb447..7e76b05 100644 --- a/sandboxed_api/rpcchannel.cc +++ b/sandboxed_api/rpcchannel.cc @@ -140,16 +140,6 @@ absl::Status RPCChannel::Exit() { // Try the RPC exit sequence. But, the only thing that matters as a success // indicator is whether the Comms channel had been closed comms_->SendTLV(comms::kMsgExit, 0, nullptr); - bool unused; - comms_->RecvBool(&unused); - - if (!comms_->IsTerminated()) { - LOG(ERROR) << "Comms channel not terminated in Exit()"; - // TODO(hamacher): Better error code - return absl::FailedPreconditionError( - "Comms channel not terminated in Exit()"); - } - return absl::OkStatus(); } diff --git a/sandboxed_api/sandbox.cc b/sandboxed_api/sandbox.cc index b134ac9..88b2696 100644 --- a/sandboxed_api/sandbox.cc +++ b/sandboxed_api/sandbox.cc @@ -40,6 +40,7 @@ #include "sandboxed_api/sandbox2/executor.h" #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/policybuilder.h" +#include "sandboxed_api/sandbox2/result.h" #include "sandboxed_api/sandbox2/sandbox2.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" #include "sandboxed_api/util/fileops.h" @@ -75,6 +76,7 @@ void InitDefaultPolicyBuilder(sandbox2::PolicyBuilder* builder) { .AllowGetPIDs() .AllowSleep() .AllowReadlink() + .AllowAccess() .AllowSyscalls({ __NR_recvmsg, __NR_sendmsg, @@ -105,20 +107,31 @@ void Sandbox::Terminate(bool attempt_graceful_exit) { return; } + absl::StatusOr<sandbox2::Result> result; if (attempt_graceful_exit) { - // Gracefully ask it to exit (with 1 second limit) first, then kill it. - Exit(); - } else { - // Kill it straight away + if (absl::Status requested_exit = rpc_channel_->Exit(); + !requested_exit.ok()) { + LOG(WARNING) + << "rpc_channel->Exit() failed, calling AwaitResultWithTimeout(1) " + << requested_exit; + } + result = s2_->AwaitResultWithTimeout(absl::Seconds(1)); + if (!result.ok()) { + LOG(WARNING) << "s2_->AwaitResultWithTimeout failed, status: " + << result.status() << " Killing PID: " << pid(); + } + } + + if (!attempt_graceful_exit || !result.ok()) { s2_->Kill(); + result = s2_->AwaitResult(); } - const auto& result = AwaitResult(); - if (result.final_status() == sandbox2::Result::OK && - result.reason_code() == 0) { - VLOG(2) << "Sandbox2 finished with: " << result.ToString(); + if (result->final_status() == sandbox2::Result::OK && + result->reason_code() == 0) { + VLOG(2) << "Sandbox2 finished with: " << result->ToString(); } else { - LOG(WARNING) << "Sandbox2 finished with: " << result.ToString(); + LOG(WARNING) << "Sandbox2 finished with: " << result->ToString(); } } @@ -127,7 +140,7 @@ static std::string PathToSAPILib(const std::string& lib_path) { : GetDataDependencyFilePath(lib_path); } -absl::Status Sandbox::Init() { +absl::Status Sandbox::Init(bool use_unotify_monitor) { // It's already initialized if (is_active()) { return absl::OkStatus(); @@ -176,6 +189,9 @@ absl::Status Sandbox::Init() { sandbox2::PolicyBuilder policy_builder; InitDefaultPolicyBuilder(&policy_builder); + if (use_unotify_monitor) { + policy_builder.CollectStacktracesOnSignal(false); + } auto s2p = ModifyPolicy(&policy_builder); // Spawn new process from the forkserver. @@ -196,6 +212,9 @@ absl::Status Sandbox::Init() { s2_ = std::make_unique<sandbox2::Sandbox2>(std::move(executor), std::move(s2p), CreateNotifier()); + if (use_unotify_monitor) { + SAPI_RETURN_IF_ERROR(s2_->EnableUnotifyMonitor()); + } s2_awaited_ = false; auto res = s2_->RunAsync(); @@ -306,6 +325,14 @@ absl::Status Sandbox::Call(const std::string& func, v::Callable* ret, // Copy all arguments into rfcall. int i = 0; for (auto* arg : args) { + if (arg == nullptr) { + rfcall.arg_type[i] = v::Type::kPointer; + rfcall.arg_size[i] = sizeof(void*); + rfcall.args[i].arg_int = 0; + VLOG(1) << "CALL ARG: (" << i << "): nullptr"; + ++i; + continue; + } rfcall.arg_size[i] = arg->GetSize(); rfcall.arg_type[i] = arg->GetType(); @@ -339,7 +366,6 @@ absl::Status Sandbox::Call(const std::string& func, v::Callable* ret, } rfcall.args[i].arg_int = fd->GetRemoteFd(); } - VLOG(1) << "CALL ARG: (" << i << "), Type: " << arg->GetTypeString() << ", Size: " << arg->GetSize() << ", Val: " << arg->ToString(); ++i; @@ -364,7 +390,9 @@ absl::Status Sandbox::Call(const std::string& func, v::Callable* ret, // Synchronize all pointers after the call if it's needed. for (auto* arg : args) { - SAPI_RETURN_IF_ERROR(SynchronizePtrAfter(arg)); + if (arg != nullptr) { + SAPI_RETURN_IF_ERROR(SynchronizePtrAfter(arg)); + } } VLOG(1) << "CALL EXIT: Type: " << ret->GetTypeString() diff --git a/sandboxed_api/sandbox.h b/sandboxed_api/sandbox.h index 577144e..b691e08 100644 --- a/sandboxed_api/sandbox.h +++ b/sandboxed_api/sandbox.h @@ -52,7 +52,7 @@ class Sandbox { virtual ~Sandbox(); // Initializes a new sandboxing session. - absl::Status Init(); + absl::Status Init(bool use_unotify_monitor = false); // Returns whether the current sandboxing session is active. bool is_active() const; diff --git a/sandboxed_api/sandbox2/BUILD.bazel b/sandboxed_api/sandbox2/BUILD.bazel index 9e0ade3..3b08b55 100644 --- a/sandboxed_api/sandbox2/BUILD.bazel +++ b/sandboxed_api/sandbox2/BUILD.bazel @@ -41,6 +41,23 @@ cc_library( ) cc_library( + name = "trace_all_syscalls", + hdrs = ["trace_all_syscalls.h"], + copts = sapi_platform_copts(), + visibility = [ + "//sandboxed_api/sandbox2:__pkg__", + ], +) + +cc_library( + name = "testonly_trace_all_syscalls", + testonly = True, + hdrs = ["trace_all_syscalls.h"], + copts = sapi_platform_copts(), + visibility = ["//visibility:public"], +) + +cc_library( name = "allow_unrestricted_networking", hdrs = ["allow_unrestricted_networking.h"], copts = sapi_platform_copts(), @@ -109,15 +126,18 @@ cc_library( srcs = [ "syscall.cc", "syscall_defs.cc", + ], + hdrs = [ + "syscall.h", "syscall_defs.h", ], - hdrs = ["syscall.h"], copts = sapi_platform_copts(), visibility = ["//visibility:public"], deps = [ ":util", "//sandboxed_api:config", "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", @@ -237,7 +257,6 @@ cc_library( ":result", ":syscall", ":util", - "//sandboxed_api:config", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/log", ], @@ -529,6 +548,7 @@ cc_library( ":stack_trace", ":syscall", ":util", + "//sandboxed_api/sandbox2/network_proxy:client", "//sandboxed_api/sandbox2/network_proxy:server", "//sandboxed_api/util:file_helpers", "//sandboxed_api/util:raw_logging", @@ -560,6 +580,7 @@ cc_library( ":namespace", ":policy", ":syscall", + ":trace_all_syscalls", ":violation_cc_proto", "//sandboxed_api:config", "//sandboxed_api/sandbox2/network_proxy:filtering", @@ -921,6 +942,7 @@ cc_test( deps = [ ":comms", ":sandbox2", + ":trace_all_syscalls", "//sandboxed_api:testing", "@com_google_absl//absl/log", "@com_google_absl//absl/strings", @@ -957,6 +979,7 @@ cc_test( copts = sapi_platform_copts(), data = [ "//sandboxed_api/sandbox2/testcases:abort", + "//sandboxed_api/sandbox2/testcases:custom_fork", "//sandboxed_api/sandbox2/testcases:minimal", "//sandboxed_api/sandbox2/testcases:sleep", "//sandboxed_api/sandbox2/testcases:starve", @@ -967,6 +990,7 @@ cc_test( "no_qemu_user_mode", ], deps = [ + ":fork_client", ":sandbox2", "//sandboxed_api:config", "//sandboxed_api:testing", diff --git a/sandboxed_api/sandbox2/CMakeLists.txt b/sandboxed_api/sandbox2/CMakeLists.txt index 116f609..b01c4d9 100644 --- a/sandboxed_api/sandbox2/CMakeLists.txt +++ b/sandboxed_api/sandbox2/CMakeLists.txt @@ -26,6 +26,15 @@ target_link_libraries(sandbox2_allow_all_syscalls PRIVATE sapi::base ) +# sandboxed_api/sandbox2:trace_all_syscalls +add_library(sandbox2_trace_all_syscalls ${SAPI_LIB_TYPE} + trace_all_syscalls.h +) +add_library(sandbox2::trace_all_syscalls ALIAS sandbox2_trace_all_syscalls) +target_link_libraries(sandbox2_trace_all_syscalls PRIVATE + sapi::base +) + # sandboxed_api/sandbox2:allow_unrestricted_networking add_library(sandbox2_allow_unrestricted_networking ${SAPI_LIB_TYPE} allow_unrestricted_networking.h @@ -194,7 +203,6 @@ target_link_libraries(sandbox2_notify sandbox2::syscall sandbox2::util PRIVATE sapi::base - sapi::config ) # sandboxed_api/sandbox2:limits @@ -422,6 +430,7 @@ target_link_libraries(sandbox2_monitor_base sandbox2::executor sandbox2::fork_client sandbox2::ipc + sandbox2::network_proxy_client sandbox2::network_proxy_server sandbox2::notify sandbox2::policy @@ -994,6 +1003,7 @@ if(BUILD_TESTING AND SAPI_BUILD_TESTING) sandbox2::comms sandbox2::regs sandbox2::sandbox2 + sandbox2::trace_all_syscalls sapi::testing sapi::test_main ) @@ -1039,6 +1049,7 @@ if(BUILD_TESTING AND SAPI_BUILD_TESTING) ) add_dependencies(sandbox2_sandbox2_test sandbox2::testcase_abort + sandbox2::testcase_custom_fork sandbox2::testcase_minimal sandbox2::testcase_sleep sandbox2::testcase_tsync @@ -1050,6 +1061,7 @@ if(BUILD_TESTING AND SAPI_BUILD_TESTING) absl::synchronization absl::time sapi::config + sandbox2::fork_client sandbox2::sandbox2 sapi::testing sapi::status_matchers diff --git a/sandboxed_api/sandbox2/examples/network/network_sandbox.cc b/sandboxed_api/sandbox2/examples/network/network_sandbox.cc index 684cbde..7dca5f6 100644 --- a/sandboxed_api/sandbox2/examples/network/network_sandbox.cc +++ b/sandboxed_api/sandbox2/examples/network/network_sandbox.cc @@ -49,7 +49,7 @@ namespace { std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) { return sandbox2::PolicyBuilder() .AllowExit() - .AllowMmap() + .AllowMmapWithoutExec() .AllowRead() .AllowWrite() .AllowSyscall(__NR_close) diff --git a/sandboxed_api/sandbox2/examples/network_proxy/networkproxy_sandbox.cc b/sandboxed_api/sandbox2/examples/network_proxy/networkproxy_sandbox.cc index da1c800..76208d1 100644 --- a/sandboxed_api/sandbox2/examples/network_proxy/networkproxy_sandbox.cc +++ b/sandboxed_api/sandbox2/examples/network_proxy/networkproxy_sandbox.cc @@ -41,7 +41,7 @@ constexpr char kSandboxeePath[] = std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) { sandbox2::PolicyBuilder builder; builder.AllowExit() - .AllowMmap() + .AllowMmapWithoutExec() .AllowRead() .AllowWrite() .AllowStat() // printf, puts @@ -50,6 +50,7 @@ std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) { .AllowSyscall(__NR_lseek) .AllowSyscall(__NR_munmap) .AllowSyscall(__NR_getpid) + .AllowSyscall(__NR_sigaltstack) .AllowTcMalloc() .AddLibrariesForBinary(sandboxee_path); if (absl::GetFlag(FLAGS_connect_with_handler)) { diff --git a/sandboxed_api/sandbox2/fork_client.cc b/sandboxed_api/sandbox2/fork_client.cc index 285344e..7ccc22f 100644 --- a/sandboxed_api/sandbox2/fork_client.cc +++ b/sandboxed_api/sandbox2/fork_client.cc @@ -27,6 +27,13 @@ namespace sandbox2 { using ::sapi::file_util::fileops::FDCloser; +ForkClient::ForkClient(pid_t pid, Comms* comms, bool is_global) + : pid_(pid), comms_(comms), is_global_(is_global) { +} + +ForkClient::~ForkClient() { +} + SandboxeeProcess ForkClient::SendRequest(const ForkRequest& request, int exec_fd, int comms_fd) { SandboxeeProcess process; diff --git a/sandboxed_api/sandbox2/fork_client.h b/sandboxed_api/sandbox2/fork_client.h index 842b152..60d483e 100644 --- a/sandboxed_api/sandbox2/fork_client.h +++ b/sandboxed_api/sandbox2/fork_client.h @@ -37,9 +37,10 @@ struct SandboxeeProcess { class ForkClient { public: - ForkClient(pid_t pid, Comms* comms) : pid_(pid), comms_(comms) {} + ForkClient(pid_t pid, Comms* comms) : ForkClient(pid, comms, false) {} ForkClient(const ForkClient&) = delete; ForkClient& operator=(const ForkClient&) = delete; + ~ForkClient(); // Sends the fork request over the supplied Comms channel. SandboxeeProcess SendRequest(const ForkRequest& request, int exec_fd, @@ -48,10 +49,16 @@ class ForkClient { pid_t pid() { return pid_; } private: + friend class GlobalForkClient; + + ForkClient(pid_t pid, Comms* comms, bool is_global); + // Pid of the ForkServer. pid_t pid_; // Comms channel connecting with the ForkServer. Not owned by the object. Comms* comms_ ABSL_GUARDED_BY(comms_mutex_); + // Is it the global forkserver + bool is_global_; // Mutex locking transactions (requests) over the Comms channel. absl::Mutex comms_mutex_; }; diff --git a/sandboxed_api/sandbox2/forkserver.cc b/sandboxed_api/sandbox2/forkserver.cc index 1106e02..c8b381b 100644 --- a/sandboxed_api/sandbox2/forkserver.cc +++ b/sandboxed_api/sandbox2/forkserver.cc @@ -543,16 +543,20 @@ bool ForkServer::Initialize() { cap_t wanted_caps = cap_init(); // starts as empty set, ie. no caps SAPI_RAW_CHECK(wanted_caps, "failed to cap_init()"); - for (cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) { - cap_flag_value_t value; - int rc = cap_get_flag(have_caps, CAP_SETFCAP, flag, &value); - SAPI_RAW_CHECK(!rc, "cap_get_flag"); - if (value == CAP_SET) { - cap_value_t caps_to_set[1] = { - CAP_SETFCAP, - }; - rc = cap_set_flag(wanted_caps, flag, 1, caps_to_set, CAP_SET); - SAPI_RAW_CHECK(!rc, "cap_set_flag"); + // CAP_SYS_PTRACE appears to be needed for apparmor (or possibly yama) + // CAP_SETFCAP is needed on newer kernels (5.10 needs it, 4.15 does not) + for (cap_value_t cap : {CAP_SYS_PTRACE, CAP_SETFCAP}) { + for (cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) { + cap_flag_value_t value; + int rc = cap_get_flag(have_caps, cap, flag, &value); + SAPI_RAW_CHECK(!rc, "cap_get_flag"); + if (value == CAP_SET) { + cap_value_t caps_to_set[1] = { + cap, + }; + rc = cap_set_flag(wanted_caps, flag, 1, caps_to_set, CAP_SET); + SAPI_RAW_CHECK(!rc, "cap_set_flag"); + } } } diff --git a/sandboxed_api/sandbox2/global_forkclient.cc b/sandboxed_api/sandbox2/global_forkclient.cc index 8a6231e..b014931 100644 --- a/sandboxed_api/sandbox2/global_forkclient.cc +++ b/sandboxed_api/sandbox2/global_forkclient.cc @@ -271,7 +271,7 @@ void GlobalForkClient::ForceStart() { "already running"); absl::StatusOr<std::unique_ptr<GlobalForkClient>> forkserver = StartGlobalForkServer(); - SAPI_RAW_CHECK(forkserver.ok(), forkserver.status().message().data()); + SAPI_RAW_CHECK(forkserver.ok(), forkserver.status().ToString().c_str()); instance_ = forkserver->release(); } diff --git a/sandboxed_api/sandbox2/global_forkclient.h b/sandboxed_api/sandbox2/global_forkclient.h index 4517c27..13e8ad1 100644 --- a/sandboxed_api/sandbox2/global_forkclient.h +++ b/sandboxed_api/sandbox2/global_forkclient.h @@ -43,7 +43,7 @@ enum class GlobalForkserverStartMode { class GlobalForkClient { public: GlobalForkClient(int fd, pid_t pid) - : comms_(fd), fork_client_(pid, &comms_) {} + : comms_(fd), fork_client_(pid, &comms_, /*is_global=*/true) {} static SandboxeeProcess SendRequest(const ForkRequest& request, int exec_fd, int comms_fd) diff --git a/sandboxed_api/sandbox2/logserver.proto b/sandboxed_api/sandbox2/logserver.proto index 0329c24..a2bf74d 100644 --- a/sandboxed_api/sandbox2/logserver.proto +++ b/sandboxed_api/sandbox2/logserver.proto @@ -13,12 +13,13 @@ // limitations under the License. syntax = "proto3"; + package sandbox2; message LogMessage { optional int32 severity = 1; optional string path = 2; optional int32 line = 3; - optional string message = 4; + optional bytes message = 4; optional int32 pid = 5; } diff --git a/sandboxed_api/sandbox2/monitor_base.cc b/sandboxed_api/sandbox2/monitor_base.cc index 8423415..76978c9 100644 --- a/sandboxed_api/sandbox2/monitor_base.cc +++ b/sandboxed_api/sandbox2/monitor_base.cc @@ -50,7 +50,9 @@ #include "sandboxed_api/sandbox2/limits.h" #include "sandboxed_api/sandbox2/mounts.h" #include "sandboxed_api/sandbox2/namespace.h" +#include "sandboxed_api/sandbox2/network_proxy/client.h" #include "sandboxed_api/sandbox2/network_proxy/server.h" +#include "sandboxed_api/sandbox2/notify.h" #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/result.h" #include "sandboxed_api/sandbox2/stack_trace.h" diff --git a/sandboxed_api/sandbox2/mounts.cc b/sandboxed_api/sandbox2/mounts.cc index 097d53d..227d207 100644 --- a/sandboxed_api/sandbox2/mounts.cc +++ b/sandboxed_api/sandbox2/mounts.cc @@ -163,7 +163,7 @@ bool HasSameTarget(const MountTree::Node& n1, const MountTree::Node& n2) { if (n1.node_case() != n2.node_case()) { return false; } - // Compare proto fileds + // Compare proto fields switch (n1.node_case()) { case MountTree::Node::kFileNode: // Check whether files are the same (e.g. symlinks / hardlinks) @@ -185,7 +185,7 @@ bool IsEquivalentNode(const MountTree::Node& n1, const MountTree::Node& n2) { return false; } - // Compare proto fileds + // Compare proto fields switch (n1.node_case()) { case MountTree::Node::kFileNode: return n1.file_node().writable() == n2.file_node().writable(); @@ -309,7 +309,7 @@ absl::Status Mounts::Insert(absl::string_view path, if (!internal::IsWritable(curtree->node()) && internal::IsWritable(new_node)) { SAPI_RAW_LOG(INFO, - "Chaning %s to writable, was insterted read-only before", + "Changing %s to writable, was inserted read-only before", std::string(path).c_str()); *curtree->mutable_node() = new_node; return absl::OkStatus(); @@ -317,7 +317,7 @@ absl::Status Mounts::Insert(absl::string_view path, if (internal::IsWritable(curtree->node()) && !internal::IsWritable(new_node)) { SAPI_RAW_LOG(INFO, - "Inserting %s read-only is a nop, as it was insterted " + "Inserting %s read-only is a nop, as it was inserted " "writable before", std::string(path).c_str()); return absl::OkStatus(); @@ -349,7 +349,7 @@ absl::Status Mounts::AddFileAt(absl::string_view outside, absl::Status Mounts::AddDirectoryAt(absl::string_view outside, absl::string_view inside, bool is_ro) { MountTree::Node node; - auto dir_node = node.mutable_dir_node(); + auto* dir_node = node.mutable_dir_node(); dir_node->set_outside(std::string(outside)); dir_node->set_writable(!is_ro); return Insert(inside, node); diff --git a/sandboxed_api/sandbox2/notify.h b/sandboxed_api/sandbox2/notify.h index 8d00a7f..0195428 100644 --- a/sandboxed_api/sandbox2/notify.h +++ b/sandboxed_api/sandbox2/notify.h @@ -21,7 +21,6 @@ #include "absl/base/attributes.h" #include "absl/log/log.h" -#include "sandboxed_api/config.h" #include "sandboxed_api/sandbox2/comms.h" #include "sandboxed_api/sandbox2/result.h" #include "sandboxed_api/sandbox2/syscall.h" diff --git a/sandboxed_api/sandbox2/notify_test.cc b/sandboxed_api/sandbox2/notify_test.cc index ad77dc8..6942f50 100644 --- a/sandboxed_api/sandbox2/notify_test.cc +++ b/sandboxed_api/sandbox2/notify_test.cc @@ -33,6 +33,7 @@ #include "sandboxed_api/sandbox2/policybuilder.h" #include "sandboxed_api/sandbox2/sandbox2.h" #include "sandboxed_api/sandbox2/syscall.h" +#include "sandboxed_api/sandbox2/trace_all_syscalls.h" #include "sandboxed_api/testing.h" namespace sandbox2 { @@ -126,5 +127,21 @@ TEST(NotifyTest, PrintPidAndComms) { EXPECT_THAT(result.reason_code(), Eq(33)); } +// Test EventSyscallTrap on personality syscall through TraceAllSyscalls +TEST(NotifyTest, TraceAllAllowPersonality) { + const std::string path = GetTestSourcePath("sandbox2/testcases/personality"); + std::vector<std::string> args = {path}; + auto policy = CreateDefaultPermissiveTestPolicy(path) + .DefaultAction(TraceAllSyscalls()) + .BuildOrDie(); + Sandbox2 s2(std::make_unique<Executor>(path, args), + NotifyTestcasePolicy(path), + std::make_unique<PersonalityNotify>(/*allow=*/true)); + auto result = s2.Run(); + + ASSERT_THAT(result.final_status(), Eq(Result::OK)); + EXPECT_THAT(result.reason_code(), Eq(22)); +} + } // namespace } // namespace sandbox2 diff --git a/sandboxed_api/sandbox2/policy.cc b/sandboxed_api/sandbox2/policy.cc index 6a4b2f4..721abcf 100644 --- a/sandboxed_api/sandbox2/policy.cc +++ b/sandboxed_api/sandbox2/policy.cc @@ -183,8 +183,9 @@ std::vector<sock_filter> Policy::GetDefaultPolicy(bool user_notif) const { policy.insert(policy.end(), { #ifdef __NR_clone3 - // Disallow clone3 - JEQ32(__NR_clone3, DENY), + // Disallow clone3. Errno instead of DENY so that libraries + // can fallback to regular clone/clone2. + JEQ32(__NR_clone3, ERRNO(ENOSYS)), #endif // Disallow clone3 and clone with unsafe flags. This uses // LOAD_SYSCALL_NR from above. diff --git a/sandboxed_api/sandbox2/policybuilder.cc b/sandboxed_api/sandbox2/policybuilder.cc index 80b42d8..6fbda54 100644 --- a/sandboxed_api/sandbox2/policybuilder.cc +++ b/sandboxed_api/sandbox2/policybuilder.cc @@ -60,6 +60,7 @@ #include "sandboxed_api/sandbox2/namespace.h" #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/syscall.h" +#include "sandboxed_api/sandbox2/trace_all_syscalls.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" #include "sandboxed_api/sandbox2/violation.pb.h" #include "sandboxed_api/util/path.h" @@ -70,6 +71,9 @@ #include <asm/termbits.h> // On PPC, TCGETS macro needs termios #endif +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0x100000 +#endif #ifndef PR_SET_VMA #define PR_SET_VMA 0x53564d41 #endif @@ -285,6 +289,7 @@ PolicyBuilder& PolicyBuilder::AllowTcMalloc() { LABEL(&labels, prot_none), ARG_32(3), // flags JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, ALLOW), + JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, ALLOW), JEQ32(MAP_ANONYMOUS | MAP_PRIVATE, ALLOW), LABEL(&labels, mmap_end), @@ -329,7 +334,7 @@ PolicyBuilder& PolicyBuilder::AllowLlvmSanitizers() { // example: // https://github.com/llvm/llvm-project/blob/596d534ac3524052df210be8d3c01a33b2260a42/compiler-rt/lib/asan/asan_allocator.cpp#L980 // https://github.com/llvm/llvm-project/blob/62ec4ac90738a5f2d209ed28c822223e58aaaeb7/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h#L98 - AllowMmap(); + AllowMmapWithoutExec(); AllowSyscall(__NR_munmap); AllowSyscall(__NR_sched_yield); @@ -359,7 +364,7 @@ PolicyBuilder& PolicyBuilder::AllowLlvmSanitizers() { OverridableBlockSyscallWithErrno(__NR_ioctl, EPERM); // https://github.com/llvm/llvm-project/blob/9aa39481d9eb718e872993791547053a3c1f16d5/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp#L150 // https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=de7edfa0928224eb8375e2fe894d6677570fbb3b;hb=HEAD#l188 - OverridableBlockSyscallWithErrno(__NR_sched_getaffinity, EPERM); + AllowSyscall(__NR_sched_getaffinity); // https://github.com/llvm/llvm-project/blob/02c2b472b510ff55679844c087b66e7837e13dc2/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L434 #ifdef __NR_readlink OverridableBlockSyscallWithErrno(__NR_readlink, ENOENT); @@ -415,6 +420,14 @@ PolicyBuilder& PolicyBuilder::AllowLimitedMadvise() { }); } +PolicyBuilder& PolicyBuilder::AllowMmapWithoutExec() { + return AddPolicyOnMmap({ + ARG_32(2), + BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, PROT_EXEC, 1, 0), + ALLOW, + }); +} + PolicyBuilder& PolicyBuilder::AllowMmap() { return AllowSyscalls(kMmapSyscalls); } @@ -760,11 +773,13 @@ PolicyBuilder& PolicyBuilder::AllowRestartableSequences( AllowFutexOp(FUTEX_WAKE); AllowRead(); AllowOpen(); + AllowPoll(); AllowSyscall(__NR_close); AddPolicyOnSyscall(__NR_rt_sigprocmask, { ARG_32(0), JEQ32(SIG_SETMASK, ALLOW), }); + AllowPrctlSetVma(); if (cpu_fence_mode == kAllowSlowFences) { AllowSyscall(__NR_sched_getaffinity); AllowSyscall(__NR_sched_setaffinity); @@ -796,6 +811,9 @@ PolicyBuilder& PolicyBuilder::AllowGetPGIDs() { } PolicyBuilder& PolicyBuilder::AllowGetRlimit() { +#ifdef __NR_prlimit64 + AddPolicyOnSyscall(__NR_prlimit64, {ARG(2), JEQ64(0, 0, ALLOW)}); +#endif return AllowSyscalls({ #ifdef __NR_getrlimit __NR_getrlimit, @@ -808,6 +826,9 @@ PolicyBuilder& PolicyBuilder::AllowGetRlimit() { PolicyBuilder& PolicyBuilder::AllowSetRlimit() { return AllowSyscalls({ +#ifdef __NR_prlimit64 + __NR_prlimit64, +#endif #ifdef __NR_setrlimit __NR_setrlimit, #endif @@ -856,7 +877,7 @@ PolicyBuilder& PolicyBuilder::AllowLogForwarding() { ARG_32(0), JEQ32(SIG_BLOCK, ALLOW), }); - AllowSyscall(__NR_prlimit64); + AllowGetRlimit(); // For LOG(FATAL) return AddPolicyOnSyscall(__NR_kill, @@ -990,14 +1011,14 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() { OverridableBlockSyscallWithErrno(__NR_readlink, ENOENT); #endif -#ifdef __NR_prlimit64 - OverridableBlockSyscallWithErrno(__NR_prlimit64, EPERM); -#endif + AllowGetRlimit(); AddPolicyOnSyscall(__NR_mprotect, { ARG_32(2), JEQ32(PROT_READ, ALLOW), }); + OverridableBlockSyscallWithErrno(__NR_sigaltstack, ENOSYS); + return *this; } @@ -1224,6 +1245,11 @@ PolicyBuilder& PolicyBuilder::DefaultAction(AllowAllSyscalls) { return *this; } +PolicyBuilder& PolicyBuilder::DefaultAction(TraceAllSyscalls) { + default_action_ = SANDBOX2_TRACE; + return *this; +} + absl::StatusOr<std::string> PolicyBuilder::ValidateAbsolutePath( absl::string_view path) { if (!file::IsAbsolutePath(path)) { diff --git a/sandboxed_api/sandbox2/policybuilder.h b/sandboxed_api/sandbox2/policybuilder.h index c832d00..5485833 100644 --- a/sandboxed_api/sandbox2/policybuilder.h +++ b/sandboxed_api/sandbox2/policybuilder.h @@ -43,6 +43,7 @@ struct bpf_labels; namespace sandbox2 { class AllowAllSyscalls; +class TraceAllSyscalls; class UnrestrictedNetworking; // PolicyBuilder is a helper class to simplify creation of policies. The builder @@ -245,20 +246,25 @@ class PolicyBuilder final { // Appends code to allow mmap. Specifically this allows mmap and mmap2 syscall // on architectures where this syscalls exist. + // Prefer using AllowMmapWithoutExec as allowing mapping executable pages + // makes exploitation easier. PolicyBuilder& AllowMmap(); + // Appends code to allow mmap calls that don't specify PROT_EXEC. + PolicyBuilder& AllowMmapWithoutExec(); + // Appends code to allow calling futex with the given operation. PolicyBuilder& AllowFutexOp(int op); // Appends code to allow opening and possibly creating files or directories. - // Allows these sycalls: + // Allows these syscalls: // - creat // - open // - openat PolicyBuilder& AllowOpen(); // Appends code to allow calling stat, fstat and lstat. - // Allows these sycalls: + // Allows these syscalls: // - fstat // - fstat64 // - fstatat @@ -313,7 +319,7 @@ class PolicyBuilder final { PolicyBuilder& AllowChown(); // Appends code to the policy to allow reading from file descriptors. - // Allows these sycalls: + // Allows these syscalls: // - read // - readv // - preadv @@ -321,7 +327,7 @@ class PolicyBuilder final { PolicyBuilder& AllowRead(); // Appends code to the policy to allow writing to file descriptors. - // Allows these sycalls: + // Allows these syscalls: // - write // - writev // - pwritev @@ -329,37 +335,37 @@ class PolicyBuilder final { PolicyBuilder& AllowWrite(); // Appends code to allow reading directories. - // Allows these sycalls: + // Allows these syscalls: // - getdents // - getdents64 PolicyBuilder& AllowReaddir(); // Appends code to allow reading symbolic links. - // Allows these sycalls: + // Allows these syscalls: // - readlink // - readlinkat PolicyBuilder& AllowReadlink(); // Appends code to allow creating links. - // Allows these sycalls: + // Allows these syscalls: // - link // - linkat PolicyBuilder& AllowLink(); // Appends code to allow creating symbolic links. - // Allows these sycalls: + // Allows these syscalls: // - symlink // - symlinkat PolicyBuilder& AllowSymlink(); // Appends code to allow creating directories. - // Allows these sycalls: + // Allows these syscalls: // - mkdir // - mkdirat PolicyBuilder& AllowMkdir(); // Appends code to allow changing file timestamps. - // Allows these sycalls: + // Allows these syscalls: // - futimens // - utime // - utimensat @@ -367,7 +373,7 @@ class PolicyBuilder final { PolicyBuilder& AllowUtime(); // Appends code to allow safe calls to fcntl. - // Allows these sycalls: + // Allows these syscalls: // - fcntl // - fcntl64 (on architectures where it exists) // @@ -377,7 +383,7 @@ class PolicyBuilder final { PolicyBuilder& AllowSafeFcntl(); // Appends code to allow creating new processes. - // Allows these sycalls: + // Allows these syscalls: // - fork // - vfork // - clone @@ -388,19 +394,19 @@ class PolicyBuilder final { PolicyBuilder& AllowFork(); // Appends code to allow waiting for processes. - // Allows these sycalls: + // Allows these syscalls: // - waitpid (on architectures where it exists) // - wait4 PolicyBuilder& AllowWait(); // Appends code to allow setting alarms / interval timers. - // Allows these sycalls: + // Allows these syscalls: // - alarm (on architectures where it exists) // - setitimer PolicyBuilder& AllowAlarm(); // Appends code to allow setting up signal handlers, returning from them, etc. - // Allows these sycalls: + // Allows these syscalls: // - rt_sigaction // - rt_sigreturn // - rt_procmask @@ -411,12 +417,12 @@ class PolicyBuilder final { PolicyBuilder& AllowHandleSignals(); // Appends code to allow doing the TCGETS ioctl. - // Allows these sycalls: + // Allows these syscalls: // - ioctl (when the first argument is TCGETS) PolicyBuilder& AllowTCGETS(); // Appends code to allow to getting the current time. - // Allows these sycalls: + // Allows these syscalls: // - time // - gettimeofday // - clock_gettime @@ -450,19 +456,19 @@ class PolicyBuilder final { PolicyBuilder& AllowGetPGIDs(); // Appends code to allow getting the rlimits. - // Allows these sycalls: + // Allows these syscalls: // - getrlimit // - ugetrlimit (on architectures where it exist) PolicyBuilder& AllowGetRlimit(); // Appends code to allow setting the rlimits. - // Allows these sycalls: + // Allows these syscalls: // - setrlimit // - usetrlimit (on architectures where it exist) PolicyBuilder& AllowSetRlimit(); // Appends code to allow reading random bytes. - // Allows these sycalls: + // Allows these syscalls: // - getrandom (with no flags or GRND_NONBLOCK) // PolicyBuilder& AllowGetRandom(); @@ -707,6 +713,12 @@ class PolicyBuilder final { // sandbox-team@ first if unsure. PolicyBuilder& DefaultAction(AllowAllSyscalls); + // Changes the default action to SANDBOX2_TRACE. + // All syscalls not handled explicitly by the policy will be passed off to + // the `sandbox2::Notify` implementation given to the `sandbox2::Sandbox2` + // instance. + PolicyBuilder& DefaultAction(TraceAllSyscalls); + ABSL_DEPRECATED("Use DefaultAction(sandbox2::AllowAllSyscalls()) instead") PolicyBuilder& DangerDefaultAllowAll(); diff --git a/sandboxed_api/sandbox2/sandbox2_test.cc b/sandboxed_api/sandbox2/sandbox2_test.cc index 8060d06..828803f 100644 --- a/sandboxed_api/sandbox2/sandbox2_test.cc +++ b/sandboxed_api/sandbox2/sandbox2_test.cc @@ -35,6 +35,7 @@ #include "absl/time/time.h" #include "sandboxed_api/config.h" #include "sandboxed_api/sandbox2/executor.h" +#include "sandboxed_api/sandbox2/fork_client.h" #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/policybuilder.h" #include "sandboxed_api/sandbox2/result.h" @@ -51,6 +52,7 @@ using ::testing::Eq; using ::testing::IsEmpty; using ::testing::IsTrue; using ::testing::Lt; +using ::testing::Ne; class Sandbox2Test : public ::testing::TestWithParam<bool> { public: @@ -195,6 +197,23 @@ TEST_P(Sandbox2Test, SandboxeeNotKilledWhenStartingThreadFinishes) { EXPECT_EQ(result.final_status(), Result::OK); } +TEST_P(Sandbox2Test, CustomForkserverWorks) { + const std::string path = GetTestSourcePath("sandbox2/testcases/custom_fork"); + std::vector<std::string> args = {path}; + auto fork_executor = std::make_unique<Executor>(path, args); + std::unique_ptr<ForkClient> fork_client = fork_executor->StartForkServer(); + ASSERT_THAT(fork_client.get(), Ne(nullptr)); + + SAPI_ASSERT_OK_AND_ASSIGN(auto policy, + CreateDefaultTestPolicy(path).TryBuild()); + + Sandbox2 sandbox(std::make_unique<Executor>(fork_client.get()), + std::move(policy)); + ASSERT_THAT(SetUpSandbox(&sandbox), IsOk()); + Result result = sandbox.Run(); + EXPECT_EQ(result.final_status(), Result::OK); +} + TEST(StarvationTest, MonitorIsNotStarvedByTheSandboxee) { const std::string path = GetTestSourcePath("sandbox2/testcases/starve"); diff --git a/sandboxed_api/sandbox2/stack_trace.cc b/sandboxed_api/sandbox2/stack_trace.cc index 2b970ad..11f9b6f 100644 --- a/sandboxed_api/sandbox2/stack_trace.cc +++ b/sandboxed_api/sandbox2/stack_trace.cc @@ -145,7 +145,7 @@ absl::StatusOr<std::unique_ptr<Policy>> StackTracePeer::GetPolicy( .AllowSyscall(__NR_recvmsg) // libunwind - .AllowMmap() + .AllowMmapWithoutExec() .AllowStat() .AllowSyscall(__NR_lseek) #ifdef __NR__llseek diff --git a/sandboxed_api/sandbox2/syscall_defs.cc b/sandboxed_api/sandbox2/syscall_defs.cc index ffbaa36..a7b41ed 100644 --- a/sandboxed_api/sandbox2/syscall_defs.cc +++ b/sandboxed_api/sandbox2/syscall_defs.cc @@ -8,6 +8,7 @@ #include <vector> #include "absl/algorithm/container.h" +#include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" @@ -18,56 +19,15 @@ namespace sandbox2 { -// Type of a given syscall argument. Used with argument conversion routines. -enum ArgType { - kGen = 1, - kInt, - kPath, - kHex, - kOct, - kSocketCall, - kSocketCallPtr, - kSignal, - kString, - kAddressFamily, - kSockaddr, - kSockmsghdr, - kCloneFlag, -}; - -// Single syscall definition -struct SyscallTable::Entry { - // Returns the number of arguments which given syscall takes. - int GetNumArgs() const { - if (num_args < 0 || num_args > syscalls::kMaxArgs) { - return syscalls::kMaxArgs; - } - return num_args; - } - - static std::string GetArgumentDescription(uint64_t value, ArgType type, - pid_t pid); - - static constexpr bool BySyscallNr(const SyscallTable::Entry& a, - const SyscallTable::Entry& b) { - return a.nr < b.nr; - } - - int nr; - absl::string_view name; - int num_args; - std::array<ArgType, syscalls::kMaxArgs> arg_types; -}; - std::string SyscallTable::Entry::GetArgumentDescription(uint64_t value, - ArgType type, + syscalls::ArgType type, pid_t pid) { std::string ret = absl::StrFormat("%#x", value); switch (type) { - case kOct: + case syscalls::kOct: absl::StrAppendFormat(&ret, " [\\0%o]", value); break; - case kPath: + case syscalls::kPath: if (auto path_or = util::ReadCPathFromPid(pid, value); path_or.ok()) { absl::StrAppendFormat(&ret, " ['%s']", absl::CHexEscape(path_or.value())); @@ -75,7 +35,7 @@ std::string SyscallTable::Entry::GetArgumentDescription(uint64_t value, absl::StrAppend(&ret, " [unreadable path]"); } break; - case kInt: + case syscalls::kInt: absl::StrAppendFormat(&ret, " [%d]", value); break; default: @@ -85,14 +45,11 @@ std::string SyscallTable::Entry::GetArgumentDescription(uint64_t value, } absl::string_view SyscallTable::GetName(int syscall) const { - auto it = absl::c_lower_bound( - data_, syscall, [](const SyscallTable::Entry& entry, int syscall) { - return entry.nr < syscall; - }); - if (it == data_.end() || it->nr != syscall) { + auto entry = GetEntry(syscall); + if (!entry.ok()) { return ""; } - return it->name; + return entry->name; } namespace { @@ -108,32 +65,61 @@ constexpr SyscallTable::Entry MakeEntry(int nr, absl::string_view name, struct UnknownArguments {}; constexpr SyscallTable::Entry MakeEntry(int nr, absl::string_view name, UnknownArguments) { - return {nr, name, -1, {kGen, kGen, kGen, kGen, kGen, kGen}}; + return {nr, + name, + -1, + {syscalls::kGen, syscalls::kGen, syscalls::kGen, syscalls::kGen, + syscalls::kGen, syscalls::kGen}}; } } // namespace -std::vector<std::string> SyscallTable::GetArgumentsDescription( - int syscall, const uint64_t values[], pid_t pid) const { - static SyscallTable::Entry kInvalidEntry = - MakeEntry(-1, "", UnknownArguments()); +absl::StatusOr<SyscallTable::Entry> SyscallTable::GetEntry(int syscall) const { auto it = absl::c_lower_bound( data_, syscall, [](const SyscallTable::Entry& entry, int syscall) { return entry.nr < syscall; }); - const auto& entry = - it != data_.end() && it->nr == syscall ? *it : kInvalidEntry; + if (it == data_.end() || it->nr != syscall) { + return absl::NotFoundError(absl::StrCat("Syscall not found: ", syscall)); + } + return *it; +} + +absl::StatusOr<SyscallTable::Entry> SyscallTable::GetEntry( + absl::string_view name) const { + // Note: There's no uniqueness guarantee of syscall names in the table, but + // other than typos it's likely safe to assume uniqueness. + auto filter = [name](const SyscallTable::Entry& entry) { + return entry.name == name; + }; + auto it = absl::c_find_if(data_, filter); + if (it != data_.end()) { + return *it; + } else { + return absl::NotFoundError(absl::StrCat("Name not found: ", name)); + } +} + +std::vector<std::string> SyscallTable::GetArgumentsDescription( + int syscall, const uint64_t values[], pid_t pid) const { + static SyscallTable::Entry kInvalidEntry = + MakeEntry(-1, "", UnknownArguments()); + auto entry = GetEntry(syscall); + if (!entry.ok()) { + entry = kInvalidEntry; + } - int num_args = entry.GetNumArgs(); + int num_args = entry->GetNumArgs(); std::vector<std::string> rv; rv.reserve(num_args); for (int i = 0; i < num_args; ++i) { rv.push_back(SyscallTable::Entry::GetArgumentDescription( - values[i], entry.arg_types[i], pid)); + values[i], entry->arg_types[i], pid)); } return rv; } +namespace syscalls { namespace { // TODO(C++20) Use std::is_sorted @@ -494,6 +480,33 @@ constexpr std::array kSyscallDataX8664 = { MakeEntry(332, "statx", kInt, kPath, kHex, kHex, kHex), MakeEntry(333, "io_pgetevents", UnknownArguments()), MakeEntry(334, "rseq", kHex, kInt, kHex, kHex), + MakeEntry(435, "clone3", kHex, kInt), + MakeEntry(436, "close_range", kInt, kInt, kHex), + MakeEntry(437, "openat2", kInt, kPath, kHex, kInt), + MakeEntry(438, "pidfd_getfd", UnknownArguments()), + MakeEntry(439, "faccessat2", kInt, kPath, kHex, kHex), + MakeEntry(440, "process_madvise", UnknownArguments()), + MakeEntry(441, "epoll_pwait2", UnknownArguments()), + MakeEntry(442, "mount_setattr", UnknownArguments()), + MakeEntry(443, "quotactl_fd", UnknownArguments()), + MakeEntry(444, "landlock_create_ruleset", UnknownArguments()), + MakeEntry(445, "landlock_add_rule", UnknownArguments()), + MakeEntry(446, "landlock_restrict_self", UnknownArguments()), + MakeEntry(447, "memfd_secret", UnknownArguments()), + MakeEntry(448, "process_mrelease", UnknownArguments()), + MakeEntry(449, "futex_waitv", UnknownArguments()), + MakeEntry(450, "set_mempolicy_home_node", UnknownArguments()), + MakeEntry(451, "cachestat", UnknownArguments()), + MakeEntry(452, "fchmodat2", kInt, kPath, kHex, kHex), + MakeEntry(453, "map_shadow_stack", UnknownArguments()), + MakeEntry(454, "futex_wake", UnknownArguments()), + MakeEntry(455, "futex_wait", UnknownArguments()), + MakeEntry(456, "futex_requeue", UnknownArguments()), + MakeEntry(457, "statmount", UnknownArguments()), + MakeEntry(458, "listmount", UnknownArguments()), + MakeEntry(459, "lsm_get_self_attr", UnknownArguments()), + MakeEntry(460, "lsm_set_self_attr", UnknownArguments()), + MakeEntry(461, "lsm_list_modules", UnknownArguments()), // clang-format on }; @@ -860,6 +873,33 @@ constexpr std::array kSyscallDataX8632 = { MakeEntry(355, "getrandom", kGen, kInt, kHex), MakeEntry(356, "memfd_create", kString, kHex), MakeEntry(357, "bpf", kInt, kHex, kInt), + MakeEntry(435, "clone3", kHex, kInt), + MakeEntry(436, "close_range", kInt, kInt, kHex), + MakeEntry(437, "openat2", kInt, kPath, kHex, kInt), + MakeEntry(438, "pidfd_getfd", UnknownArguments()), + MakeEntry(439, "faccessat2", kInt, kPath, kHex, kHex), + MakeEntry(440, "process_madvise", UnknownArguments()), + MakeEntry(441, "epoll_pwait2", UnknownArguments()), + MakeEntry(442, "mount_setattr", UnknownArguments()), + MakeEntry(443, "quotactl_fd", UnknownArguments()), + MakeEntry(444, "landlock_create_ruleset", UnknownArguments()), + MakeEntry(445, "landlock_add_rule", UnknownArguments()), + MakeEntry(446, "landlock_restrict_self", UnknownArguments()), + MakeEntry(447, "memfd_secret", UnknownArguments()), + MakeEntry(448, "process_mrelease", UnknownArguments()), + MakeEntry(449, "futex_waitv", UnknownArguments()), + MakeEntry(450, "set_mempolicy_home_node", UnknownArguments()), + MakeEntry(451, "cachestat", UnknownArguments()), + MakeEntry(452, "fchmodat2", kInt, kPath, kHex, kHex), + MakeEntry(453, "map_shadow_stack", UnknownArguments()), + MakeEntry(454, "futex_wake", UnknownArguments()), + MakeEntry(455, "futex_wait", UnknownArguments()), + MakeEntry(456, "futex_requeue", UnknownArguments()), + MakeEntry(457, "statmount", UnknownArguments()), + MakeEntry(458, "listmount", UnknownArguments()), + MakeEntry(459, "lsm_get_self_attr", UnknownArguments()), + MakeEntry(460, "lsm_set_self_attr", UnknownArguments()), + MakeEntry(461, "lsm_list_modules", UnknownArguments()), // clang-format on }; @@ -1239,6 +1279,32 @@ constexpr std::array kSyscallDataPPC64LE = { MakeEntry(379, "copy_file_range", kInt, kHex, kInt, kHex, kInt, kHex), MakeEntry(380, "preadv2", kInt, kHex, kInt, kInt, kInt, kHex), MakeEntry(381, "pwritev2", kInt, kHex, kInt, kInt, kInt, kHex), + MakeEntry(435, "clone3", kHex, kInt), + MakeEntry(436, "close_range", kInt, kInt, kHex), + MakeEntry(437, "openat2", kInt, kPath, kHex, kInt), + MakeEntry(438, "pidfd_getfd", UnknownArguments()), + MakeEntry(439, "faccessat2", kInt, kPath, kHex, kHex), + MakeEntry(440, "process_madvise", UnknownArguments()), + MakeEntry(441, "epoll_pwait2", UnknownArguments()), + MakeEntry(442, "mount_setattr", UnknownArguments()), + MakeEntry(443, "quotactl_fd", UnknownArguments()), + MakeEntry(444, "landlock_create_ruleset", UnknownArguments()), + MakeEntry(445, "landlock_add_rule", UnknownArguments()), + MakeEntry(446, "landlock_restrict_self", UnknownArguments()), + MakeEntry(448, "process_mrelease", UnknownArguments()), + MakeEntry(449, "futex_waitv", UnknownArguments()), + MakeEntry(450, "set_mempolicy_home_node", UnknownArguments()), + MakeEntry(451, "cachestat", UnknownArguments()), + MakeEntry(452, "fchmodat2", kInt, kPath, kHex, kHex), + MakeEntry(453, "map_shadow_stack", UnknownArguments()), + MakeEntry(454, "futex_wake", UnknownArguments()), + MakeEntry(455, "futex_wait", UnknownArguments()), + MakeEntry(456, "futex_requeue", UnknownArguments()), + MakeEntry(457, "statmount", UnknownArguments()), + MakeEntry(458, "listmount", UnknownArguments()), + MakeEntry(459, "lsm_get_self_attr", UnknownArguments()), + MakeEntry(460, "lsm_set_self_attr", UnknownArguments()), + MakeEntry(461, "lsm_list_modules", UnknownArguments()), // clang-format on }; @@ -1520,6 +1586,32 @@ constexpr std::array kSyscallDataArm64 = { MakeEntry(285, "copy_file_range", kInt, kHex, kInt, kHex, kInt, kHex), MakeEntry(286, "preadv2", kInt, kHex, kInt, kInt, kInt, kHex), MakeEntry(287, "pwritev2", kInt, kHex, kInt, kInt, kInt, kHex), + MakeEntry(435, "clone3", kHex, kInt), + MakeEntry(436, "close_range", kInt, kInt, kHex), + MakeEntry(437, "openat2", kInt, kPath, kHex, kInt), + MakeEntry(438, "pidfd_getfd", UnknownArguments()), + MakeEntry(439, "faccessat2", kInt, kPath, kHex, kHex), + MakeEntry(440, "process_madvise", UnknownArguments()), + MakeEntry(441, "epoll_pwait2", UnknownArguments()), + MakeEntry(442, "mount_setattr", UnknownArguments()), + MakeEntry(443, "quotactl_fd", UnknownArguments()), + MakeEntry(444, "landlock_create_ruleset", UnknownArguments()), + MakeEntry(445, "landlock_add_rule", UnknownArguments()), + MakeEntry(446, "landlock_restrict_self", UnknownArguments()), + MakeEntry(448, "process_mrelease", UnknownArguments()), + MakeEntry(449, "futex_waitv", UnknownArguments()), + MakeEntry(450, "set_mempolicy_home_node", UnknownArguments()), + MakeEntry(451, "cachestat", UnknownArguments()), + MakeEntry(452, "fchmodat2", kInt, kPath, kHex, kHex), + MakeEntry(453, "map_shadow_stack", UnknownArguments()), + MakeEntry(454, "futex_wake", UnknownArguments()), + MakeEntry(455, "futex_wait", UnknownArguments()), + MakeEntry(456, "futex_requeue", UnknownArguments()), + MakeEntry(457, "statmount", UnknownArguments()), + MakeEntry(458, "listmount", UnknownArguments()), + MakeEntry(459, "lsm_get_self_attr", UnknownArguments()), + MakeEntry(460, "lsm_set_self_attr", UnknownArguments()), + MakeEntry(461, "lsm_list_modules", UnknownArguments()), // clang-format on }; @@ -1877,6 +1969,32 @@ constexpr std::array kSyscallDataArm32 = { MakeEntry(393, "pwritev2", kInt, kHex, kInt, kInt, kInt, kHex), MakeEntry(400, "migrate_pages", kGen, kGen, kGen, kGen), MakeEntry(401, "kexec_file_load", kInt, kInt, kInt, kString, kHex), + MakeEntry(435, "clone3", kHex, kInt), + MakeEntry(436, "close_range", kInt, kInt, kHex), + MakeEntry(437, "openat2", kInt, kPath, kHex, kInt), + MakeEntry(438, "pidfd_getfd", UnknownArguments()), + MakeEntry(439, "faccessat2", kInt, kPath, kHex, kHex), + MakeEntry(440, "process_madvise", UnknownArguments()), + MakeEntry(441, "epoll_pwait2", UnknownArguments()), + MakeEntry(442, "mount_setattr", UnknownArguments()), + MakeEntry(443, "quotactl_fd", UnknownArguments()), + MakeEntry(444, "landlock_create_ruleset", UnknownArguments()), + MakeEntry(445, "landlock_add_rule", UnknownArguments()), + MakeEntry(446, "landlock_restrict_self", UnknownArguments()), + MakeEntry(448, "process_mrelease", UnknownArguments()), + MakeEntry(449, "futex_waitv", UnknownArguments()), + MakeEntry(450, "set_mempolicy_home_node", UnknownArguments()), + MakeEntry(451, "cachestat", UnknownArguments()), + MakeEntry(452, "fchmodat2", kInt, kPath, kHex, kHex), + MakeEntry(453, "map_shadow_stack", UnknownArguments()), + MakeEntry(454, "futex_wake", UnknownArguments()), + MakeEntry(455, "futex_wait", UnknownArguments()), + MakeEntry(456, "futex_requeue", UnknownArguments()), + MakeEntry(457, "statmount", UnknownArguments()), + MakeEntry(458, "listmount", UnknownArguments()), + MakeEntry(459, "lsm_get_self_attr", UnknownArguments()), + MakeEntry(460, "lsm_set_self_attr", UnknownArguments()), + MakeEntry(461, "lsm_list_modules", UnknownArguments()), MakeEntry(0xf0001, "ARM_breakpoint", kHex, kHex, kHex, kHex), MakeEntry(0xf0002, "ARM_cacheflush", kHex, kHex, kHex, kHex), MakeEntry(0xf0003, "ARM_usr26", kHex, kHex, kHex, kHex), @@ -1889,19 +2007,20 @@ static_assert(IsSorted(kSyscallDataArm32, SyscallTable::Entry::BySyscallNr), "Syscalls should be sorted"); } // namespace +} // namespace syscalls SyscallTable SyscallTable::get(sapi::cpu::Architecture arch) { switch (arch) { case sapi::cpu::kX8664: - return SyscallTable(kSyscallDataX8664); + return SyscallTable(syscalls::kSyscallDataX8664); case sapi::cpu::kX86: - return SyscallTable(kSyscallDataX8632); + return SyscallTable(syscalls::kSyscallDataX8632); case sapi::cpu::kPPC64LE: - return SyscallTable(kSyscallDataPPC64LE); + return SyscallTable(syscalls::kSyscallDataPPC64LE); case sapi::cpu::kArm64: - return SyscallTable(kSyscallDataArm64); + return SyscallTable(syscalls::kSyscallDataArm64); case sapi::cpu::kArm: - return SyscallTable(kSyscallDataArm32); + return SyscallTable(syscalls::kSyscallDataArm32); default: return SyscallTable(); } diff --git a/sandboxed_api/sandbox2/syscall_defs.h b/sandboxed_api/sandbox2/syscall_defs.h index a5e7fc3..1fbf3dc 100644 --- a/sandboxed_api/sandbox2/syscall_defs.h +++ b/sandboxed_api/sandbox2/syscall_defs.h @@ -3,10 +3,12 @@ #include <sys/types.h> +#include <array> #include <cstdint> #include <string> #include <vector> +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "sandboxed_api/config.h" @@ -17,11 +19,51 @@ namespace syscalls { constexpr int kMaxArgs = 6; +// Type of a given syscall argument. Used with argument conversion routines. +enum ArgType { + kGen = 1, + kInt, + kPath, + kHex, + kOct, + kSocketCall, + kSocketCallPtr, + kSignal, + kString, + kAddressFamily, + kSockaddr, + kSockmsghdr, + kCloneFlag, +}; + } // namespace syscalls class SyscallTable { public: - struct Entry; + // Single syscall definition + struct Entry { + // Returns the number of arguments which given syscall takes. + int GetNumArgs() const { + if (num_args < 0 || num_args > syscalls::kMaxArgs) { + return syscalls::kMaxArgs; + } + return num_args; + } + + static std::string GetArgumentDescription(uint64_t value, + syscalls::ArgType type, + pid_t pid); + + static constexpr bool BySyscallNr(const SyscallTable::Entry& a, + const SyscallTable::Entry& b) { + return a.nr < b.nr; + } + + int nr; + absl::string_view name; + int num_args; + std::array<syscalls::ArgType, syscalls::kMaxArgs> arg_types; + }; // Returns the syscall table for the architecture. static SyscallTable get(sapi::cpu::Architecture arch); @@ -34,6 +76,12 @@ class SyscallTable { const uint64_t values[], pid_t pid) const; + absl::StatusOr<Entry> GetEntry(int syscall) const; + // Returns the first entry matching the provided name. + absl::StatusOr<Entry> GetEntry(absl::string_view name) const; + + absl::Span<const Entry> GetEntries() const { return data_; } + private: constexpr SyscallTable() = default; explicit constexpr SyscallTable(absl::Span<const Entry> data) : data_(data) {} diff --git a/sandboxed_api/sandbox2/testcases/BUILD.bazel b/sandboxed_api/sandbox2/testcases/BUILD.bazel index 92cedb8..7ba8141 100644 --- a/sandboxed_api/sandbox2/testcases/BUILD.bazel +++ b/sandboxed_api/sandbox2/testcases/BUILD.bazel @@ -261,3 +261,16 @@ cc_binary( "@com_google_absl//absl/strings:string_view", ], ) + +cc_binary( + name = "custom_fork", + testonly = True, + srcs = ["custom_fork.cc"], + copts = sapi_platform_copts(), + features = ["fully_static_link"], + deps = [ + "//sandboxed_api/sandbox2:comms", + "//sandboxed_api/sandbox2:forkingclient", + "//sandboxed_api/util:raw_logging", + ], +) diff --git a/sandboxed_api/sandbox2/testcases/CMakeLists.txt b/sandboxed_api/sandbox2/testcases/CMakeLists.txt index 3dfd039..43bde70 100644 --- a/sandboxed_api/sandbox2/testcases/CMakeLists.txt +++ b/sandboxed_api/sandbox2/testcases/CMakeLists.txt @@ -322,3 +322,19 @@ target_link_libraries(sandbox2_testcase_network_proxy PRIVATE sapi::status ) +# sandboxed_api/sandbox2/testcases:custom_fork +add_executable(sandbox2_testcase_custom_fork + custom_fork.cc +) +add_executable(sandbox2::testcase_custom_fork ALIAS sandbox2_testcase_custom_fork) +set_target_properties(sandbox2_testcase_custom_fork PROPERTIES + OUTPUT_NAME custom_fork +) +target_link_libraries(sandbox2_testcase_custom_fork PRIVATE + sandbox2::comms + sandbox2::forkingclient + sapi::base + sapi::raw_logging +) + + diff --git a/sandboxed_api/sandbox2/testcases/custom_fork.cc b/sandboxed_api/sandbox2/testcases/custom_fork.cc new file mode 100644 index 0000000..3625229 --- /dev/null +++ b/sandboxed_api/sandbox2/testcases/custom_fork.cc @@ -0,0 +1,34 @@ +// Copyright 2023 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/comms.h" +#include "sandboxed_api/sandbox2/forkingclient.h" +#include "sandboxed_api/util/raw_logging.h" + +int main(int argc, char* argv[]) { + sandbox2::Comms comms(sandbox2::Comms::kDefaultConnection); + sandbox2::ForkingClient s2client(&comms); + + for (;;) { + pid_t pid = s2client.WaitAndFork(); + if (pid == -1) { + SAPI_RAW_LOG(FATAL, "Could not spawn a new sandboxee"); + } + if (pid == 0) { + // Start sandboxing here + s2client.SandboxMeHere(); + return 0; + } + } +} diff --git a/sandboxed_api/sandbox2/testcases/starve.cc b/sandboxed_api/sandbox2/testcases/starve.cc index 6903c0a..5295e76 100644 --- a/sandboxed_api/sandbox2/testcases/starve.cc +++ b/sandboxed_api/sandbox2/testcases/starve.cc @@ -40,7 +40,7 @@ int ChildFunc(void*) { int main() { for (int i = 0; i < kProcesses; ++i) { - int p[2]; + int p[2] = {0, 0}; char c = ' '; pipe(p); g_pids[i] = fork(); diff --git a/sandboxed_api/sandbox2/trace_all_syscalls.h b/sandboxed_api/sandbox2/trace_all_syscalls.h new file mode 100644 index 0000000..d387cc3 --- /dev/null +++ b/sandboxed_api/sandbox2/trace_all_syscalls.h @@ -0,0 +1,27 @@ +// Copyright 2024 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_TRACE_ALL_SYSCALLS_H_ +#define SANDBOXED_API_SANDBOX2_TRACE_ALL_SYSCALLS_H_ + +namespace sandbox2 { + +class TraceAllSyscalls { + public: + explicit TraceAllSyscalls() = default; +}; + +} // namespace sandbox2 + +#endif // SANDBOXED_API_SANDBOX2_ALLOW_ALL_SYSCALLS_H_ diff --git a/sandboxed_api/sandbox2/util/BUILD.bazel b/sandboxed_api/sandbox2/util/BUILD.bazel index 86cc785..89bc522 100644 --- a/sandboxed_api/sandbox2/util/BUILD.bazel +++ b/sandboxed_api/sandbox2/util/BUILD.bazel @@ -32,8 +32,6 @@ cc_library( name = "bpf_helper", srcs = ["bpf_helper.c"], hdrs = ["bpf_helper.h"], - copts = sapi_platform_copts([ - ]), visibility = ["//visibility:public"], ) diff --git a/sandboxed_api/sapi_test.cc b/sandboxed_api/sapi_test.cc index 5f66f2c..6aa25ab 100644 --- a/sandboxed_api/sapi_test.cc +++ b/sandboxed_api/sapi_test.cc @@ -284,5 +284,24 @@ TEST(SandboxTest, NoRaceInConcurrentTerminate) { EXPECT_THAT(result.final_status(), Eq(sandbox2::Result::EXTERNAL_KILL)); } +TEST(SandboxTest, UseUnotifyMonitor) { + SumSandbox sandbox; + ASSERT_THAT(sandbox.Init(/*use_unotify_monitor=*/true), IsOk()); + SumApi api(&sandbox); + + // Violate the sandbox policy. + EXPECT_THAT(api.violate(), StatusIs(absl::StatusCode::kUnavailable)); + EXPECT_THAT(api.sum(1, 2).status(), StatusIs(absl::StatusCode::kUnavailable)); + EXPECT_THAT(sandbox.AwaitResult().final_status(), + Eq(sandbox2::Result::VIOLATION)); + + // Restart the sandbox. + ASSERT_THAT(sandbox.Restart(false), IsOk()); + + // The sandbox should now be responsive again. + SAPI_ASSERT_OK_AND_ASSIGN(int result, api.sum(1, 2)); + EXPECT_THAT(result, Eq(3)); +} + } // namespace } // namespace sapi diff --git a/sandboxed_api/tools/generator2/code_test.py b/sandboxed_api/tools/generator2/code_test.py index de74485..8ef6057 100644 --- a/sandboxed_api/tools/generator2/code_test.py +++ b/sandboxed_api/tools/generator2/code_test.py @@ -89,7 +89,7 @@ class CodeAnalysisTest(parameterized.TestCase): if x.kind != cindex.CursorKind.MACRO_DEFINITION ] self.assertListEqual(cursor_kinds, [ - cindex.CursorKind.TRANSLATION_UNIT, cindex.CursorKind.UNEXPOSED_DECL, + cindex.CursorKind.TRANSLATION_UNIT, cindex.CursorKind.LINKAGE_SPEC, cindex.CursorKind.FUNCTION_DECL, cindex.CursorKind.PARM_DECL ]) diff --git a/sandboxed_api/var_ptr.h b/sandboxed_api/var_ptr.h index ad2568c..2c9894f 100644 --- a/sandboxed_api/var_ptr.h +++ b/sandboxed_api/var_ptr.h @@ -20,6 +20,7 @@ #include <memory> #include <string> +#include "absl/base/attributes.h" #include "absl/base/macros.h" #include "absl/strings/str_format.h" #include "sandboxed_api/var_abstract.h" @@ -79,7 +80,9 @@ class Ptr : public Reg<Var*> { }; // Good, old nullptr -class NullPtr : public Ptr { +class ABSL_DEPRECATED( + "Use regular `nullptr` or `NULL` instead. This class will eventually get " + "removed") NullPtr : public Ptr { public: NullPtr() : Ptr(&void_obj_, SyncType::kSyncNone) {} |