Use sandboxed libunwind also with sanitizers

PiperOrigin-RevId: 610710893
Change-Id: Iea2c103e88a848b40c5c5cbf3c9f6b9d7bf166db
This commit is contained in:
Wiktor Garbacz 2024-02-27 04:35:44 -08:00 committed by Copybara-Service
parent 2cacad6008
commit 2430bc8ae8
3 changed files with 36 additions and 18 deletions

View File

@ -66,6 +66,10 @@ namespace {
namespace file = ::sapi::file; namespace file = ::sapi::file;
namespace file_util = ::sapi::file_util; namespace file_util = ::sapi::file_util;
// Use a fake pid so that /proc/{pid}/maps etc. also exist in the new pid
// namespace
constexpr int kFakePid = 1;
// Similar to GetStackTrace() but without using the sandbox to isolate // Similar to GetStackTrace() but without using the sandbox to isolate
// libunwind. // libunwind.
absl::StatusOr<std::vector<std::string>> UnsafeGetStackTrace(pid_t pid) { absl::StatusOr<std::vector<std::string>> UnsafeGetStackTrace(pid_t pid) {
@ -92,9 +96,9 @@ bool IsSameFile(const std::string& path, const std::string& other) {
class StackTracePeer { class StackTracePeer {
public: public:
static absl::StatusOr<std::unique_ptr<Policy>> GetPolicy( static absl::StatusOr<std::unique_ptr<Policy>> GetPolicy(
pid_t target_pid, const std::string& maps_file, const std::string& maps_file, const std::string& app_path,
const std::string& app_path, const std::string& exe_path, const std::string& exe_path, const Namespace* ns,
const Namespace* ns, bool uses_custom_forkserver); bool uses_custom_forkserver);
static absl::StatusOr<std::vector<std::string>> LaunchLibunwindSandbox( static absl::StatusOr<std::vector<std::string>> LaunchLibunwindSandbox(
const Regs* regs, const Namespace* ns, bool uses_custom_forkserver, const Regs* regs, const Namespace* ns, bool uses_custom_forkserver,
@ -102,7 +106,7 @@ class StackTracePeer {
}; };
absl::StatusOr<std::unique_ptr<Policy>> StackTracePeer::GetPolicy( absl::StatusOr<std::unique_ptr<Policy>> StackTracePeer::GetPolicy(
pid_t target_pid, const std::string& maps_file, const std::string& app_path, const std::string& maps_file, const std::string& app_path,
const std::string& exe_path, const Namespace* ns, const std::string& exe_path, const Namespace* ns,
bool uses_custom_forkserver) { bool uses_custom_forkserver) {
PolicyBuilder builder; PolicyBuilder builder;
@ -169,14 +173,15 @@ absl::StatusOr<std::unique_ptr<Policy>> StackTracePeer::GetPolicy(
// Add proc maps. // Add proc maps.
.AddFileAt(maps_file, .AddFileAt(maps_file,
file::JoinPath("/proc", absl::StrCat(target_pid), "maps")) file::JoinPath("/proc", absl::StrCat(kFakePid), "maps"))
.AddFileAt(maps_file, .AddFileAt(maps_file,
file::JoinPath("/proc", absl::StrCat(target_pid), "task", file::JoinPath("/proc", absl::StrCat(kFakePid), "task",
absl::StrCat(target_pid), "maps")) absl::StrCat(kFakePid), "maps"))
// Add the binary itself. // Add the binary itself.
.AddFileAt(exe_path, app_path) .AddFileAt(exe_path, app_path)
.AllowLlvmCoverage(); .AllowLlvmCoverage()
.AllowLlvmSanitizers();
return builder.TryBuild(); return builder.TryBuild();
} }
@ -261,8 +266,8 @@ absl::StatusOr<std::vector<std::string>> StackTracePeer::LaunchLibunwindSandbox(
// forkserver). // forkserver).
SAPI_ASSIGN_OR_RETURN( SAPI_ASSIGN_OR_RETURN(
std::unique_ptr<Policy> policy, std::unique_ptr<Policy> policy,
StackTracePeer::GetPolicy(pid, unwind_temp_maps_path, app_path, exe_path, StackTracePeer::GetPolicy(unwind_temp_maps_path, app_path, exe_path, ns,
ns, uses_custom_forkserver)); uses_custom_forkserver));
VLOG(1) << "Running libunwind sandbox"; VLOG(1) << "Running libunwind sandbox";
auto sandbox = auto sandbox =
@ -270,7 +275,7 @@ absl::StatusOr<std::vector<std::string>> StackTracePeer::LaunchLibunwindSandbox(
Comms* comms = sandbox->comms(); Comms* comms = sandbox->comms();
UnwindSetup msg; UnwindSetup msg;
msg.set_pid(pid); msg.set_pid(kFakePid);
msg.set_regs(reinterpret_cast<const char*>(&regs->user_regs_), msg.set_regs(reinterpret_cast<const char*>(&regs->user_regs_),
sizeof(regs->user_regs_)); sizeof(regs->user_regs_));
msg.set_default_max_frames(kDefaultMaxFrames); msg.set_default_max_frames(kDefaultMaxFrames);
@ -330,13 +335,6 @@ absl::StatusOr<std::vector<std::string>> GetStackTrace(
return UnsafeGetStackTrace(regs->pid()); return UnsafeGetStackTrace(regs->pid());
} }
// Show a warning if sandboxed libunwind is requested but we're running in
// a sanitizer build (= we can't use sandboxed libunwind).
if (sapi::sanitizers::IsAny()) {
LOG(WARNING) << "Sanitizer build, using non-sandboxed libunwind";
return UnsafeGetStackTrace(regs->pid());
}
return StackTracePeer::LaunchLibunwindSandbox( return StackTracePeer::LaunchLibunwindSandbox(
regs, ns, uses_custom_forkserver, recursion_depth); regs, ns, uses_custom_forkserver, recursion_depth);
} }

View File

@ -331,6 +331,13 @@ INSTANTIATE_TEST_SUITE_P(
.final_status = Result::VIOLATION, .final_status = Result::VIOLATION,
.function_name = "ViolatePolicy", .function_name = "ViolatePolicy",
.full_function_description = "ViolatePolicy(int)", .full_function_description = "ViolatePolicy(int)",
},
TestCase{
.testname = "ViolatePolicyForked",
.testno = 5,
.final_status = Result::VIOLATION,
.function_name = "ViolatePolicy",
.full_function_description = "ViolatePolicy(int)",
}), }),
[](const ::testing::TestParamInfo<TestCase>& info) { [](const ::testing::TestParamInfo<TestCase>& info) {
return info.param.testname; return info.param.testname;

View File

@ -80,6 +80,19 @@ void RunTest(int testno) {
case 4: case 4:
SleepForXSeconds(10); SleepForXSeconds(10);
break; break;
case 5: {
constexpr int kMaxForks = 16;
for (int i = 0; i < kMaxForks; ++i) {
if (fork() == 0) {
if (i == kMaxForks - 1) {
ViolatePolicy();
}
break;
}
}
SleepForXSeconds(10);
break;
}
default: default:
SAPI_RAW_LOG(FATAL, "Unknown test case: %d", testno); SAPI_RAW_LOG(FATAL, "Unknown test case: %d", testno);
} }