blob: 52af21e1b2956c4a19ffb2115a375f49ebd06cee [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sandbox/mac/seatbelt_exec.h"
#include <stdarg.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#include <vector>
#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "sandbox/mac/sandbox_logging.h"
#include "sandbox/mac/seatbelt.h"
namespace sandbox {
SeatbeltExecClient::SeatbeltExecClient() {
if (pipe(pipe_) != 0)
logging::PFatal("SeatbeltExecClient: pipe failed");
}
SeatbeltExecClient::~SeatbeltExecClient() {
if (pipe_[1] != -1)
IGNORE_EINTR(close(pipe_[1]));
// If pipe() fails, PCHECK() will be hit in the constructor, so this file
// descriptor should always be closed if the proess is alive at this point.
IGNORE_EINTR(close(pipe_[0]));
}
bool SeatbeltExecClient::SetBooleanParameter(const std::string& key,
bool value) {
google::protobuf::MapPair<std::string, std::string> pair(
key, value ? "TRUE" : "FALSE");
return policy_.mutable_params()->insert(pair).second;
}
bool SeatbeltExecClient::SetParameter(const std::string& key,
const std::string& value) {
google::protobuf::MapPair<std::string, std::string> pair(key, value);
return policy_.mutable_params()->insert(pair).second;
}
void SeatbeltExecClient::SetProfile(const std::string& policy) {
policy_.set_profile(policy);
}
int SeatbeltExecClient::SendProfileAndGetFD() {
std::string serialized_protobuf;
if (!policy_.SerializeToString(&serialized_protobuf))
return -1;
if (!WriteString(&serialized_protobuf))
return -1;
IGNORE_EINTR(close(pipe_[1]));
pipe_[1] = -1;
return pipe_[0];
}
bool SeatbeltExecClient::WriteString(std::string* str) {
struct iovec iov[1];
iov[0].iov_base = &(*str)[0];
iov[0].iov_len = str->size();
ssize_t written = HANDLE_EINTR(writev(pipe_[1], iov, arraysize(iov)));
if (written < 0) {
logging::PError("SeatbeltExecClient: writev failed");
return false;
}
return static_cast<uint64_t>(written) == str->size();
}
SeatbeltExecServer::SeatbeltExecServer(int fd) : fd_(fd), extra_params_() {}
SeatbeltExecServer::~SeatbeltExecServer() {
close(fd_);
}
bool SeatbeltExecServer::InitializeSandbox() {
std::string policy_string;
if (!ReadString(&policy_string))
return false;
mac::SandboxPolicy policy;
if (!policy.ParseFromString(policy_string)) {
logging::Error("SeatbeltExecServer: ParseFromString failed");
return false;
}
return ApplySandboxProfile(policy);
}
bool SeatbeltExecServer::ApplySandboxProfile(const mac::SandboxPolicy& policy) {
std::vector<const char*> weak_params;
for (const auto& pair : policy.params()) {
weak_params.push_back(pair.first.c_str());
weak_params.push_back(pair.second.c_str());
}
for (const auto& pair : extra_params_) {
weak_params.push_back(pair.first.c_str());
weak_params.push_back(pair.second.c_str());
}
weak_params.push_back(nullptr);
char* error = nullptr;
int rv = Seatbelt::InitWithParams(policy.profile().c_str(), 0,
weak_params.data(), &error);
if (error) {
logging::Error("SeatbeltExecServer: Failed to initialize sandbox: %d %s",
rv, error);
Seatbelt::FreeError(error);
return false;
}
return rv == 0;
}
bool SeatbeltExecServer::ReadString(std::string* str) {
// 4 pages of memory is enough to hold the sandbox profiles.
std::vector<char> buffer(4096 * 4, '\0');
struct iovec iov[1];
iov[0].iov_base = buffer.data();
iov[0].iov_len = buffer.size();
ssize_t read_length = HANDLE_EINTR(readv(fd_, iov, arraysize(iov)));
if (read_length < 0) {
logging::PError("SeatbeltExecServer: readv failed");
return false;
}
str->assign(buffer.data());
return true;
}
bool SeatbeltExecServer::SetParameter(const std::string& key,
const std::string& value) {
return extra_params_.insert(std::make_pair(key, value)).second;
}
} // namespace sandbox