sandboxed-api/sandboxed_api/sandbox2/executor.cc
Wiktor Garbacz b258535161 Treat libunwind sandbox as a ~regular sandboxee
This removes dependency on unwind from forkserver,
which should reduce binary size for all the custom forkservers (also the SAPI generated ones).
Unwind was only ever used by the global forkserver anyhow

PiperOrigin-RevId: 557921074
Change-Id: Iea4904da0506fee5a00f970538f512cba7b02326
2023-08-17 13:32:44 -07:00

194 lines
6.2 KiB
C++

// Copyright 2019 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.
// Implementation of the sandbox2::Executor class
#include "sandboxed_api/sandbox2/executor.h"
#include <fcntl.h>
#include <libgen.h>
#include <sys/socket.h>
#include <unistd.h>
#include <climits>
#include <cstddef>
#include <memory>
#include <string_view>
#include "absl/status/status.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "sandboxed_api/config.h"
#include "sandboxed_api/sandbox2/fork_client.h"
#include "sandboxed_api/sandbox2/forkserver.pb.h"
#include "sandboxed_api/sandbox2/global_forkclient.h"
#include "sandboxed_api/sandbox2/ipc.h"
#include "sandboxed_api/sandbox2/util.h"
#include "sandboxed_api/util/fileops.h"
#include "sandboxed_api/util/raw_logging.h"
namespace sandbox2 {
namespace file_util = ::sapi::file_util;
namespace {
void DisableCompressStackDepot(ForkRequest& request) {
auto disable_compress_stack_depot = [&request](absl::string_view sanitizer) {
auto prefix = absl::StrCat(sanitizer, "_OPTIONS=");
auto it = std::find_if(request.mutable_envs()->begin(),
request.mutable_envs()->end(),
[&prefix](const std::string& env) {
return absl::StartsWith(env, prefix);
});
constexpr absl::string_view option = "compress_stack_depot=0";
if (it != request.mutable_envs()->end()) {
// If it's already there, the last value will be used.
absl::StrAppend(&*it, ":", option);
return;
}
request.add_envs(absl::StrCat(prefix, option));
};
if constexpr (sapi::sanitizers::IsASan()) {
disable_compress_stack_depot("ASAN");
}
if constexpr (sapi::sanitizers::IsMSan()) {
disable_compress_stack_depot("MSAN");
}
if constexpr (sapi::sanitizers::IsLSan()) {
disable_compress_stack_depot("LSAN");
}
if constexpr (sapi::sanitizers::IsHwASan()) {
disable_compress_stack_depot("HWSAN");
}
if constexpr (sapi::sanitizers::IsTSan()) {
disable_compress_stack_depot("TSAN");
}
}
} // namespace
std::vector<std::string> Executor::CopyEnviron() {
return util::CharPtrArray(environ).ToStringVector();
}
absl::StatusOr<SandboxeeProcess> Executor::StartSubProcess(int32_t clone_flags,
const Namespace* ns,
MonitorType type) {
if (started_) {
return absl::FailedPreconditionError(
"This executor has already been started");
}
if (!path_.empty()) {
exec_fd_ = file_util::fileops::FDCloser(open(path_.c_str(), O_PATH));
if (exec_fd_.get() < 0) {
if (errno == ENOENT) {
return absl::ErrnoToStatus(errno, path_);
}
return absl::ErrnoToStatus(errno,
absl::StrCat("Could not open file ", path_));
}
}
if (libunwind_sbox_for_pid_ != 0) {
VLOG(1) << "StartSubProcces, starting libunwind";
} else if (exec_fd_.get() < 0) {
VLOG(1) << "StartSubProcess, with [Fork-Server]";
} else if (!path_.empty()) {
VLOG(1) << "StartSubProcess, with file " << path_;
} else {
VLOG(1) << "StartSubProcess, with fd " << exec_fd_.get();
}
ForkRequest request;
*request.mutable_args() = {argv_.begin(), argv_.end()};
*request.mutable_envs() = {envp_.begin(), envp_.end()};
// Add LD_ORIGIN_PATH to envs, as it'll make the amount of syscalls invoked by
// ld.so smaller.
if (!path_.empty()) {
request.add_envs(absl::StrCat("LD_ORIGIN_PATH=",
file_util::fileops::StripBasename(path_)));
}
// Disable optimization to avoid related syscalls.
if constexpr (sapi::sanitizers::IsAny()) {
DisableCompressStackDepot(request);
}
// If neither the path, nor exec_fd is specified, just assume that we need to
// send a fork request.
//
// Otherwise, it's either sandboxing pre- or post-execve with the global
// Fork-Server.
if (exec_fd_.get() == -1) {
request.set_mode(FORKSERVER_FORK);
} else if (enable_sandboxing_pre_execve_) {
request.set_mode(FORKSERVER_FORK_EXECVE_SANDBOX);
} else {
request.set_mode(FORKSERVER_FORK_EXECVE);
}
if (ns) {
clone_flags |= ns->clone_flags();
*request.mutable_mount_tree() = ns->mounts().GetMountTree();
request.set_hostname(ns->hostname());
request.set_allow_mount_propagation(ns->allow_mount_propagation());
}
request.set_clone_flags(clone_flags);
request.set_monitor_type(type);
SandboxeeProcess process;
if (fork_client_) {
process = fork_client_->SendRequest(request, exec_fd_.get(),
client_comms_fd_.get());
} else {
process = GlobalForkClient::SendRequest(request, exec_fd_.get(),
client_comms_fd_.get());
}
started_ = true;
client_comms_fd_.Close();
exec_fd_.Close();
VLOG(1) << "StartSubProcess returned with: " << process.main_pid;
return process;
}
std::unique_ptr<ForkClient> Executor::StartForkServer() {
// This flag is set explicitly to 'true' during object instantiation, and
// custom fork-servers should never be sandboxed.
set_enable_sandbox_before_exec(false);
absl::StatusOr<SandboxeeProcess> process = StartSubProcess(0);
if (!process.ok()) {
return nullptr;
}
return std::make_unique<ForkClient>(process->main_pid, ipc_.comms());
}
void Executor::SetUpServerSideCommsFd() {
int sv[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
PLOG(FATAL) << "socketpair(AF_UNIX, SOCK_STREAM) failed";
}
client_comms_fd_ = file_util::fileops::FDCloser(sv[0]);
ipc_.SetUpServerSideComms(sv[1]);
}
} // namespace sandbox2