// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sandbox/mac/seatbelt.h"
#include <errno.h>
#include <unistd.h>
extern "C" {
#include <sandbox.h>
int sandbox_init_with_parameters(const char* profile,
uint64_t flags,
const char* const parameters[],
char** errorbuf);
// Not deprecated. The canonical usage to test if sandboxed is
// sandbox_check(getpid(), NULL, SANDBOX_FILTER_NONE), which returns
// 1 if sandboxed. Note `type` is actually a sandbox_filter_type enum value, but
// it is unused currently.
int sandbox_check(pid_t pid, const char* operation, int type, ...);
struct sandbox_params_t {
const char** params;
size_t size;
size_t available;
};
sandbox_params_t* sandbox_create_params();
int sandbox_set_param(sandbox_params_t*, const char* key, const char* value);
void sandbox_free_params(sandbox_params_t*);
struct sandbox_profile_t {
char* builtin;
const uint8_t* data;
size_t size;
};
sandbox_profile_t* sandbox_compile_string(const char* data,
sandbox_params_t*,
char** error);
int sandbox_apply(sandbox_profile_t*);
void sandbox_free_profile(sandbox_profile_t*);
} // extern "C"
namespace sandbox {
namespace {
bool HandleSandboxResult(int rv, char* errorbuf, std::string* error) {
if (rv == 0) {
if (error)
error->clear();
return true;
}
if (error)
*error = errorbuf;
Seatbelt::FreeError(errorbuf);
return false;
}
bool HandleSandboxErrno(int rv, const char* message, std::string* error) {
if (rv == 0) {
if (error)
error->clear();
return true;
}
if (error) {
char* perror = strerror(errno);
error->assign(message);
error->append(perror);
}
return false;
}
} // namespace
// static
Seatbelt::Parameters Seatbelt::Parameters::Create() {
Parameters params;
params.params_ = ::sandbox_create_params();
return params;
}
Seatbelt::Parameters::Parameters() = default;
Seatbelt::Parameters::Parameters(Seatbelt::Parameters&& other) {
params_ = std::exchange(other.params_, nullptr);
}
Seatbelt::Parameters& Seatbelt::Parameters::operator=(
Seatbelt::Parameters&& other) {
params_ = std::exchange(other.params_, nullptr);
return *this;
}
bool Seatbelt::Parameters::Set(const char* key, const char* value) {
return ::sandbox_set_param(params_, key, value) == 0;
}
Seatbelt::Parameters::~Parameters() {
if (params_) {
::sandbox_free_params(params_);
}
}
// Initialize the static member variables.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
const char* Seatbelt::kProfilePureComputation = kSBXProfilePureComputation;
#pragma clang diagnostic pop
// static
bool Seatbelt::Init(const char* profile, uint64_t flags, std::string* error) {
// OS X deprecated these functions, but did not provide a suitable replacement,
// so ignore the deprecation warning.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
char* errorbuf = nullptr;
int rv = ::sandbox_init(profile, flags, &errorbuf);
return HandleSandboxResult(rv, errorbuf, error);
#pragma clang diagnostic pop
}
// static
bool Seatbelt::InitWithParams(const char* profile,
uint64_t flags,
const char* const parameters[],
std::string* error) {
char* errorbuf = nullptr;
int rv =
::sandbox_init_with_parameters(profile, flags, parameters, &errorbuf);
return HandleSandboxResult(rv, errorbuf, error);
}
// static
bool Seatbelt::Compile(const char* profile,
const Seatbelt::Parameters& params,
std::string& compiled_profile,
std::string* error) {
char* errorbuf = nullptr;
sandbox_profile_t* sandbox_profile =
::sandbox_compile_string(profile, params.params(), &errorbuf);
if (!HandleSandboxResult(sandbox_profile ? 0 : -1, errorbuf, error)) {
return false;
}
compiled_profile.assign(reinterpret_cast<const char*>(sandbox_profile->data),
sandbox_profile->size);
::sandbox_free_profile(sandbox_profile);
return true;
}
// static
bool Seatbelt::ApplyCompiledProfile(const std::string& profile,
std::string* error) {
sandbox_profile_t sbox_profile = {
.builtin = nullptr,
.data = reinterpret_cast<const uint8_t*>(profile.data()),
.size = profile.size()};
return HandleSandboxErrno(::sandbox_apply(&sbox_profile),
"sandbox_apply: ", error);
}
// static
void Seatbelt::FreeError(char* errorbuf) {
// OS X deprecated these functions, but did not provide a suitable replacement,
// so ignore the deprecation warning.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return ::sandbox_free_error(errorbuf);
#pragma clang diagnostic pop
}
// static
bool Seatbelt::IsSandboxed() {
return ::sandbox_check(getpid(), NULL, 0);
}
} // namespace sandbox