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 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox | 5 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox |
6 | 6 |
7 #define _GNU_SOURCE | 7 #define _GNU_SOURCE |
8 #include <asm/unistd.h> | 8 #include <asm/unistd.h> |
9 #include <errno.h> | 9 #include <errno.h> |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
11 #include <sched.h> | 11 #include <sched.h> |
12 #include <signal.h> | 12 #include <signal.h> |
13 #include <stdarg.h> | 13 #include <stdarg.h> |
| 14 #include <stdbool.h> |
| 15 #include <stdint.h> |
14 #include <stdio.h> | 16 #include <stdio.h> |
15 #include <stdlib.h> | 17 #include <stdlib.h> |
16 #include <string.h> | 18 #include <string.h> |
17 #include <sys/prctl.h> | 19 #include <sys/prctl.h> |
18 #include <sys/resource.h> | 20 #include <sys/resource.h> |
19 #include <sys/socket.h> | 21 #include <sys/socket.h> |
20 #include <sys/stat.h> | 22 #include <sys/stat.h> |
21 #include <sys/time.h> | 23 #include <sys/time.h> |
22 #include <sys/types.h> | 24 #include <sys/types.h> |
23 #include <unistd.h> | 25 #include <unistd.h> |
24 #include <stdbool.h> | |
25 | 26 |
| 27 #include "linux_util.h" |
26 #include "suid_unsafe_environment_variables.h" | 28 #include "suid_unsafe_environment_variables.h" |
27 | 29 |
28 #if !defined(CLONE_NEWPID) | 30 #if !defined(CLONE_NEWPID) |
29 #define CLONE_NEWPID 0x20000000 | 31 #define CLONE_NEWPID 0x20000000 |
30 #endif | 32 #endif |
31 | 33 |
32 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; | 34 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; |
33 | 35 |
34 // These are the magic byte values which the sandboxed process uses to request | 36 // These are the magic byte values which the sandboxed process uses to request |
35 // that it be chrooted. | 37 // that it be chrooted. |
36 static const char kMsgChrootMe = 'C'; | 38 static const char kMsgChrootMe = 'C'; |
37 static const char kMsgChrootSuccessful = 'O'; | 39 static const char kMsgChrootSuccessful = 'O'; |
38 | 40 |
39 static void FatalError(const char *msg, ...) | 41 static void FatalError(const char *msg, ...) |
40 __attribute__((noreturn, format(printf,1,2))); | 42 __attribute__((noreturn, format(printf, 1, 2))); |
41 | 43 |
42 static void FatalError(const char *msg, ...) { | 44 static void FatalError(const char *msg, ...) { |
43 va_list ap; | 45 va_list ap; |
44 va_start(ap, msg); | 46 va_start(ap, msg); |
45 | 47 |
46 vfprintf(stderr, msg, ap); | 48 vfprintf(stderr, msg, ap); |
47 fprintf(stderr, ": %s\n", strerror(errno)); | 49 fprintf(stderr, ": %s\n", strerror(errno)); |
48 fflush(stderr); | 50 fflush(stderr); |
49 exit(1); | 51 exit(1); |
50 } | 52 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 if (pid == -1) { | 104 if (pid == -1) { |
103 perror("clone"); | 105 perror("clone"); |
104 close(sv[0]); | 106 close(sv[0]); |
105 close(sv[1]); | 107 close(sv[1]); |
106 return -1; | 108 return -1; |
107 } | 109 } |
108 | 110 |
109 if (pid == 0) { | 111 if (pid == 0) { |
110 // We share our files structure with an untrusted process. As a security in | 112 // We share our files structure with an untrusted process. As a security in |
111 // depth measure, we make sure that we can't open anything by mistake. | 113 // depth measure, we make sure that we can't open anything by mistake. |
112 // TODO: drop CAP_SYS_RESOURCE / use SECURE_NOROOT | 114 // TODO(agl): drop CAP_SYS_RESOURCE / use SECURE_NOROOT |
113 | 115 |
114 const struct rlimit nofile = {0, 0}; | 116 const struct rlimit nofile = {0, 0}; |
115 if (setrlimit(RLIMIT_NOFILE, &nofile)) | 117 if (setrlimit(RLIMIT_NOFILE, &nofile)) |
116 FatalError("Setting RLIMIT_NOFILE"); | 118 FatalError("Setting RLIMIT_NOFILE"); |
117 | 119 |
118 if (close(sv[1])) | 120 if (close(sv[1])) |
119 FatalError("close"); | 121 FatalError("close"); |
120 | 122 |
121 // wait for message | 123 // wait for message |
122 char msg; | 124 char msg; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 | 253 |
252 if (setresuid(ruid, ruid, ruid)) { | 254 if (setresuid(ruid, ruid, ruid)) { |
253 perror("setresuid"); | 255 perror("setresuid"); |
254 return false; | 256 return false; |
255 } | 257 } |
256 | 258 |
257 return true; | 259 return true; |
258 } | 260 } |
259 | 261 |
260 static bool SetupChildEnvironment() { | 262 static bool SetupChildEnvironment() { |
261 | |
262 unsigned i; | 263 unsigned i; |
263 | 264 |
264 // ld.so may have cleared several environment variables because we are SUID. | 265 // ld.so may have cleared several environment variables because we are SUID. |
265 // However, the child process might need them so zygote_host_linux.cc saves a | 266 // However, the child process might need them so zygote_host_linux.cc saves a |
266 // copy in SANDBOX_$x. This is safe because we have dropped root by this | 267 // copy in SANDBOX_$x. This is safe because we have dropped root by this |
267 // point, so we can only exec a binary with the permissions of the user who | 268 // point, so we can only exec a binary with the permissions of the user who |
268 // ran us in the first place. | 269 // ran us in the first place. |
269 | 270 |
270 for (i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) { | 271 for (i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) { |
271 const char* const envvar = kSUIDUnsafeEnvironmentVariables[i]; | 272 const char* const envvar = kSUIDUnsafeEnvironmentVariables[i]; |
(...skipping 12 matching lines...) Expand all Loading... |
284 | 285 |
285 return true; | 286 return true; |
286 } | 287 } |
287 | 288 |
288 int main(int argc, char **argv) { | 289 int main(int argc, char **argv) { |
289 if (argc <= 1) { | 290 if (argc <= 1) { |
290 fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]); | 291 fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]); |
291 return 1; | 292 return 1; |
292 } | 293 } |
293 | 294 |
| 295 // In the SUID sandbox, if we succeed in calling MoveToNewPIDNamespace() |
| 296 // below, then the zygote and all the renderers are in an alternate PID |
| 297 // namespace and do not know their real PIDs. As such, they report the wrong |
| 298 // PIDs to the task manager. |
| 299 // |
| 300 // To fix this, when the zygote spawns a new renderer, it gives the renderer |
| 301 // a dummy socket, which has a unique inode number. Then it asks the sandbox |
| 302 // host to find the PID of the process holding that fd by searching /proc. |
| 303 // |
| 304 // Since the zygote and renderers are all spawned by this setuid executable, |
| 305 // their entries in /proc are owned by root and only readable by root. In |
| 306 // order to search /proc for the fd we want, this setuid executable has to |
| 307 // double as a helper and perform the search. The code block below does this |
| 308 // when you call it with --find-inode INODE_NUMBER. |
| 309 if (argc == 3 && (0 == strcmp(argv[1], kFindInodeSwitch))) { |
| 310 pid_t pid; |
| 311 char *endptr; |
| 312 ino_t inode = strtoull(argv[2], &endptr, 10); |
| 313 if (inode == ULLONG_MAX || *endptr) |
| 314 return 1; |
| 315 if (!FindProcessHoldingSocket(&pid, inode)) |
| 316 return 1; |
| 317 printf("%d\n", pid); |
| 318 return 0; |
| 319 } |
| 320 |
294 if (!MoveToNewPIDNamespace()) | 321 if (!MoveToNewPIDNamespace()) |
295 return 1; | 322 return 1; |
296 if (!SpawnChrootHelper()) | 323 if (!SpawnChrootHelper()) |
297 return 1; | 324 return 1; |
298 if (!DropRoot()) | 325 if (!DropRoot()) |
299 return 1; | 326 return 1; |
300 if (!SetupChildEnvironment()) | 327 if (!SetupChildEnvironment()) |
301 return 1; | 328 return 1; |
302 | 329 |
303 execv(argv[1], &argv[1]); | 330 execv(argv[1], &argv[1]); |
304 FatalError("execv failed"); | 331 FatalError("execv failed"); |
305 | 332 |
306 return 1; | 333 return 1; |
307 } | 334 } |
OLD | NEW |