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

Side by Side Diff: chrome/browser/zygote_main_linux.cc

Issue 361002: Add support for getting the real process id from within the suid sandbox. The... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/zygote_host_linux.cc ('k') | chrome/chrome.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <sys/epoll.h>
7 #include <sys/prctl.h>
8 #include <sys/signal.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
6 #include <unistd.h> 12 #include <unistd.h>
7 #include <sys/epoll.h> 13
8 #include <sys/types.h> 14 #if defined(CHROMIUM_SELINUX)
9 #include <sys/socket.h> 15 #include <selinux/selinux.h>
10 #include <sys/signal.h> 16 #include <selinux/context.h>
11 #include <sys/prctl.h> 17 #endif
12 #include <sys/wait.h>
13 18
14 #include "base/basictypes.h" 19 #include "base/basictypes.h"
15 #include "base/command_line.h" 20 #include "base/command_line.h"
16 #include "base/eintr_wrapper.h" 21 #include "base/eintr_wrapper.h"
17 #include "base/global_descriptors_posix.h" 22 #include "base/global_descriptors_posix.h"
23 #include "base/hash_tables.h"
24 #include "base/linux_util.h"
18 #include "base/path_service.h" 25 #include "base/path_service.h"
19 #include "base/pickle.h" 26 #include "base/pickle.h"
20 #include "base/rand_util.h" 27 #include "base/rand_util.h"
21 #include "base/scoped_ptr.h" 28 #include "base/scoped_ptr.h"
22 #include "base/sys_info.h" 29 #include "base/sys_info.h"
23 #include "base/unix_domain_socket_posix.h" 30 #include "base/unix_domain_socket_posix.h"
24 31
25 #include "chrome/browser/zygote_host_linux.h" 32 #include "chrome/browser/zygote_host_linux.h"
26 #include "chrome/common/chrome_descriptors.h" 33 #include "chrome/common/chrome_descriptors.h"
27 #include "chrome/common/chrome_switches.h" 34 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/main_function_params.h" 35 #include "chrome/common/main_function_params.h"
29 #include "chrome/common/process_watcher.h" 36 #include "chrome/common/process_watcher.h"
30 #include "chrome/common/sandbox_methods_linux.h" 37 #include "chrome/common/sandbox_methods_linux.h"
31 38
32 #include "media/base/media.h" 39 #include "media/base/media.h"
33 40
34 #include "skia/ext/SkFontHost_fontconfig_control.h" 41 #include "skia/ext/SkFontHost_fontconfig_control.h"
35 42
36 #if defined(CHROMIUM_SELINUX)
37 #include <selinux/selinux.h>
38 #include <selinux/context.h>
39 #endif
40
41 #include "unicode/timezone.h" 43 #include "unicode/timezone.h"
42 44
43 // http://code.google.com/p/chromium/wiki/LinuxZygote 45 // http://code.google.com/p/chromium/wiki/LinuxZygote
44 46
47 static const int kBrowserDescriptor = 3;
45 static const int kMagicSandboxIPCDescriptor = 5; 48 static const int kMagicSandboxIPCDescriptor = 5;
49 static const int kZygoteIdDescriptor = 7;
50 static bool g_suid_sandbox_active = false;
46 51
47 // This is the object which implements the zygote. The ZygoteMain function, 52 // This is the object which implements the zygote. The ZygoteMain function,
48 // which is called from ChromeMain, at the the bottom and simple constructs one 53 // which is called from ChromeMain, at the the bottom and simple constructs one
49 // of these objects and runs it. 54 // of these objects and runs it.
50 class Zygote { 55 class Zygote {
51 public: 56 public:
52 bool ProcessRequests() { 57 bool ProcessRequests() {
53 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the 58 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
54 // browser on it. 59 // browser on it.
55 // A SOCK_DGRAM is installed in fd 4. This is the sandbox IPC channel. 60 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
56 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC 61 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
57 62
58 // We need to accept SIGCHLD, even though our handler is a no-op because 63 // We need to accept SIGCHLD, even though our handler is a no-op because
59 // otherwise we cannot wait on children. (According to POSIX 2001.) 64 // otherwise we cannot wait on children. (According to POSIX 2001.)
60 struct sigaction action; 65 struct sigaction action;
61 memset(&action, 0, sizeof(action)); 66 memset(&action, 0, sizeof(action));
62 action.sa_handler = SIGCHLDHandler; 67 action.sa_handler = SIGCHLDHandler;
63 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); 68 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
64 69
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
65 for (;;) { 79 for (;;) {
66 if (HandleRequestFromBrowser(3)) 80 if (HandleRequestFromBrowser(kBrowserDescriptor))
67 return true; 81 return true;
68 } 82 }
69 } 83 }
70 84
71 private: 85 private:
72 // See comment below, where sigaction is called. 86 // See comment below, where sigaction is called.
73 static void SIGCHLDHandler(int signal) { } 87 static void SIGCHLDHandler(int signal) { }
74 88
75 // --------------------------------------------------------------------------- 89 // ---------------------------------------------------------------------------
76 // Requests from the browser... 90 // Requests from the browser...
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 } 129 }
116 } 130 }
117 131
118 LOG(WARNING) << "Error parsing message from browser"; 132 LOG(WARNING) << "Error parsing message from browser";
119 for (std::vector<int>::const_iterator 133 for (std::vector<int>::const_iterator
120 i = fds.begin(); i != fds.end(); ++i) 134 i = fds.begin(); i != fds.end(); ++i)
121 close(*i); 135 close(*i);
122 return false; 136 return false;
123 } 137 }
124 138
125 bool HandleReapRequest(int fd, Pickle& pickle, void* iter) { 139 bool HandleReapRequest(int fd, const Pickle& pickle, void* iter) {
126 pid_t child; 140 base::ProcessId child;
141 base::ProcessId actual_child;
127 142
128 if (!pickle.ReadInt(&iter, &child)) { 143 if (!pickle.ReadInt(&iter, &child)) {
129 LOG(WARNING) << "Error parsing reap request from browser"; 144 LOG(WARNING) << "Error parsing reap request from browser";
130 return false; 145 return false;
131 } 146 }
132 147
133 ProcessWatcher::EnsureProcessTerminated(child); 148 if (g_suid_sandbox_active) {
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);
134 158
135 return false; 159 return false;
136 } 160 }
137 161
138 bool HandleDidProcessCrash(int fd, Pickle& pickle, void* iter) { 162 bool HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) {
139 base::ProcessHandle child; 163 base::ProcessHandle child;
140 164
141 if (!pickle.ReadInt(&iter, &child)) { 165 if (!pickle.ReadInt(&iter, &child)) {
142 LOG(WARNING) << "Error parsing DidProcessCrash request from browser"; 166 LOG(WARNING) << "Error parsing DidProcessCrash request from browser";
143 return false; 167 return false;
144 } 168 }
145 169
146 bool child_exited; 170 bool child_exited;
147 bool did_crash = base::DidProcessCrash(&child_exited, child); 171 bool did_crash;
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;
148 178
149 Pickle write_pickle; 179 Pickle write_pickle;
150 write_pickle.WriteBool(did_crash); 180 write_pickle.WriteBool(did_crash);
151 write_pickle.WriteBool(child_exited); 181 write_pickle.WriteBool(child_exited);
152 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); 182 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));
153 183
154 return false; 184 return false;
155 } 185 }
156 186
157 // Handle a 'fork' request from the browser: this means that the browser 187 // Handle a 'fork' request from the browser: this means that the browser
158 // wishes to start a new renderer. 188 // wishes to start a new renderer.
159 bool HandleForkRequest(int fd, Pickle& pickle, void* iter, 189 bool HandleForkRequest(int fd, const Pickle& pickle, void* iter,
160 std::vector<int>& fds) { 190 std::vector<int>& fds) {
161 std::vector<std::string> args; 191 std::vector<std::string> args;
162 int argc, numfds; 192 int argc, numfds;
163 base::GlobalDescriptors::Mapping mapping; 193 base::GlobalDescriptors::Mapping mapping;
164 pid_t child; 194 base::ProcessId child;
195 uint64_t dummy_inode = 0;
196 int dummy_fd = -1;
165 197
166 if (!pickle.ReadInt(&iter, &argc)) 198 if (!pickle.ReadInt(&iter, &argc))
167 goto error; 199 goto error;
168 200
169 for (int i = 0; i < argc; ++i) { 201 for (int i = 0; i < argc; ++i) {
170 std::string arg; 202 std::string arg;
171 if (!pickle.ReadString(&iter, &arg)) 203 if (!pickle.ReadString(&iter, &arg))
172 goto error; 204 goto error;
173 args.push_back(arg); 205 args.push_back(arg);
174 } 206 }
175 207
176 if (!pickle.ReadInt(&iter, &numfds)) 208 if (!pickle.ReadInt(&iter, &numfds))
177 goto error; 209 goto error;
178 if (numfds != static_cast<int>(fds.size())) 210 if (numfds != static_cast<int>(fds.size()))
179 goto error; 211 goto error;
180 212
181 for (int i = 0; i < numfds; ++i) { 213 for (int i = 0; i < numfds; ++i) {
182 base::GlobalDescriptors::Key key; 214 base::GlobalDescriptors::Key key;
183 if (!pickle.ReadUInt32(&iter, &key)) 215 if (!pickle.ReadUInt32(&iter, &key))
184 goto error; 216 goto error;
185 mapping.push_back(std::make_pair(key, fds[i])); 217 mapping.push_back(std::make_pair(key, fds[i]));
186 } 218 }
187 219
188 mapping.push_back(std::make_pair( 220 mapping.push_back(std::make_pair(
189 static_cast<uint32_t>(kSandboxIPCChannel), 5)); 221 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
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 }
190 231
191 child = fork(); 232 child = fork();
192 233
193 if (!child) { 234 if (!child) {
194 close(3); // our socket from the browser is in fd 3 235 close(kBrowserDescriptor); // our socket from the browser
236 close(kZygoteIdDescriptor); // another socket from the browser
195 Singleton<base::GlobalDescriptors>()->Reset(mapping); 237 Singleton<base::GlobalDescriptors>()->Reset(mapping);
196 238
197 // Reset the process-wide command line to our new command line. 239 // Reset the process-wide command line to our new command line.
198 CommandLine::Reset(); 240 CommandLine::Reset();
199 CommandLine::Init(0, NULL); 241 CommandLine::Init(0, NULL);
200 CommandLine::ForCurrentProcess()->InitFromArgv(args); 242 CommandLine::ForCurrentProcess()->InitFromArgv(args);
201 CommandLine::SetProcTitle(); 243 CommandLine::SetProcTitle();
202 return true; 244 return true;
245 } else if (child < 0) {
246 LOG(ERROR) << "Zygote could not fork";
247 goto error;
203 } 248 }
204 249
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";
205 for (std::vector<int>::const_iterator 285 for (std::vector<int>::const_iterator
206 i = fds.begin(); i != fds.end(); ++i) 286 i = fds.begin(); i != fds.end(); ++i)
207 close(*i); 287 close(*i);
208 288 if (dummy_fd >= 0)
209 HANDLE_EINTR(write(fd, &child, sizeof(child))); 289 close(dummy_fd);
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);
217 return false; 290 return false;
218 } 291 }
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;
219 }; 298 };
220 299
221 // With SELinux we can carve out a precise sandbox, so we don't have to play 300 // With SELinux we can carve out a precise sandbox, so we don't have to play
222 // with intercepting libc calls. 301 // with intercepting libc calls.
223 #if !defined(CHROMIUM_SELINUX) 302 #if !defined(CHROMIUM_SELINUX)
224 303
225 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, 304 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
226 char* timezone_out, 305 char* timezone_out,
227 size_t timezone_out_len) { 306 size_t timezone_out_len) {
228 Pickle request; 307 Pickle request;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 } 474 }
396 475
397 #if !defined(CHROMIUM_SELINUX) 476 #if !defined(CHROMIUM_SELINUX)
398 static bool EnterSandbox() { 477 static bool EnterSandbox() {
399 const char* const sandbox_fd_string = getenv("SBX_D"); 478 const char* const sandbox_fd_string = getenv("SBX_D");
400 if (sandbox_fd_string) { 479 if (sandbox_fd_string) {
401 // The SUID sandbox sets this environment variable to a file descriptor 480 // The SUID sandbox sets this environment variable to a file descriptor
402 // over which we can signal that we have completed our startup and can be 481 // over which we can signal that we have completed our startup and can be
403 // chrooted. 482 // chrooted.
404 483
484 g_suid_sandbox_active = true;
485
405 char* endptr; 486 char* endptr;
406 const long fd_long = strtol(sandbox_fd_string, &endptr, 10); 487 const long fd_long = strtol(sandbox_fd_string, &endptr, 10);
407 if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX) 488 if (!*sandbox_fd_string || *endptr || fd_long < 0 || fd_long > INT_MAX)
408 return false; 489 return false;
409 const int fd = fd_long; 490 const int fd = fd_long;
410 491
411 PreSandboxInit(); 492 PreSandboxInit();
412 493
413 static const char kChrootMe = 'C'; 494 static const char kChrootMe = 'C';
414 static const char kChrootMeSuccess = 'O'; 495 static const char kChrootMeSuccess = 'O';
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 583
503 if (!EnterSandbox()) { 584 if (!EnterSandbox()) {
504 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " 585 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
505 << errno << ")"; 586 << errno << ")";
506 return false; 587 return false;
507 } 588 }
508 589
509 Zygote zygote; 590 Zygote zygote;
510 return zygote.ProcessRequests(); 591 return zygote.ProcessRequests();
511 } 592 }
OLDNEW
« no previous file with comments | « chrome/browser/zygote_host_linux.cc ('k') | chrome/chrome.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698