diff options
-rw-r--r-- | base/linux_util.h | 2 | ||||
-rw-r--r-- | chrome/app/chrome_dll_main.cc | 33 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_sandbox_host_linux.cc | 80 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_sandbox_host_linux.h | 17 | ||||
-rw-r--r-- | chrome/browser/zygote_host_linux.cc | 93 | ||||
-rw-r--r-- | chrome/browser/zygote_host_linux.h | 11 | ||||
-rw-r--r-- | chrome/browser/zygote_main_linux.cc | 133 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 10 | ||||
-rw-r--r-- | chrome/common/sandbox_methods_linux.h | 1 |
9 files changed, 300 insertions, 80 deletions
diff --git a/base/linux_util.h b/base/linux_util.h index 657edda..1da519e 100644 --- a/base/linux_util.h +++ b/base/linux_util.h @@ -12,6 +12,8 @@ namespace base { +static const char kFindInodeSwitch[] = "--find-inode"; + // Makes a copy of |pixels| with the ordering changed from BGRA to RGBA. // The caller is responsible for free()ing the data. If |stride| is 0, // it's assumed to be 4 * |width|. diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc index f46ec70..22e95d2 100644 --- a/chrome/app/chrome_dll_main.cc +++ b/chrome/app/chrome_dll_main.cc @@ -18,8 +18,8 @@ #elif defined(OS_POSIX) #include <locale.h> #include <signal.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> #endif @@ -27,6 +27,7 @@ #include <gdk/gdk.h> #include <glib.h> #include <gtk/gtk.h> +#include <stdlib.h> #include <string.h> #endif @@ -58,6 +59,7 @@ #if defined(OS_LINUX) #include "base/nss_init.h" #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" +#include "chrome/browser/zygote_host_linux.h" #endif #if defined(OS_MACOSX) @@ -385,7 +387,7 @@ int ChromeMain(int argc, char** argv) { browser_pid = static_cast<base::ProcessId>(StringToInt(WideToASCII(channel_name))); - DCHECK(browser_pid != 0); + DCHECK_NE(browser_pid, 0); #else browser_pid = base::GetCurrentProcId(); #endif @@ -579,8 +581,29 @@ int ChromeMain(int argc, char** argv) { #endif } else if (process_type.empty()) { #if defined(OS_LINUX) - // Tickle the sandbox host so it forks now. - Singleton<RenderSandboxHostLinux>().get(); + const char* sandbox_binary = NULL; + struct stat st; + + // In Chromium branded builds, developers can set an environment variable to + // use the development sandbox. See + // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment + if (stat("/proc/self/exe", &st) == 0 && st.st_uid == getuid()) + sandbox_binary = getenv("CHROME_DEVEL_SANDBOX"); + +#if defined(LINUX_SANDBOX_PATH) + if (!sandbox_binary) + sandbox_binary = LINUX_SANDBOX_PATH; +#endif + + std::string sandbox_cmd; + if (sandbox_binary) + sandbox_cmd = sandbox_binary; + + // Tickle the sandbox host and zygote host so they fork now. + RenderSandboxHostLinux* shost = Singleton<RenderSandboxHostLinux>().get(); + shost->Init(sandbox_cmd); + ZygoteHost* zhost = Singleton<ZygoteHost>().get(); + zhost->Init(sandbox_cmd); // We want to be sure to init NSPR on the main thread. base::EnsureNSPRInit(); @@ -595,7 +618,7 @@ int ChromeMain(int argc, char** argv) { // gtk_init() can change |argc| and |argv|. gtk_init(&argc, &argv); SetUpGLibLogHandler(); -#endif +#endif // defined(OS_LINUX) ScopedOleInitializer ole_initializer; rv = BrowserMain(main_params); diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc index 9e6e609a..f31f71f 100644 --- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc +++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc @@ -11,12 +11,14 @@ #include <sys/poll.h> #include <time.h> +#include <vector> + +#include "base/command_line.h" #include "base/eintr_wrapper.h" -#include "base/platform_file.h" -#include "base/process_util.h" -#include "base/logging.h" -#include "base/message_loop.h" +#include "base/linux_util.h" #include "base/pickle.h" +#include "base/process_util.h" +#include "base/scoped_ptr.h" #include "base/string_util.h" #include "base/unix_domain_socket_posix.h" #include "chrome/common/sandbox_methods_linux.h" @@ -42,7 +44,9 @@ class SandboxIPCProcess { // browser_socket: the browser's end of the sandbox IPC socketpair. From the // point of view of the renderer, it's talking to the browser but this // object actually services the requests. - SandboxIPCProcess(int lifeline_fd, int browser_socket) + // sandbox_cmd: the path of the sandbox executable + SandboxIPCProcess(int lifeline_fd, int browser_socket, + std::string sandbox_cmd) : lifeline_fd_(lifeline_fd), browser_socket_(browser_socket), font_config_(new FontConfigDirect()) { @@ -51,6 +55,11 @@ class SandboxIPCProcess { multimap.push_back(base::InjectionArc(0, browser_socket, false)); base::CloseSuperfluousFds(multimap); + + if (!sandbox_cmd.empty()) { + sandbox_cmd_.push_back(sandbox_cmd); + sandbox_cmd_.push_back(base::kFindInodeSwitch); + } } void Run() { @@ -114,6 +123,8 @@ class SandboxIPCProcess { HandleGetFontFamilyForChars(fd, pickle, iter, fds); } else if (kind == LinuxSandbox::METHOD_LOCALTIME) { HandleLocaltime(fd, pickle, iter, fds); + } else if (kind == LinuxSandbox::METHOD_GET_CHILD_WITH_INODE) { + HandleGetChildWithInode(fd, pickle, iter, fds); } error: @@ -123,7 +134,7 @@ class SandboxIPCProcess { } } - void HandleFontMatchRequest(int fd, Pickle& pickle, void* iter, + void HandleFontMatchRequest(int fd, const Pickle& pickle, void* iter, std::vector<int>& fds) { bool fileid_valid; uint32_t fileid; @@ -162,7 +173,7 @@ class SandboxIPCProcess { SendRendererReply(fds, reply, -1); } - void HandleFontOpenRequest(int fd, Pickle& pickle, void* iter, + void HandleFontOpenRequest(int fd, const Pickle& pickle, void* iter, std::vector<int>& fds) { uint32_t fileid; if (!pickle.ReadUInt32(&iter, &fileid)) @@ -182,7 +193,7 @@ class SandboxIPCProcess { close(result_fd); } - void HandleGetFontFamilyForChars(int fd, Pickle& pickle, void* iter, + void HandleGetFontFamilyForChars(int fd, const Pickle& pickle, void* iter, std::vector<int>& fds) { // The other side of this call is // chrome/renderer/renderer_sandbox_support_linux.cc @@ -222,7 +233,7 @@ class SandboxIPCProcess { SendRendererReply(fds, reply, -1); } - void HandleLocaltime(int fd, Pickle& pickle, void* iter, + void HandleLocaltime(int fd, const Pickle& pickle, void* iter, std::vector<int>& fds) { // The other side of this call is in zygote_main_linux.cc @@ -247,6 +258,37 @@ class SandboxIPCProcess { SendRendererReply(fds, reply, -1); } + void HandleGetChildWithInode(int fd, const Pickle& pickle, void* iter, + std::vector<int>& fds) { + // The other side of this call is in zygote_main_linux.cc + if (sandbox_cmd_.empty()) { + LOG(ERROR) << "Not in the sandbox, this should not be called"; + return; + } + + uint64_t inode; + if (!pickle.ReadUInt64(&iter, &inode)) + return; + + base::ProcessId pid = 0; + std::string inode_output; + + std::vector<std::string> sandbox_cmd = sandbox_cmd_; + sandbox_cmd.push_back(IntToString(inode)); + CommandLine get_inode_cmd(sandbox_cmd); + if (base::GetAppOutput(get_inode_cmd, &inode_output)) + StringToInt(inode_output, &pid); + + if (!pid) { + LOG(ERROR) << "Could not get pid"; + return; + } + + Pickle reply; + reply.WriteInt(pid); + SendRendererReply(fds, reply, -1); + } + void SendRendererReply(const std::vector<int>& fds, const Pickle& reply, int reply_fd) { struct msghdr msg; @@ -266,7 +308,7 @@ class SandboxIPCProcess { cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(int)); + memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd)); msg.msg_controllen = cmsg->cmsg_len; } @@ -278,12 +320,20 @@ class SandboxIPCProcess { const int lifeline_fd_; const int browser_socket_; FontConfigDirect* const font_config_; + std::vector<std::string> sandbox_cmd_; }; // ----------------------------------------------------------------------------- // Runs on the main thread at startup. -RenderSandboxHostLinux::RenderSandboxHostLinux() { +RenderSandboxHostLinux::RenderSandboxHostLinux() + : init_(false) { +} + +void RenderSandboxHostLinux::Init(const std::string& sandbox_path) { + DCHECK(!init_); + init_ = true; + int fds[2]; // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the renderer from // sending datagrams to other sockets on the system. The sandbox may prevent @@ -303,13 +353,15 @@ RenderSandboxHostLinux::RenderSandboxHostLinux() { pid_ = fork(); if (pid_ == 0) { - SandboxIPCProcess handler(child_lifeline_fd, browser_socket); + SandboxIPCProcess handler(child_lifeline_fd, browser_socket, sandbox_path); handler.Run(); _exit(0); } } RenderSandboxHostLinux::~RenderSandboxHostLinux() { - HANDLE_EINTR(close(renderer_socket_)); - HANDLE_EINTR(close(childs_lifeline_fd_)); + if (init_) { + HANDLE_EINTR(close(renderer_socket_)); + HANDLE_EINTR(close(childs_lifeline_fd_)); + } } diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.h b/chrome/browser/renderer_host/render_sandbox_host_linux.h index 6911787..ef871b8 100644 --- a/chrome/browser/renderer_host/render_sandbox_host_linux.h +++ b/chrome/browser/renderer_host/render_sandbox_host_linux.h @@ -7,6 +7,9 @@ #ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_ #define CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_ +#include <string> + +#include "base/logging.h" #include "base/singleton.h" // This is a singleton object which handles sandbox requests from the @@ -15,8 +18,15 @@ class RenderSandboxHostLinux { public: // Get the file descriptor which renderers should be given in order to signal // crashes to the browser. - int GetRendererSocket() const { return renderer_socket_; } - pid_t pid() const { return pid_; } + int GetRendererSocket() const { + DCHECK(init_); + return renderer_socket_; + } + pid_t pid() const { + DCHECK(init_); + return pid_; + } + void Init(const std::string& sandbox_path); private: friend struct DefaultSingletonTraits<RenderSandboxHostLinux>; @@ -24,11 +34,12 @@ class RenderSandboxHostLinux { RenderSandboxHostLinux(); ~RenderSandboxHostLinux(); + bool init_; int renderer_socket_; int childs_lifeline_fd_; pid_t pid_; - DISALLOW_EVIL_CONSTRUCTORS(RenderSandboxHostLinux); + DISALLOW_COPY_AND_ASSIGN(RenderSandboxHostLinux); }; #endif // CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_ diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc index 34159264..aafaecc 100644 --- a/chrome/browser/zygote_host_linux.cc +++ b/chrome/browser/zygote_host_linux.cc @@ -4,13 +4,14 @@ #include "chrome/browser/zygote_host_linux.h" -#include <unistd.h> -#include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> #include "base/command_line.h" #include "base/eintr_wrapper.h" +#include "base/linux_util.h" #include "base/logging.h" #include "base/path_service.h" #include "base/pickle.h" @@ -21,6 +22,7 @@ #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/process_watcher.h" #include "sandbox/linux/suid/suid_unsafe_environment_variables.h" @@ -45,7 +47,20 @@ static void SaveSUIDUnsafeEnvironmentVariables() { } } -ZygoteHost::ZygoteHost() { +ZygoteHost::ZygoteHost() + : pid_(-1), + init_(false) { +} + +ZygoteHost::~ZygoteHost() { + if (init_) + close(control_fd_); +} + +void ZygoteHost::Init(const std::string& sandbox_cmd) { + DCHECK(!init_); + init_ = true; + FilePath chrome_path; CHECK(PathService::Get(base::FILE_EXE, &chrome_path)); CommandLine cmd_line(chrome_path); @@ -82,26 +97,15 @@ ZygoteHost::ZygoteHost() { switches::kEnableLogging)); } - const char* sandbox_binary = NULL; + const char* sandbox_binary = sandbox_cmd.c_str(); struct stat st; - // In Chromium branded builds, developers can set an environment variable to - // use the development sandbox. See - // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment - if (stat("/proc/self/exe", &st) == 0 && - st.st_uid == getuid()) { - sandbox_binary = getenv("CHROME_DEVEL_SANDBOX"); - } - -#if defined(LINUX_SANDBOX_PATH) - if (!sandbox_binary) - sandbox_binary = LINUX_SANDBOX_PATH; -#endif - - if (sandbox_binary && stat(sandbox_binary, &st) == 0) { + bool using_suid_sandbox = false; + if (!sandbox_cmd.empty() && stat(sandbox_binary, &st) == 0) { if (access(sandbox_binary, X_OK) == 0 && (st.st_mode & S_ISUID) && (st.st_mode & S_IXOTH)) { + using_suid_sandbox = true; cmd_line.PrependWrapper(ASCIIToWide(sandbox_binary)); SaveSUIDUnsafeEnvironmentVariables(); @@ -118,22 +122,63 @@ ZygoteHost::ZygoteHost() { const int sfd = Singleton<RenderSandboxHostLinux>()->GetRendererSocket(); fds_to_map.push_back(std::make_pair(sfd, 5)); + int dummy_fd = -1; + if (using_suid_sandbox) { + dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); + CHECK(dummy_fd >= 0); + fds_to_map.push_back(std::make_pair(dummy_fd, 7)); + } + base::ProcessHandle process; base::LaunchApp(cmd_line.argv(), fds_to_map, false, &process); CHECK(process != -1) << "Failed to launch zygote process"; - pid_ = process; + if (using_suid_sandbox) { + // In the SUID sandbox, the real zygote is forked from the sandbox. + // We need to look for it. + // But first, wait for the zygote to tell us it's running. + // The sending code is in chrome/browser/zygote_main_linux.cc. + std::vector<int> fds_vec; + const int kExpectedLength = sizeof(kZygoteMagic); + char buf[kExpectedLength]; + const ssize_t len = base::RecvMsg(fds[0], buf, sizeof(buf), &fds_vec); + CHECK(len == kExpectedLength) << "Incorrect zygote magic length"; + CHECK(0 == strcmp(buf, kZygoteMagic)) << "Incorrect zygote magic"; + + std::string inode_output; + ino_t inode = 0; + // Figure out the inode for |dummy_fd|, close |dummy_fd| on our end, + // and find the zygote process holding |dummy_fd|. + if (base::FileDescriptorGetInode(&inode, dummy_fd)) { + close(dummy_fd); + std::vector<std::string> get_inode_cmdline; + get_inode_cmdline.push_back(sandbox_binary); + get_inode_cmdline.push_back(base::kFindInodeSwitch); + get_inode_cmdline.push_back(IntToString(inode)); + CommandLine get_inode_cmd(get_inode_cmdline); + if (base::GetAppOutput(get_inode_cmd, &inode_output)) { + StringToInt(inode_output, &pid_); + } + } + CHECK(pid_ > 0) << "Did not find zygote process"; + + if (process != pid_) { + // Reap the sandbox. + ProcessWatcher::EnsureProcessGetsReaped(process); + } + } else { + // Not using the SUID sandbox. + pid_ = process; + } + close(fds[1]); control_fd_ = fds[0]; } -ZygoteHost::~ZygoteHost() { - close(control_fd_); -} - pid_t ZygoteHost::ForkRenderer( const std::vector<std::string>& argv, const base::GlobalDescriptors::Mapping& mapping) { + DCHECK(init_); Pickle pickle; pickle.WriteInt(kCmdFork); @@ -162,6 +207,7 @@ pid_t ZygoteHost::ForkRenderer( } void ZygoteHost::EnsureProcessTerminated(pid_t process) { + DCHECK(init_); Pickle pickle; pickle.WriteInt(kCmdReap); @@ -172,6 +218,7 @@ void ZygoteHost::EnsureProcessTerminated(pid_t process) { bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle, bool* child_exited) { + DCHECK(init_); Pickle pickle; pickle.WriteInt(kCmdDidProcessCrash); pickle.WriteInt(handle); diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h index 516a18b..5b4244c 100644 --- a/chrome/browser/zygote_host_linux.h +++ b/chrome/browser/zygote_host_linux.h @@ -5,24 +5,26 @@ #ifndef CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_ #define CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_ +#include <unistd.h> + #include <string> #include <vector> -#include <unistd.h> - #include "base/global_descriptors_posix.h" #include "base/process.h" template<typename Type> struct DefaultSingletonTraits; +static const char kZygoteMagic[] = "ZYGOTE_OK"; + // http://code.google.com/p/chromium/wiki/LinuxZygote // The zygote host is the interface, in the browser process, to the zygote // process. class ZygoteHost { public: - ~ZygoteHost(); + void Init(const std::string& sandbox_cmd); pid_t ForkRenderer(const std::vector<std::string>& command_line, const base::GlobalDescriptors::Mapping& mapping); @@ -46,10 +48,11 @@ class ZygoteHost { private: friend struct DefaultSingletonTraits<ZygoteHost>; ZygoteHost(); - void LaunchZygoteProcess(); + ~ZygoteHost(); int control_fd_; // the socket to the zygote pid_t pid_; + bool init_; }; #endif // CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_ diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc index ecf7291..b9839d3 100644 --- a/chrome/browser/zygote_main_linux.cc +++ b/chrome/browser/zygote_main_linux.cc @@ -3,18 +3,25 @@ // found in the LICENSE file. #include <dlfcn.h> -#include <unistd.h> #include <sys/epoll.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/signal.h> #include <sys/prctl.h> +#include <sys/signal.h> +#include <sys/socket.h> +#include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> + +#if defined(CHROMIUM_SELINUX) +#include <selinux/selinux.h> +#include <selinux/context.h> +#endif #include "base/basictypes.h" #include "base/command_line.h" #include "base/eintr_wrapper.h" #include "base/global_descriptors_posix.h" +#include "base/hash_tables.h" +#include "base/linux_util.h" #include "base/path_service.h" #include "base/pickle.h" #include "base/rand_util.h" @@ -33,16 +40,14 @@ #include "skia/ext/SkFontHost_fontconfig_control.h" -#if defined(CHROMIUM_SELINUX) -#include <selinux/selinux.h> -#include <selinux/context.h> -#endif - #include "unicode/timezone.h" // http://code.google.com/p/chromium/wiki/LinuxZygote +static const int kBrowserDescriptor = 3; static const int kMagicSandboxIPCDescriptor = 5; +static const int kZygoteIdDescriptor = 7; +static bool g_suid_sandbox_active = false; // This is the object which implements the zygote. The ZygoteMain function, // which is called from ChromeMain, at the the bottom and simple constructs one @@ -52,7 +57,7 @@ class Zygote { bool ProcessRequests() { // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the // browser on it. - // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel. + // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC // We need to accept SIGCHLD, even though our handler is a no-op because @@ -62,8 +67,17 @@ class Zygote { action.sa_handler = SIGCHLDHandler; CHECK(sigaction(SIGCHLD, &action, NULL) == 0); + if (g_suid_sandbox_active) { + // Let the ZygoteHost know we are ready to go. + // The receiving code is in chrome/browser/zygote_host_linux.cc. + std::vector<int> empty; + bool r = base::SendMsg(kBrowserDescriptor, kZygoteMagic, + sizeof(kZygoteMagic), empty); + CHECK(r) << "Sending zygote magic failed"; + } + for (;;) { - if (HandleRequestFromBrowser(3)) + if (HandleRequestFromBrowser(kBrowserDescriptor)) return true; } } @@ -122,20 +136,30 @@ class Zygote { return false; } - bool HandleReapRequest(int fd, Pickle& pickle, void* iter) { - pid_t child; + bool HandleReapRequest(int fd, const Pickle& pickle, void* iter) { + base::ProcessId child; + base::ProcessId actual_child; if (!pickle.ReadInt(&iter, &child)) { LOG(WARNING) << "Error parsing reap request from browser"; return false; } - ProcessWatcher::EnsureProcessTerminated(child); + if (g_suid_sandbox_active) { + actual_child = real_pids_to_sandbox_pids[child]; + if (!actual_child) + return false; + real_pids_to_sandbox_pids.erase(child); + } else { + actual_child = child; + } + + ProcessWatcher::EnsureProcessTerminated(actual_child); return false; } - bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) { + bool HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) { base::ProcessHandle child; if (!pickle.ReadInt(&iter, &child)) { @@ -144,7 +168,13 @@ class Zygote { } bool child_exited; - bool did_crash = base::DidProcessCrash(&child_exited, child); + bool did_crash; + if (g_suid_sandbox_active) + child = real_pids_to_sandbox_pids[child]; + if (child) + did_crash = base::DidProcessCrash(&child_exited, child); + else + did_crash = child_exited = false; Pickle write_pickle; write_pickle.WriteBool(did_crash); @@ -156,12 +186,14 @@ class Zygote { // Handle a 'fork' request from the browser: this means that the browser // wishes to start a new renderer. - bool HandleForkRequest(int fd, Pickle& pickle, void* iter, + bool HandleForkRequest(int fd, const Pickle& pickle, void* iter, std::vector<int>& fds) { std::vector<std::string> args; int argc, numfds; base::GlobalDescriptors::Mapping mapping; - pid_t child; + base::ProcessId child; + uint64_t dummy_inode = 0; + int dummy_fd = -1; if (!pickle.ReadInt(&iter, &argc)) goto error; @@ -186,12 +218,22 @@ class Zygote { } mapping.push_back(std::make_pair( - static_cast<uint32_t>(kSandboxIPCChannel), 5)); + static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); + + if (g_suid_sandbox_active) { + dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (dummy_fd < 0) + goto error; + + if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) + goto error; + } child = fork(); if (!child) { - close(3); // our socket from the browser is in fd 3 + close(kBrowserDescriptor); // our socket from the browser + close(kZygoteIdDescriptor); // another socket from the browser Singleton<base::GlobalDescriptors>()->Reset(mapping); // Reset the process-wide command line to our new command line. @@ -200,22 +242,59 @@ class Zygote { CommandLine::ForCurrentProcess()->InitFromArgv(args); CommandLine::SetProcTitle(); return true; + } else if (child < 0) { + LOG(ERROR) << "Zygote could not fork"; + goto error; } - for (std::vector<int>::const_iterator - i = fds.begin(); i != fds.end(); ++i) - close(*i); + { + base::ProcessId proc_id; + if (g_suid_sandbox_active) { + close(dummy_fd); + dummy_fd = -1; + uint8_t reply_buf[512]; + Pickle request; + request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE); + request.WriteUInt64(dummy_inode); + + const ssize_t r = base::SendRecvMsg(kMagicSandboxIPCDescriptor, + reply_buf, sizeof(reply_buf), + NULL, request); + if (r == -1) + goto error; + + Pickle reply(reinterpret_cast<char*>(reply_buf), r); + void* iter2 = NULL; + if (!reply.ReadInt(&iter2, &proc_id)) + goto error; + real_pids_to_sandbox_pids[proc_id] = child; + } else { + proc_id = child; + } - HANDLE_EINTR(write(fd, &child, sizeof(child))); - return false; + for (std::vector<int>::const_iterator + i = fds.begin(); i != fds.end(); ++i) + close(*i); + + HANDLE_EINTR(write(fd, &proc_id, sizeof(proc_id))); + return false; + } error: - LOG(WARNING) << "Error parsing fork request from browser"; + LOG(ERROR) << "Error parsing fork request from browser"; for (std::vector<int>::const_iterator i = fds.begin(); i != fds.end(); ++i) close(*i); + if (dummy_fd >= 0) + close(dummy_fd); return false; } + + // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs + // fork() returns are not the real PIDs, so we need to map the Real PIDS + // into the sandbox PID namespace. + typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; + ProcessMap real_pids_to_sandbox_pids; }; // With SELinux we can carve out a precise sandbox, so we don't have to play @@ -402,6 +481,8 @@ static bool EnterSandbox() { // over which we can signal that we have completed our startup and can be // chrooted. + g_suid_sandbox_active = true; + char* endptr; const long fd_long = strtol(sandbox_fd_string, &endptr, 10); if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX) diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index c2f061c..4ef2bff 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2531,11 +2531,6 @@ 'browser/renderer_host/render_crash_handler_host_linux_stub.cc', ], }], - ['linux_sandbox_path != ""', { - 'defines': [ - 'LINUX_SANDBOX_PATH="<(linux_sandbox_path)"', - ], - }], ], }], ['OS=="linux" and toolkit_views==0', { @@ -3785,6 +3780,11 @@ '../sandbox/sandbox.gyp:sandbox', ], }], + ['linux_sandbox_path != ""', { + 'defines': [ + 'LINUX_SANDBOX_PATH="<(linux_sandbox_path)"', + ], + }], ], }], ['OS=="mac" or OS=="win"', { diff --git a/chrome/common/sandbox_methods_linux.h b/chrome/common/sandbox_methods_linux.h index 4dceba0..22fbf29 100644 --- a/chrome/common/sandbox_methods_linux.h +++ b/chrome/common/sandbox_methods_linux.h @@ -14,6 +14,7 @@ class LinuxSandbox { enum Methods { METHOD_GET_FONT_FAMILY_FOR_CHARS = 32, METHOD_LOCALTIME = 33, + METHOD_GET_CHILD_WITH_INODE = 34, }; }; |