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

Side by Side Diff: sandbox/linux/suid/sandbox.c

Issue 10447135: Don't fork Zygote as a background process (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: minor update Created 8 years, 6 months 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox 5 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
6 6
7 #include "sandbox.h" 7 #include "sandbox.h"
8 8
9 #define _GNU_SOURCE 9 #define _GNU_SOURCE
10 #include <asm/unistd.h> 10 #include <asm/unistd.h>
11 #include <errno.h> 11 #include <errno.h>
12 #include <fcntl.h> 12 #include <fcntl.h>
13 #include <limits.h> 13 #include <limits.h>
14 #include <sched.h> 14 #include <sched.h>
15 #include <signal.h> 15 #include <signal.h>
16 #include <stdarg.h> 16 #include <stdarg.h>
17 #include <stdbool.h> 17 #include <stdbool.h>
18 #include <stdint.h> 18 #include <stdint.h>
19 #include <stdio.h> 19 #include <stdio.h>
20 #include <stdlib.h> 20 #include <stdlib.h>
21 #include <string.h> 21 #include <string.h>
22 #include <sys/prctl.h> 22 #include <sys/prctl.h>
23 #include <sys/resource.h> 23 #include <sys/resource.h>
24 #include <sys/socket.h> 24 #include <sys/socket.h>
25 #include <sys/stat.h> 25 #include <sys/stat.h>
26 #include <sys/time.h> 26 #include <sys/time.h>
27 #include <sys/types.h> 27 #include <sys/types.h>
28 #include <sys/vfs.h> 28 #include <sys/vfs.h>
29 #include <sys/wait.h>
29 #include <unistd.h> 30 #include <unistd.h>
30 31
31 #include "linux_util.h" 32 #include "linux_util.h"
32 #include "process_util.h" 33 #include "process_util.h"
33 #include "suid_unsafe_environment_variables.h" 34 #include "suid_unsafe_environment_variables.h"
34 35
35 #if !defined(CLONE_NEWPID) 36 #if !defined(CLONE_NEWPID)
36 #define CLONE_NEWPID 0x20000000 37 #define CLONE_NEWPID 0x20000000
37 #endif 38 #endif
38 #if !defined(CLONE_NEWNET) 39 #if !defined(CLONE_NEWNET)
39 #define CLONE_NEWNET 0x40000000 40 #define CLONE_NEWNET 0x40000000
40 #endif 41 #endif
41 42
42 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; 43 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
43 static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID"; 44 static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
45 // This number must be kept in sync in with common/zygote_commands_linux.h
Jorge Lucangeli Obes 2012/06/01 15:08:07 "in with" -> "with"
46 static const int kZygoteIdFd = 7;
44 47
45 // These are the magic byte values which the sandboxed process uses to request 48 // These are the magic byte values which the sandboxed process uses to request
46 // that it be chrooted. 49 // that it be chrooted.
47 static const char kMsgChrootMe = 'C'; 50 static const char kMsgChrootMe = 'C';
48 static const char kMsgChrootSuccessful = 'O'; 51 static const char kMsgChrootSuccessful = 'O';
49 52
53 static bool DropRoot();
54
55 #define HANDLE_EINTR(x) TEMP_FAILURE_RETRY(x)
56
50 static void FatalError(const char *msg, ...) 57 static void FatalError(const char *msg, ...)
51 __attribute__((noreturn, format(printf, 1, 2))); 58 __attribute__((noreturn, format(printf, 1, 2)));
52 59
53 static void FatalError(const char *msg, ...) { 60 static void FatalError(const char *msg, ...) {
54 va_list ap; 61 va_list ap;
55 va_start(ap, msg); 62 va_start(ap, msg);
56 63
57 vfprintf(stderr, msg, ap); 64 vfprintf(stderr, msg, ap);
58 fprintf(stderr, ": %s\n", strerror(errno)); 65 fprintf(stderr, ": %s\n", strerror(errno));
59 fflush(stderr); 66 fflush(stderr);
67 va_end(ap);
60 _exit(1); 68 _exit(1);
61 } 69 }
62 70
63 // We will chroot() to the helper's /proc/self directory. Anything there will 71 // We will chroot() to the helper's /proc/self directory. Anything there will
64 // not exist anymore if we make sure to wait() for the helper. 72 // not exist anymore if we make sure to wait() for the helper.
65 // 73 //
66 // /proc/self/fdinfo or /proc/self/fd are especially safe and will be empty 74 // /proc/self/fdinfo or /proc/self/fd are especially safe and will be empty
67 // even if the helper survives as a zombie. 75 // even if the helper survives as a zombie.
68 // 76 //
69 // There is very little reason to use fdinfo/ instead of fd/ but we are 77 // There is very little reason to use fdinfo/ instead of fd/ but we are
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 193
186 if (setenv(kSandboxHelperPidEnvironmentVarName, helper_pid_str, 1)) { 194 if (setenv(kSandboxHelperPidEnvironmentVarName, helper_pid_str, 1)) {
187 perror("setenv"); 195 perror("setenv");
188 close(sv[1]); 196 close(sv[1]);
189 return false; 197 return false;
190 } 198 }
191 199
192 return true; 200 return true;
193 } 201 }
194 202
203 // Block until child_pid exits, then exit. Try to preserve the exit code.
204 static void WaitForChildAndExit(pid_t child_pid) {
205 int exit_code = -1;
206 siginfo_t reaped_child_info;
207
208 int wait_ret =
209 HANDLE_EINTR(waitid(P_PID, child_pid, &reaped_child_info, WEXITED));
210
211 if (!wait_ret && reaped_child_info.si_pid == child_pid) {
212 if (reaped_child_info.si_code == CLD_EXITED) {
213 exit_code = reaped_child_info.si_status;
214 } else {
215 // Exit with code 0 if the child got signaled.
216 exit_code = 0;
217 }
218 }
219 _exit(exit_code);
220 }
221
195 static bool MoveToNewNamespaces() { 222 static bool MoveToNewNamespaces() {
196 // These are the sets of flags which we'll try, in order. 223 // These are the sets of flags which we'll try, in order.
197 const int kCloneExtraFlags[] = { 224 const int kCloneExtraFlags[] = {
198 CLONE_NEWPID | CLONE_NEWNET, 225 CLONE_NEWPID | CLONE_NEWNET,
199 CLONE_NEWPID, 226 CLONE_NEWPID,
200 }; 227 };
201 228
229 // We need to close kZygoteIdFd before the child can continue. We use this
230 // socketpair to tell the child when to continue;
231 int sync_fds[2];
232 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
233 FatalError("Failed to create a socketpair");
234 }
235
202 for (size_t i = 0; 236 for (size_t i = 0;
203 i < sizeof(kCloneExtraFlags) / sizeof(kCloneExtraFlags[0]); 237 i < sizeof(kCloneExtraFlags) / sizeof(kCloneExtraFlags[0]);
204 i++) { 238 i++) {
205 pid_t pid = syscall(__NR_clone, SIGCHLD | kCloneExtraFlags[i], 0, 0, 0); 239 pid_t pid = syscall(__NR_clone, SIGCHLD | kCloneExtraFlags[i], 0, 0, 0);
206 240
207 if (pid > 0) 241 if (pid > 0) {
208 _exit(0); 242 if (DropRoot()) {
agl 2012/06/01 13:13:57 Preferably exceptional conditions should be handle
243 if (close(sync_fds[0]) || shutdown(sync_fds[1], SHUT_RD))
244 FatalError("Could not close socketpair");
245 // The kZygoteIdFd needs to be closed in the parent before
246 // Zygote gets started.
247 if (close(kZygoteIdFd))
248 FatalError("close");
249 // Tell our child to continue
250 if (send(sync_fds[1], "C", 1, MSG_NOSIGNAL) != 1)
agl 2012/06/01 13:13:57 HANDLE_EINTR
251 FatalError("send");
252 if (close(sync_fds[1]))
253 FatalError("close");
254 // We want to keep a full process tree and we don't want our childs to
255 // be reparented to (the outer PID namespace) init. So we wait for it.
256 WaitForChildAndExit(pid);
257 } else {
258 FatalError("Could not drop privileges");
259 }
260 // NOTREACHED
261 FatalError("Not reached");
262 }
209 263
210 if (pid == 0) { 264 if (pid == 0) {
265 if (close(sync_fds[1]) || shutdown(sync_fds[0], SHUT_WR))
266 FatalError("close ; shutdown");
Jorge Lucangeli Obes 2012/06/01 15:08:07 The "close() || shutdown()" comments are not terri
267
268 // Wait for the parent to confirm it closed kZygoteIdFd before we
269 // continue
270 char should_continue;
271 if (read(sync_fds[0], &should_continue, 1) != 1)
agl 2012/06/01 13:13:57 HANDLE_EINTR
272 FatalError("Read on socketpair");
273 if (close(sync_fds[0]))
274 FatalError("close");
275
211 if (kCloneExtraFlags[i] & CLONE_NEWPID) { 276 if (kCloneExtraFlags[i] & CLONE_NEWPID) {
212 setenv("SBX_PID_NS", "", 1 /* overwrite */); 277 setenv("SBX_PID_NS", "", 1 /* overwrite */);
213 } else { 278 } else {
214 unsetenv("SBX_PID_NS"); 279 unsetenv("SBX_PID_NS");
215 } 280 }
216 281
217 if (kCloneExtraFlags[i] & CLONE_NEWNET) { 282 if (kCloneExtraFlags[i] & CLONE_NEWNET) {
218 setenv("SBX_NET_NS", "", 1 /* overwrite */); 283 setenv("SBX_NET_NS", "", 1 /* overwrite */);
219 } else { 284 } else {
220 unsetenv("SBX_NET_NS"); 285 unsetenv("SBX_NET_NS");
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 if (!DropRoot()) 433 if (!DropRoot())
369 return 1; 434 return 1;
370 if (!SetupChildEnvironment()) 435 if (!SetupChildEnvironment())
371 return 1; 436 return 1;
372 437
373 execv(argv[1], &argv[1]); 438 execv(argv[1], &argv[1]);
374 FatalError("execv failed"); 439 FatalError("execv failed");
375 440
376 return 1; 441 return 1;
377 } 442 }
OLDNEW
« content/common/zygote_commands_linux.h ('K') | « content/common/zygote_commands_linux.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698