1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/renderer_host/render_sandbox_host_linux.h"
6
7#include <sys/socket.h>
8
9#include "base/memory/singleton.h"
10#include "base/posix/eintr_wrapper.h"
11
12namespace content {
13
14// Runs on the main thread at startup.
15RenderSandboxHostLinux::RenderSandboxHostLinux()
16    : initialized_(false), renderer_socket_(0), childs_lifeline_fd_(0) {
17}
18
19// static
20RenderSandboxHostLinux* RenderSandboxHostLinux::GetInstance() {
21  return Singleton<RenderSandboxHostLinux>::get();
22}
23
24void RenderSandboxHostLinux::Init() {
25  DCHECK(!initialized_);
26  initialized_ = true;
27
28  int fds[2];
29  // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the renderer from
30  // sending datagrams to other sockets on the system. The sandbox may prevent
31  // the renderer from calling socket() to create new sockets, but it'll still
32  // inherit some sockets. With AF_UNIX+SOCK_DGRAM, it can call sendmsg to send
33  // a datagram to any (abstract) socket on the same system. With
34  // SOCK_SEQPACKET, this is prevented.
35  CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
36
37  renderer_socket_ = fds[0];
38  // The SandboxIPC client is not expected to read from |renderer_socket_|.
39  // Instead, it reads from a temporary socket sent with the request.
40  PCHECK(0 == shutdown(renderer_socket_, SHUT_RD)) << "shutdown";
41
42  const int browser_socket = fds[1];
43  // The SandboxIPC handler is not expected to write to |browser_socket|.
44  // Instead, it replies on a temporary socket provided by the caller.
45  PCHECK(0 == shutdown(browser_socket, SHUT_WR)) << "shutdown";
46
47  int pipefds[2];
48  CHECK(0 == pipe(pipefds));
49  const int child_lifeline_fd = pipefds[0];
50  childs_lifeline_fd_ = pipefds[1];
51
52  ipc_handler_.reset(
53      new SandboxIPCHandler(child_lifeline_fd, browser_socket));
54  ipc_thread_.reset(
55      new base::DelegateSimpleThread(ipc_handler_.get(), "sandbox_ipc_thread"));
56  ipc_thread_->Start();
57}
58
59bool RenderSandboxHostLinux::ShutdownIPCChannel() {
60  return IGNORE_EINTR(close(childs_lifeline_fd_)) == 0;
61}
62
63RenderSandboxHostLinux::~RenderSandboxHostLinux() {
64  if (initialized_) {
65    if (!ShutdownIPCChannel())
66      LOG(ERROR) << "ShutdownIPCChannel failed";
67    if (IGNORE_EINTR(close(renderer_socket_)) < 0)
68      PLOG(ERROR) << "close";
69
70    ipc_thread_->Join();
71  }
72}
73
74}  // namespace content
75