Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: chrome/browser/renderer_host/render_sandbox_host_linux.cc

Issue 112074: Linux: Add support for chrooted renderers. (Closed)
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/renderer_host/render_sandbox_host_linux.cc
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
new file mode 100644
index 0000000000000000000000000000000000000000..13d96a80556fbb24869fb6a05033256dc9e77cc1
--- /dev/null
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
@@ -0,0 +1,257 @@
+// Copyright (c) 2009 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 "chrome/browser/renderer_host/render_sandbox_host_linux.h"
+
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/process_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+
+#include "SkFontHost_fontconfig_direct.h"
+#include "SkFontHost_fontconfig_ipc.h"
+
+// http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
+
+// BEWARE: code in this file run across *processes* (not just threads).
+
+// This code runs in a child process
+class SandboxIPCProcess {
+ public:
+ // lifeline_fd: this is the read end of a pipe which the browser process
+ // holds the other end of. If the browser process dies, it's descriptors are
+ // closed and we will noticed an EOF on the pipe. That's our signal to exit.
+ // browser_socket: the 'browser's end of the sandbox IPC socketpair. From the
+ // point of view of the renderer's, it's talking to the browser but this
+ // object actually services the requests.
+ SandboxIPCProcess(int lifeline_fd, int browser_socket)
+ : lifeline_fd_(lifeline_fd),
+ browser_socket_(browser_socket),
+ font_config_(new FontConfigDirect()) {
+ base::InjectiveMultimap multimap;
+ multimap.push_back(base::InjectionArc(0, lifeline_fd, false));
+ multimap.push_back(base::InjectionArc(0, browser_socket, false));
+
+ base::CloseSuperfluousFds(multimap);
+ }
+
+ void Run() {
+ const int epollfd = epoll_create(2);
+ CHECK(epollfd >= 0);
+ struct epoll_event ev;
+
+ ev.events = EPOLLIN;
+ ev.data.fd = lifeline_fd_;
+ CHECK(0 == epoll_ctl(epollfd, EPOLL_CTL_ADD, lifeline_fd_, &ev));
+
+ ev.events = EPOLLIN;
+ ev.data.fd = browser_socket_;
+ CHECK(0 == epoll_ctl(epollfd, EPOLL_CTL_ADD, browser_socket_, &ev));
+
+ for (;;) {
+ CHECK(1 == HANDLE_EINTR(epoll_wait(epollfd, &ev, 1, -1)));
+ if (ev.data.fd == lifeline_fd_) {
+ // our parent died so we should too.
+ _exit(0);
+ } else {
+ CHECK(ev.data.fd == browser_socket_);
+ HandleRequest(browser_socket_);
+ }
+ }
+ }
+
+ void HandleRequest(int fd) {
+ struct msghdr msg = {0};
+ struct iovec iov;
+ uint8_t buf[1024];
+ uint8_t control_buf[CMSG_SPACE(sizeof(int))];
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control_buf;
+ msg.msg_controllen = sizeof(control_buf);
+
+ const ssize_t n = HANDLE_EINTR(recvmsg(fd, &msg, 0));
+
+ if (n < 1) {
+ LOG(ERROR) << "Error reading from sandbox IPC socket. Sandbox IPC is"
+ << " disabled."
+ << " n:" << n
+ << " errno:" << errno;
+ _exit(1);
+ return;
+ }
+
+ if (msg.msg_controllen != sizeof(control_buf) ||
+ n < static_cast<ssize_t>(sizeof(uint16_t)) ||
+ msg.msg_flags) {
+ LOG(ERROR) << "Sandbox IPC: missing control message or truncated message:"
+ << " n:" << n
+ << " msg.msg_controllen:" << msg.msg_controllen
+ << " msg.msg_flags:" << msg.msg_flags;
+ return;
+ }
+
+ // Get the reply socket from the control message
+ int reply_fd = -1;
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ // The client cannot send us additional descriptors because the control
+ // message buffer is only sized for a single int.
+ reply_fd = *reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ } else {
+ LOG(ERROR) << "Sandbox IPC: message without reply descriptor:"
+ << " n:" << n
+ << " msg.msg_controllen:" << msg.msg_controllen
+ << " cmsg->cmsg_level:" << cmsg->cmsg_level
+ << " cmsg->cmsg_type:" << cmsg->cmsg_type;
+ return;
+ }
+
+ const uint16_t request_type = *reinterpret_cast<uint16_t*>(buf);
+ switch (request_type) {
+ case FontConfigIPC::METHOD_MATCH:
+ return FontConfigMatch(reply_fd, buf, n);
+ case FontConfigIPC::METHOD_OPEN:
+ return FontConfigOpen(reply_fd, buf, n);
+ default:
+ LOG(ERROR) << "Sandbox IPC: message with unknown type:"
+ << " request_type:" << request_type;
+ HANDLE_EINTR(close(reply_fd));
+ }
+ }
+
+ // Send a reply to a client
+ // reply_fd: the reply channel given to us by the client
+ // iov, iov_len: the contents of the reply message
+ // extra_fd: an fd to include in the reply, or -1
+ //
+ // Both reply_fd and extra_fd (if any) are closed.
+ void SendReplyAndClose(int reply_fd, const struct iovec* iov,
+ unsigned iov_len, int extra_fd) {
+ struct msghdr msg = {0};
+ msg.msg_iov = const_cast<struct iovec*>(iov);
+ msg.msg_iovlen = iov_len;
+
+ uint8_t control_buf[CMSG_SPACE(sizeof(int))];
+
+ if (extra_fd >= 0) {
+ msg.msg_control = control_buf;
+ msg.msg_controllen = sizeof(control_buf);
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = extra_fd;
+ }
+
+ HANDLE_EINTR(sendmsg(reply_fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT));
+ HANDLE_EINTR(close(reply_fd));
+ if (extra_fd >= 0)
+ HANDLE_EINTR(close(extra_fd));
+ }
+
+ void FontConfigMatch(int reply_fd, const uint8_t* request_bytes,
+ unsigned request_len) {
+ if (request_len < sizeof(FontConfigIPC::MatchRequest))
+ return (void) HANDLE_EINTR(close(reply_fd));
+
+ const FontConfigIPC::MatchRequest* request =
+ reinterpret_cast<const FontConfigIPC::MatchRequest*>(request_bytes);
+
+ if (request_len != sizeof(FontConfigIPC::MatchRequest) + request->family_len)
+ return (void) HANDLE_EINTR(close(reply_fd));
+
+ const std::string family(
+ reinterpret_cast<const char*>(request_bytes + sizeof(*request)),
+ request->family_len);
+ std::string result_family;
+ unsigned result_fileid;
+
+ const bool r = font_config_->Match(
+ &result_family, &result_fileid, request->fileid_valid, request->fileid,
+ family, request->is_bold, request->is_italic);
+
+ struct iovec iov[2];
+ FontConfigIPC::MatchReply reply;
+ memset(&reply, 0, sizeof(reply));
+
+ iov[0].iov_base = &reply;
+ iov[0].iov_len = sizeof(reply);
+
+ if (r) {
+ reply.result = 1;
+ reply.result_fileid = result_fileid;
+ reply.filename_len = result_family.size();
+
+ iov[1].iov_base = const_cast<char*>(result_family.data());
+ iov[1].iov_len = result_family.size();
+ }
+
+ SendReplyAndClose(reply_fd, iov, r ? 2 : 1, -1 /* no fd */);
+ }
+
+ void FontConfigOpen(int reply_fd, const uint8_t* request_bytes,
+ unsigned request_len) {
+ if (request_len < sizeof(FontConfigIPC::OpenRequest))
+ return (void) HANDLE_EINTR(close(reply_fd));
+
+ const FontConfigIPC::OpenRequest* request =
+ reinterpret_cast<const FontConfigIPC::OpenRequest*>(request_bytes);
+
+ FontConfigDirect* fc = reinterpret_cast<FontConfigDirect*>(font_config_);
+
+ const int result_fd = fc->Open(request->fileid);
+
+ FontConfigIPC::OpenReply reply;
+ reply.result = result_fd >= 0 ? 1 : 0;
+
+ struct iovec iov;
+ iov.iov_base = &reply;
+ iov.iov_len = sizeof(reply);
+
+ SendReplyAndClose(reply_fd, &iov, 1, result_fd);
+ }
+
+ private:
+ const int lifeline_fd_;
+ const int browser_socket_;
+ FontConfigDirect* const font_config_;
+};
+
+// -----------------------------------------------------------------------------
+
+// Runs on the main thread at startup.
+RenderSandboxHostLinux::RenderSandboxHostLinux() {
+ int fds[2];
+ CHECK(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == 0);
+
+ renderer_socket_ = fds[0];
+ const int browser_socket = fds[1];
+
+ int pipefds[2];
+ CHECK(0 == pipe(pipefds));
+ const int child_lifeline_fd = pipefds[0];
+ childs_lifeline_fd_ = pipefds[1];
+
+ const pid_t child = fork();
+ if (child == 0) {
+ SandboxIPCProcess handler(child_lifeline_fd, browser_socket);
+ handler.Run();
+ _exit(0);
+ }
+}
+
+RenderSandboxHostLinux::~RenderSandboxHostLinux() {
+ HANDLE_EINTR(close(renderer_socket_));
+ HANDLE_EINTR(close(childs_lifeline_fd_));
+}

Powered by Google App Engine
This is Rietveld 408576698