| OLD | NEW | 
|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include <dlfcn.h> | 5 #include <dlfcn.h> | 
|  | 6 #include <unistd.h> | 
| 6 #include <sys/epoll.h> | 7 #include <sys/epoll.h> | 
|  | 8 #include <sys/types.h> | 
|  | 9 #include <sys/socket.h> | 
|  | 10 #include <sys/signal.h> | 
| 7 #include <sys/prctl.h> | 11 #include <sys/prctl.h> | 
| 8 #include <sys/signal.h> |  | 
| 9 #include <sys/socket.h> |  | 
| 10 #include <sys/types.h> |  | 
| 11 #include <sys/wait.h> | 12 #include <sys/wait.h> | 
| 12 #include <unistd.h> |  | 
| 13 |  | 
| 14 #if defined(CHROMIUM_SELINUX) |  | 
| 15 #include <selinux/selinux.h> |  | 
| 16 #include <selinux/context.h> |  | 
| 17 #endif |  | 
| 18 | 13 | 
| 19 #include "base/basictypes.h" | 14 #include "base/basictypes.h" | 
| 20 #include "base/command_line.h" | 15 #include "base/command_line.h" | 
| 21 #include "base/eintr_wrapper.h" | 16 #include "base/eintr_wrapper.h" | 
| 22 #include "base/global_descriptors_posix.h" | 17 #include "base/global_descriptors_posix.h" | 
| 23 #include "base/hash_tables.h" |  | 
| 24 #include "base/linux_util.h" |  | 
| 25 #include "base/path_service.h" | 18 #include "base/path_service.h" | 
| 26 #include "base/pickle.h" | 19 #include "base/pickle.h" | 
| 27 #include "base/rand_util.h" | 20 #include "base/rand_util.h" | 
| 28 #include "base/scoped_ptr.h" | 21 #include "base/scoped_ptr.h" | 
| 29 #include "base/sys_info.h" | 22 #include "base/sys_info.h" | 
| 30 #include "base/unix_domain_socket_posix.h" | 23 #include "base/unix_domain_socket_posix.h" | 
| 31 | 24 | 
| 32 #include "chrome/browser/zygote_host_linux.h" | 25 #include "chrome/browser/zygote_host_linux.h" | 
| 33 #include "chrome/common/chrome_descriptors.h" | 26 #include "chrome/common/chrome_descriptors.h" | 
| 34 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" | 
| 35 #include "chrome/common/main_function_params.h" | 28 #include "chrome/common/main_function_params.h" | 
| 36 #include "chrome/common/process_watcher.h" | 29 #include "chrome/common/process_watcher.h" | 
| 37 #include "chrome/common/sandbox_methods_linux.h" | 30 #include "chrome/common/sandbox_methods_linux.h" | 
| 38 | 31 | 
| 39 #include "media/base/media.h" | 32 #include "media/base/media.h" | 
| 40 | 33 | 
| 41 #include "skia/ext/SkFontHost_fontconfig_control.h" | 34 #include "skia/ext/SkFontHost_fontconfig_control.h" | 
| 42 | 35 | 
|  | 36 #if defined(CHROMIUM_SELINUX) | 
|  | 37 #include <selinux/selinux.h> | 
|  | 38 #include <selinux/context.h> | 
|  | 39 #endif | 
|  | 40 | 
| 43 #include "unicode/timezone.h" | 41 #include "unicode/timezone.h" | 
| 44 | 42 | 
| 45 // http://code.google.com/p/chromium/wiki/LinuxZygote | 43 // http://code.google.com/p/chromium/wiki/LinuxZygote | 
| 46 | 44 | 
| 47 static const int kBrowserDescriptor = 3; |  | 
| 48 static const int kMagicSandboxIPCDescriptor = 5; | 45 static const int kMagicSandboxIPCDescriptor = 5; | 
| 49 static const int kZygoteIdDescriptor = 7; |  | 
| 50 static bool g_suid_sandbox_active = false; |  | 
| 51 | 46 | 
| 52 // This is the object which implements the zygote. The ZygoteMain function, | 47 // This is the object which implements the zygote. The ZygoteMain function, | 
| 53 // which is called from ChromeMain, at the the bottom and simple constructs one | 48 // which is called from ChromeMain, at the the bottom and simple constructs one | 
| 54 // of these objects and runs it. | 49 // of these objects and runs it. | 
| 55 class Zygote { | 50 class Zygote { | 
| 56  public: | 51  public: | 
| 57   bool ProcessRequests() { | 52   bool ProcessRequests() { | 
| 58     // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the | 53     // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the | 
| 59     // browser on it. | 54     // browser on it. | 
| 60     // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. | 55     // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel. | 
| 61     // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC | 56     // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC | 
| 62 | 57 | 
| 63     // We need to accept SIGCHLD, even though our handler is a no-op because | 58     // We need to accept SIGCHLD, even though our handler is a no-op because | 
| 64     // otherwise we cannot wait on children. (According to POSIX 2001.) | 59     // otherwise we cannot wait on children. (According to POSIX 2001.) | 
| 65     struct sigaction action; | 60     struct sigaction action; | 
| 66     memset(&action, 0, sizeof(action)); | 61     memset(&action, 0, sizeof(action)); | 
| 67     action.sa_handler = SIGCHLDHandler; | 62     action.sa_handler = SIGCHLDHandler; | 
| 68     CHECK(sigaction(SIGCHLD, &action, NULL) == 0); | 63     CHECK(sigaction(SIGCHLD, &action, NULL) == 0); | 
| 69 | 64 | 
| 70     if (g_suid_sandbox_active) { |  | 
| 71       // Let the ZygoteHost know we are ready to go. |  | 
| 72       // The receiving code is in chrome/browser/zygote_host_linux.cc. |  | 
| 73       std::vector<int> empty; |  | 
| 74       bool r = base::SendMsg(kBrowserDescriptor, kZygoteMagic, |  | 
| 75                              sizeof(kZygoteMagic), empty); |  | 
| 76       CHECK(r) << "Sending zygote magic failed"; |  | 
| 77     } |  | 
| 78 |  | 
| 79     for (;;) { | 65     for (;;) { | 
| 80       if (HandleRequestFromBrowser(kBrowserDescriptor)) | 66       if (HandleRequestFromBrowser(3)) | 
| 81         return true; | 67         return true; | 
| 82     } | 68     } | 
| 83   } | 69   } | 
| 84 | 70 | 
| 85  private: | 71  private: | 
| 86   // See comment below, where sigaction is called. | 72   // See comment below, where sigaction is called. | 
| 87   static void SIGCHLDHandler(int signal) { } | 73   static void SIGCHLDHandler(int signal) { } | 
| 88 | 74 | 
| 89   // --------------------------------------------------------------------------- | 75   // --------------------------------------------------------------------------- | 
| 90   // Requests from the browser... | 76   // Requests from the browser... | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 129       } | 115       } | 
| 130     } | 116     } | 
| 131 | 117 | 
| 132     LOG(WARNING) << "Error parsing message from browser"; | 118     LOG(WARNING) << "Error parsing message from browser"; | 
| 133     for (std::vector<int>::const_iterator | 119     for (std::vector<int>::const_iterator | 
| 134          i = fds.begin(); i != fds.end(); ++i) | 120          i = fds.begin(); i != fds.end(); ++i) | 
| 135       close(*i); | 121       close(*i); | 
| 136     return false; | 122     return false; | 
| 137   } | 123   } | 
| 138 | 124 | 
| 139   bool HandleReapRequest(int fd, const Pickle& pickle, void* iter) { | 125   bool HandleReapRequest(int fd, Pickle& pickle, void* iter) { | 
| 140     base::ProcessId child; | 126     pid_t child; | 
| 141     base::ProcessId actual_child; |  | 
| 142 | 127 | 
| 143     if (!pickle.ReadInt(&iter, &child)) { | 128     if (!pickle.ReadInt(&iter, &child)) { | 
| 144       LOG(WARNING) << "Error parsing reap request from browser"; | 129       LOG(WARNING) << "Error parsing reap request from browser"; | 
| 145       return false; | 130       return false; | 
| 146     } | 131     } | 
| 147 | 132 | 
| 148     if (g_suid_sandbox_active) { | 133     ProcessWatcher::EnsureProcessTerminated(child); | 
| 149       actual_child = real_pids_to_sandbox_pids[child]; |  | 
| 150       if (!actual_child) |  | 
| 151         return false; |  | 
| 152       real_pids_to_sandbox_pids.erase(child); |  | 
| 153     } else { |  | 
| 154       actual_child = child; |  | 
| 155     } |  | 
| 156 |  | 
| 157     ProcessWatcher::EnsureProcessTerminated(actual_child); |  | 
| 158 | 134 | 
| 159     return false; | 135     return false; | 
| 160   } | 136   } | 
| 161 | 137 | 
| 162   bool HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) { | 138   bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) { | 
| 163     base::ProcessHandle child; | 139     base::ProcessHandle child; | 
| 164 | 140 | 
| 165     if (!pickle.ReadInt(&iter, &child)) { | 141     if (!pickle.ReadInt(&iter, &child)) { | 
| 166       LOG(WARNING) << "Error parsing DidProcessCrash request from browser"; | 142       LOG(WARNING) << "Error parsing DidProcessCrash request from browser"; | 
| 167       return false; | 143       return false; | 
| 168     } | 144     } | 
| 169 | 145 | 
| 170     bool child_exited; | 146     bool child_exited; | 
| 171     bool did_crash; | 147     bool did_crash = base::DidProcessCrash(&child_exited, child); | 
| 172     if (g_suid_sandbox_active) |  | 
| 173       child = real_pids_to_sandbox_pids[child]; |  | 
| 174     if (child) |  | 
| 175       did_crash = base::DidProcessCrash(&child_exited, child); |  | 
| 176     else |  | 
| 177       did_crash = child_exited = false; |  | 
| 178 | 148 | 
| 179     Pickle write_pickle; | 149     Pickle write_pickle; | 
| 180     write_pickle.WriteBool(did_crash); | 150     write_pickle.WriteBool(did_crash); | 
| 181     write_pickle.WriteBool(child_exited); | 151     write_pickle.WriteBool(child_exited); | 
| 182     HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); | 152     HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); | 
| 183 | 153 | 
| 184     return false; | 154     return false; | 
| 185   } | 155   } | 
| 186 | 156 | 
| 187   // Handle a 'fork' request from the browser: this means that the browser | 157   // Handle a 'fork' request from the browser: this means that the browser | 
| 188   // wishes to start a new renderer. | 158   // wishes to start a new renderer. | 
| 189   bool HandleForkRequest(int fd, const Pickle& pickle, void* iter, | 159   bool HandleForkRequest(int fd, Pickle& pickle, void* iter, | 
| 190                          std::vector<int>& fds) { | 160                          std::vector<int>& fds) { | 
| 191     std::vector<std::string> args; | 161     std::vector<std::string> args; | 
| 192     int argc, numfds; | 162     int argc, numfds; | 
| 193     base::GlobalDescriptors::Mapping mapping; | 163     base::GlobalDescriptors::Mapping mapping; | 
| 194     base::ProcessId child; | 164     pid_t child; | 
| 195     uint64_t dummy_inode = 0; |  | 
| 196     int dummy_fd = -1; |  | 
| 197 | 165 | 
| 198     if (!pickle.ReadInt(&iter, &argc)) | 166     if (!pickle.ReadInt(&iter, &argc)) | 
| 199       goto error; | 167       goto error; | 
| 200 | 168 | 
| 201     for (int i = 0; i < argc; ++i) { | 169     for (int i = 0; i < argc; ++i) { | 
| 202       std::string arg; | 170       std::string arg; | 
| 203       if (!pickle.ReadString(&iter, &arg)) | 171       if (!pickle.ReadString(&iter, &arg)) | 
| 204         goto error; | 172         goto error; | 
| 205       args.push_back(arg); | 173       args.push_back(arg); | 
| 206     } | 174     } | 
| 207 | 175 | 
| 208     if (!pickle.ReadInt(&iter, &numfds)) | 176     if (!pickle.ReadInt(&iter, &numfds)) | 
| 209       goto error; | 177       goto error; | 
| 210     if (numfds != static_cast<int>(fds.size())) | 178     if (numfds != static_cast<int>(fds.size())) | 
| 211       goto error; | 179       goto error; | 
| 212 | 180 | 
| 213     for (int i = 0; i < numfds; ++i) { | 181     for (int i = 0; i < numfds; ++i) { | 
| 214       base::GlobalDescriptors::Key key; | 182       base::GlobalDescriptors::Key key; | 
| 215       if (!pickle.ReadUInt32(&iter, &key)) | 183       if (!pickle.ReadUInt32(&iter, &key)) | 
| 216         goto error; | 184         goto error; | 
| 217       mapping.push_back(std::make_pair(key, fds[i])); | 185       mapping.push_back(std::make_pair(key, fds[i])); | 
| 218     } | 186     } | 
| 219 | 187 | 
| 220     mapping.push_back(std::make_pair( | 188     mapping.push_back(std::make_pair( | 
| 221         static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); | 189         static_cast<uint32_t>(kSandboxIPCChannel), 5)); | 
| 222 |  | 
| 223     if (g_suid_sandbox_active) { |  | 
| 224       dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); |  | 
| 225       if (dummy_fd < 0) |  | 
| 226         goto error; |  | 
| 227 |  | 
| 228       if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) |  | 
| 229         goto error; |  | 
| 230     } |  | 
| 231 | 190 | 
| 232     child = fork(); | 191     child = fork(); | 
| 233 | 192 | 
| 234     if (!child) { | 193     if (!child) { | 
| 235       close(kBrowserDescriptor);  // our socket from the browser | 194       close(3);  // our socket from the browser is in fd 3 | 
| 236       close(kZygoteIdDescriptor);  // another socket from the browser |  | 
| 237       Singleton<base::GlobalDescriptors>()->Reset(mapping); | 195       Singleton<base::GlobalDescriptors>()->Reset(mapping); | 
| 238 | 196 | 
| 239       // Reset the process-wide command line to our new command line. | 197       // Reset the process-wide command line to our new command line. | 
| 240       CommandLine::Reset(); | 198       CommandLine::Reset(); | 
| 241       CommandLine::Init(0, NULL); | 199       CommandLine::Init(0, NULL); | 
| 242       CommandLine::ForCurrentProcess()->InitFromArgv(args); | 200       CommandLine::ForCurrentProcess()->InitFromArgv(args); | 
| 243       CommandLine::SetProcTitle(); | 201       CommandLine::SetProcTitle(); | 
| 244       return true; | 202       return true; | 
| 245     } else if (child < 0) { |  | 
| 246       LOG(ERROR) << "Zygote could not fork"; |  | 
| 247       goto error; |  | 
| 248     } | 203     } | 
| 249 | 204 | 
| 250     { |  | 
| 251       base::ProcessId proc_id; |  | 
| 252       if (g_suid_sandbox_active) { |  | 
| 253         close(dummy_fd); |  | 
| 254         dummy_fd = -1; |  | 
| 255         uint8_t reply_buf[512]; |  | 
| 256         Pickle request; |  | 
| 257         request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE); |  | 
| 258         request.WriteUInt64(dummy_inode); |  | 
| 259 |  | 
| 260         const ssize_t r = base::SendRecvMsg(kMagicSandboxIPCDescriptor, |  | 
| 261                                             reply_buf, sizeof(reply_buf), |  | 
| 262                                             NULL, request); |  | 
| 263         if (r == -1) |  | 
| 264           goto error; |  | 
| 265 |  | 
| 266         Pickle reply(reinterpret_cast<char*>(reply_buf), r); |  | 
| 267         void* iter2 = NULL; |  | 
| 268         if (!reply.ReadInt(&iter2, &proc_id)) |  | 
| 269           goto error; |  | 
| 270         real_pids_to_sandbox_pids[proc_id] = child; |  | 
| 271       } else { |  | 
| 272         proc_id = child; |  | 
| 273       } |  | 
| 274 |  | 
| 275       for (std::vector<int>::const_iterator |  | 
| 276            i = fds.begin(); i != fds.end(); ++i) |  | 
| 277         close(*i); |  | 
| 278 |  | 
| 279       HANDLE_EINTR(write(fd, &proc_id, sizeof(proc_id))); |  | 
| 280       return false; |  | 
| 281     } |  | 
| 282 |  | 
| 283    error: |  | 
| 284     LOG(ERROR) << "Error parsing fork request from browser"; |  | 
| 285     for (std::vector<int>::const_iterator | 205     for (std::vector<int>::const_iterator | 
| 286          i = fds.begin(); i != fds.end(); ++i) | 206          i = fds.begin(); i != fds.end(); ++i) | 
| 287       close(*i); | 207       close(*i); | 
| 288     if (dummy_fd >= 0) | 208 | 
| 289       close(dummy_fd); | 209     HANDLE_EINTR(write(fd, &child, sizeof(child))); | 
|  | 210     return false; | 
|  | 211 | 
|  | 212    error: | 
|  | 213     LOG(WARNING) << "Error parsing fork request from browser"; | 
|  | 214     for (std::vector<int>::const_iterator | 
|  | 215          i = fds.begin(); i != fds.end(); ++i) | 
|  | 216       close(*i); | 
| 290     return false; | 217     return false; | 
| 291   } | 218   } | 
| 292 |  | 
| 293   // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs |  | 
| 294   // fork() returns are not the real PIDs, so we need to map the Real PIDS |  | 
| 295   // into the sandbox PID namespace. |  | 
| 296   typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; |  | 
| 297   ProcessMap real_pids_to_sandbox_pids; |  | 
| 298 }; | 219 }; | 
| 299 | 220 | 
| 300 // With SELinux we can carve out a precise sandbox, so we don't have to play | 221 // With SELinux we can carve out a precise sandbox, so we don't have to play | 
| 301 // with intercepting libc calls. | 222 // with intercepting libc calls. | 
| 302 #if !defined(CHROMIUM_SELINUX) | 223 #if !defined(CHROMIUM_SELINUX) | 
| 303 | 224 | 
| 304 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, | 225 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, | 
| 305                                         char* timezone_out, | 226                                         char* timezone_out, | 
| 306                                         size_t timezone_out_len) { | 227                                         size_t timezone_out_len) { | 
| 307   Pickle request; | 228   Pickle request; | 
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 474 } | 395 } | 
| 475 | 396 | 
| 476 #if !defined(CHROMIUM_SELINUX) | 397 #if !defined(CHROMIUM_SELINUX) | 
| 477 static bool EnterSandbox() { | 398 static bool EnterSandbox() { | 
| 478   const char* const sandbox_fd_string = getenv("SBX_D"); | 399   const char* const sandbox_fd_string = getenv("SBX_D"); | 
| 479   if (sandbox_fd_string) { | 400   if (sandbox_fd_string) { | 
| 480     // The SUID sandbox sets this environment variable to a file descriptor | 401     // The SUID sandbox sets this environment variable to a file descriptor | 
| 481     // over which we can signal that we have completed our startup and can be | 402     // over which we can signal that we have completed our startup and can be | 
| 482     // chrooted. | 403     // chrooted. | 
| 483 | 404 | 
| 484     g_suid_sandbox_active = true; |  | 
| 485 |  | 
| 486     char* endptr; | 405     char* endptr; | 
| 487     const long fd_long = strtol(sandbox_fd_string, &endptr, 10); | 406     const long fd_long = strtol(sandbox_fd_string, &endptr, 10); | 
| 488     if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX) | 407     if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX) | 
| 489       return false; | 408       return false; | 
| 490     const int fd = fd_long; | 409     const int fd = fd_long; | 
| 491 | 410 | 
| 492     PreSandboxInit(); | 411     PreSandboxInit(); | 
| 493 | 412 | 
| 494     static const char kChrootMe = 'C'; | 413     static const char kChrootMe = 'C'; | 
| 495     static const char kChrootMeSuccess = 'O'; | 414     static const char kChrootMeSuccess = 'O'; | 
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 583 | 502 | 
| 584   if (!EnterSandbox()) { | 503   if (!EnterSandbox()) { | 
| 585     LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " | 504     LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " | 
| 586                << errno << ")"; | 505                << errno << ")"; | 
| 587     return false; | 506     return false; | 
| 588   } | 507   } | 
| 589 | 508 | 
| 590   Zygote zygote; | 509   Zygote zygote; | 
| 591   return zygote.ProcessRequests(); | 510   return zygote.ProcessRequests(); | 
| 592 } | 511 } | 
| OLD | NEW | 
|---|