diff options
Diffstat (limited to 'chrome/browser')
-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 |
5 files changed, 70 insertions, 264 deletions
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc index f31f71f..9e6e609a 100644 --- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc +++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc @@ -11,14 +11,12 @@ #include <sys/poll.h> #include <time.h> -#include <vector> - -#include "base/command_line.h" #include "base/eintr_wrapper.h" -#include "base/linux_util.h" -#include "base/pickle.h" +#include "base/platform_file.h" #include "base/process_util.h" -#include "base/scoped_ptr.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/pickle.h" #include "base/string_util.h" #include "base/unix_domain_socket_posix.h" #include "chrome/common/sandbox_methods_linux.h" @@ -44,9 +42,7 @@ 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. - // sandbox_cmd: the path of the sandbox executable - SandboxIPCProcess(int lifeline_fd, int browser_socket, - std::string sandbox_cmd) + SandboxIPCProcess(int lifeline_fd, int browser_socket) : lifeline_fd_(lifeline_fd), browser_socket_(browser_socket), font_config_(new FontConfigDirect()) { @@ -55,11 +51,6 @@ 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() { @@ -123,8 +114,6 @@ 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: @@ -134,7 +123,7 @@ class SandboxIPCProcess { } } - void HandleFontMatchRequest(int fd, const Pickle& pickle, void* iter, + void HandleFontMatchRequest(int fd, Pickle& pickle, void* iter, std::vector<int>& fds) { bool fileid_valid; uint32_t fileid; @@ -173,7 +162,7 @@ class SandboxIPCProcess { SendRendererReply(fds, reply, -1); } - void HandleFontOpenRequest(int fd, const Pickle& pickle, void* iter, + void HandleFontOpenRequest(int fd, Pickle& pickle, void* iter, std::vector<int>& fds) { uint32_t fileid; if (!pickle.ReadUInt32(&iter, &fileid)) @@ -193,7 +182,7 @@ class SandboxIPCProcess { close(result_fd); } - void HandleGetFontFamilyForChars(int fd, const Pickle& pickle, void* iter, + void HandleGetFontFamilyForChars(int fd, Pickle& pickle, void* iter, std::vector<int>& fds) { // The other side of this call is // chrome/renderer/renderer_sandbox_support_linux.cc @@ -233,7 +222,7 @@ class SandboxIPCProcess { SendRendererReply(fds, reply, -1); } - void HandleLocaltime(int fd, const Pickle& pickle, void* iter, + void HandleLocaltime(int fd, Pickle& pickle, void* iter, std::vector<int>& fds) { // The other side of this call is in zygote_main_linux.cc @@ -258,37 +247,6 @@ 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; @@ -308,7 +266,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(reply_fd)); + memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; } @@ -320,20 +278,12 @@ 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() - : init_(false) { -} - -void RenderSandboxHostLinux::Init(const std::string& sandbox_path) { - DCHECK(!init_); - init_ = true; - +RenderSandboxHostLinux::RenderSandboxHostLinux() { 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 @@ -353,15 +303,13 @@ void RenderSandboxHostLinux::Init(const std::string& sandbox_path) { pid_ = fork(); if (pid_ == 0) { - SandboxIPCProcess handler(child_lifeline_fd, browser_socket, sandbox_path); + SandboxIPCProcess handler(child_lifeline_fd, browser_socket); handler.Run(); _exit(0); } } RenderSandboxHostLinux::~RenderSandboxHostLinux() { - if (init_) { - HANDLE_EINTR(close(renderer_socket_)); - HANDLE_EINTR(close(childs_lifeline_fd_)); - } + 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 ef871b8..6911787 100644 --- a/chrome/browser/renderer_host/render_sandbox_host_linux.h +++ b/chrome/browser/renderer_host/render_sandbox_host_linux.h @@ -7,9 +7,6 @@ #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 @@ -18,15 +15,8 @@ class RenderSandboxHostLinux { public: // Get the file descriptor which renderers should be given in order to signal // crashes to the browser. - int GetRendererSocket() const { - DCHECK(init_); - return renderer_socket_; - } - pid_t pid() const { - DCHECK(init_); - return pid_; - } - void Init(const std::string& sandbox_path); + int GetRendererSocket() const { return renderer_socket_; } + pid_t pid() const { return pid_; } private: friend struct DefaultSingletonTraits<RenderSandboxHostLinux>; @@ -34,12 +24,11 @@ class RenderSandboxHostLinux { RenderSandboxHostLinux(); ~RenderSandboxHostLinux(); - bool init_; int renderer_socket_; int childs_lifeline_fd_; pid_t pid_; - DISALLOW_COPY_AND_ASSIGN(RenderSandboxHostLinux); + DISALLOW_EVIL_CONSTRUCTORS(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 aafaecc..34159264 100644 --- a/chrome/browser/zygote_host_linux.cc +++ b/chrome/browser/zygote_host_linux.cc @@ -4,14 +4,13 @@ #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" @@ -22,7 +21,6 @@ #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" @@ -47,20 +45,7 @@ static void SaveSUIDUnsafeEnvironmentVariables() { } } -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; - +ZygoteHost::ZygoteHost() { FilePath chrome_path; CHECK(PathService::Get(base::FILE_EXE, &chrome_path)); CommandLine cmd_line(chrome_path); @@ -97,15 +82,26 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) { switches::kEnableLogging)); } - const char* sandbox_binary = sandbox_cmd.c_str(); + const char* sandbox_binary = NULL; struct stat st; - bool using_suid_sandbox = false; - if (!sandbox_cmd.empty() && stat(sandbox_binary, &st) == 0) { + // 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) { 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(); @@ -122,63 +118,22 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) { 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"; - 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; - } - + 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); @@ -207,7 +162,6 @@ pid_t ZygoteHost::ForkRenderer( } void ZygoteHost::EnsureProcessTerminated(pid_t process) { - DCHECK(init_); Pickle pickle; pickle.WriteInt(kCmdReap); @@ -218,7 +172,6 @@ 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 5b4244c..516a18b 100644 --- a/chrome/browser/zygote_host_linux.h +++ b/chrome/browser/zygote_host_linux.h @@ -5,26 +5,24 @@ #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: - void Init(const std::string& sandbox_cmd); + ~ZygoteHost(); pid_t ForkRenderer(const std::vector<std::string>& command_line, const base::GlobalDescriptors::Mapping& mapping); @@ -48,11 +46,10 @@ class ZygoteHost { private: friend struct DefaultSingletonTraits<ZygoteHost>; ZygoteHost(); - ~ZygoteHost(); + void LaunchZygoteProcess(); 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 b9839d3..ecf7291 100644 --- a/chrome/browser/zygote_main_linux.cc +++ b/chrome/browser/zygote_main_linux.cc @@ -3,25 +3,18 @@ // found in the LICENSE file. #include <dlfcn.h> +#include <unistd.h> #include <sys/epoll.h> -#include <sys/prctl.h> -#include <sys/signal.h> -#include <sys/socket.h> #include <sys/types.h> +#include <sys/socket.h> +#include <sys/signal.h> +#include <sys/prctl.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" @@ -40,14 +33,16 @@ #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 @@ -57,7 +52,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 5. This is the sandbox IPC channel. + // A SOCK_DGRAM is installed in fd 4. 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 @@ -67,17 +62,8 @@ 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(kBrowserDescriptor)) + if (HandleRequestFromBrowser(3)) return true; } } @@ -136,30 +122,20 @@ class Zygote { return false; } - bool HandleReapRequest(int fd, const Pickle& pickle, void* iter) { - base::ProcessId child; - base::ProcessId actual_child; + bool HandleReapRequest(int fd, Pickle& pickle, void* iter) { + pid_t child; if (!pickle.ReadInt(&iter, &child)) { LOG(WARNING) << "Error parsing reap request from browser"; return false; } - 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); + ProcessWatcher::EnsureProcessTerminated(child); return false; } - bool HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) { + bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) { base::ProcessHandle child; if (!pickle.ReadInt(&iter, &child)) { @@ -168,13 +144,7 @@ class Zygote { } bool child_exited; - 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; + bool did_crash = base::DidProcessCrash(&child_exited, child); Pickle write_pickle; write_pickle.WriteBool(did_crash); @@ -186,14 +156,12 @@ class Zygote { // Handle a 'fork' request from the browser: this means that the browser // wishes to start a new renderer. - bool HandleForkRequest(int fd, const Pickle& pickle, void* iter, + bool HandleForkRequest(int fd, Pickle& pickle, void* iter, std::vector<int>& fds) { std::vector<std::string> args; int argc, numfds; base::GlobalDescriptors::Mapping mapping; - base::ProcessId child; - uint64_t dummy_inode = 0; - int dummy_fd = -1; + pid_t child; if (!pickle.ReadInt(&iter, &argc)) goto error; @@ -218,22 +186,12 @@ class Zygote { } mapping.push_back(std::make_pair( - 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; - } + static_cast<uint32_t>(kSandboxIPCChannel), 5)); child = fork(); if (!child) { - close(kBrowserDescriptor); // our socket from the browser - close(kZygoteIdDescriptor); // another socket from the browser + close(3); // our socket from the browser is in fd 3 Singleton<base::GlobalDescriptors>()->Reset(mapping); // Reset the process-wide command line to our new command line. @@ -242,59 +200,22 @@ class Zygote { CommandLine::ForCurrentProcess()->InitFromArgv(args); CommandLine::SetProcTitle(); return true; - } else if (child < 0) { - LOG(ERROR) << "Zygote could not fork"; - goto error; } - { - 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; - } - - for (std::vector<int>::const_iterator - i = fds.begin(); i != fds.end(); ++i) - close(*i); + 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; - } + HANDLE_EINTR(write(fd, &child, sizeof(child))); + return false; error: - LOG(ERROR) << "Error parsing fork request from browser"; + LOG(WARNING) << "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 @@ -481,8 +402,6 @@ 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) |