Commit 7ea6cf78 authored by Greg Kerr's avatar Greg Kerr Committed by Commit Bot

macOS V2 Sandbox: Send serialized seatbelt profile in a loop.

In some cases, and on user's machines per bug reports, writev() performs
a short write. The child process receives an invalid profile and tabs
fail to launch. This switches to using a sequence of write() calls to
send the buffer length, and then send the buffer in a loop.

Bug: 801889
Change-Id: Ib1f4c57c61d3ce68b875b347de480f514100d3c2
Reviewed-on: https://chromium-review.googlesource.com/920765Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: Greg Kerr <kerrnel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537360}
parent b7d3a7d9
...@@ -65,7 +65,7 @@ int SeatbeltExecClient::SendProfileAndGetFD() { ...@@ -65,7 +65,7 @@ int SeatbeltExecClient::SendProfileAndGetFD() {
return -1; return -1;
} }
if (!WriteString(&serialized_protobuf)) { if (!WriteString(serialized_protobuf)) {
logging::Error( logging::Error(
"SeatbeltExecClient: Writing the serialized profile failed."); "SeatbeltExecClient: Writing the serialized profile failed.");
return -1; return -1;
...@@ -80,25 +80,28 @@ int SeatbeltExecClient::SendProfileAndGetFD() { ...@@ -80,25 +80,28 @@ int SeatbeltExecClient::SendProfileAndGetFD() {
return pipe_[0]; return pipe_[0];
} }
bool SeatbeltExecClient::WriteString(std::string* str) { bool SeatbeltExecClient::WriteString(const std::string& str) {
struct iovec iov[1]; uint64_t str_len = static_cast<uint64_t>(str.size());
iov[0].iov_base = &(*str)[0];
iov[0].iov_len = str->size();
ssize_t written = HANDLE_EINTR(writev(pipe_[1], iov, arraysize(iov))); if (HANDLE_EINTR(write(pipe_[1], &str_len, sizeof(str_len))) !=
if (written < 0) { sizeof(str_len)) {
logging::PError("SeatbeltExecClient: writev failed"); logging::PError("SeatbeltExecClient: write size of buffer failed");
return false; return false;
} }
bool write_complete = static_cast<uint64_t>(written) == str->size(); uint64_t bytes_written = 0;
if (!write_complete) {
logging::Error("SeatbeltExecClient: short writev(). written: %" PRIu64 while (bytes_written < str_len) {
", str->size(): %" PRIu64 "", ssize_t wrote_this_pass = HANDLE_EINTR(
static_cast<uint64_t>(written), str->size()); write(pipe_[1], &str[bytes_written], str_len - bytes_written));
if (wrote_this_pass < 0) {
logging::PError("SeatbeltExecClient: write failed");
return false;
}
bytes_written += wrote_this_pass;
} }
return write_complete; return true;
} }
SeatbeltExecServer::SeatbeltExecServer(int fd) : fd_(fd), extra_params_() {} SeatbeltExecServer::SeatbeltExecServer(int fd) : fd_(fd), extra_params_() {}
...@@ -147,19 +150,27 @@ bool SeatbeltExecServer::ApplySandboxProfile(const mac::SandboxPolicy& policy) { ...@@ -147,19 +150,27 @@ bool SeatbeltExecServer::ApplySandboxProfile(const mac::SandboxPolicy& policy) {
} }
bool SeatbeltExecServer::ReadString(std::string* str) { bool SeatbeltExecServer::ReadString(std::string* str) {
// 4 pages of memory is enough to hold the sandbox profiles. uint64_t buf_len = 0;
std::vector<char> buffer(4096 * 4, '\0'); if (HANDLE_EINTR(read(fd_, &buf_len, sizeof(buf_len))) != sizeof(buf_len)) {
logging::PError("SeatbeltExecServer: read buffer length failed");
return false;
}
struct iovec iov[1]; str->clear();
iov[0].iov_base = buffer.data(); str->resize(buf_len);
iov[0].iov_len = buffer.size();
ssize_t read_length = HANDLE_EINTR(readv(fd_, iov, arraysize(iov))); uint64_t bytes_read = 0;
if (read_length < 0) {
logging::PError("SeatbeltExecServer: readv failed"); while (bytes_read < buf_len) {
return false; ssize_t read_this_pass =
HANDLE_EINTR(read(fd_, &(*str)[bytes_read], buf_len - bytes_read));
if (read_this_pass < 0) {
logging::PError("SeatbeltExecServer: read failed");
return false;
}
bytes_read += read_this_pass;
} }
str->assign(buffer.data());
return true; return true;
} }
......
...@@ -45,7 +45,7 @@ class SEATBELT_EXPORT SeatbeltExecClient { ...@@ -45,7 +45,7 @@ class SEATBELT_EXPORT SeatbeltExecClient {
private: private:
// This writes a string (the serialized protobuf) to the |pipe_|. // This writes a string (the serialized protobuf) to the |pipe_|.
bool WriteString(std::string* str); bool WriteString(const std::string& str);
// This is the protobuf which contains the sandbox profile and parameters, // This is the protobuf which contains the sandbox profile and parameters,
// and is serialized and sent to the other process. // and is serialized and sent to the other process.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment