OLD | NEW |
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> |
(...skipping 24 matching lines...) Expand all Loading... |
35 | 35 |
36 #if !defined(CLONE_NEWPID) | 36 #if !defined(CLONE_NEWPID) |
37 #define CLONE_NEWPID 0x20000000 | 37 #define CLONE_NEWPID 0x20000000 |
38 #endif | 38 #endif |
39 #if !defined(CLONE_NEWNET) | 39 #if !defined(CLONE_NEWNET) |
40 #define CLONE_NEWNET 0x40000000 | 40 #define CLONE_NEWNET 0x40000000 |
41 #endif | 41 #endif |
42 | 42 |
43 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; | 43 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; |
44 static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID"; | 44 static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID"; |
| 45 |
| 46 // Should be kept in sync with base/linux_util.h |
| 47 static const long kSUIDSandboxApiNumber = 0; |
| 48 static const char kSandboxEnvironmentApiRequest[] = "SBX_CHROME_API_RQ"; |
| 49 static const char kSandboxEnvironmentApiProvides[] = "SBX_CHROME_API_PRV"; |
| 50 |
45 // This number must be kept in sync with common/zygote_commands_linux.h | 51 // This number must be kept in sync with common/zygote_commands_linux.h |
46 static const int kZygoteIdFd = 7; | 52 static const int kZygoteIdFd = 7; |
47 | 53 |
48 // These are the magic byte values which the sandboxed process uses to request | 54 // These are the magic byte values which the sandboxed process uses to request |
49 // that it be chrooted. | 55 // that it be chrooted. |
50 static const char kMsgChrootMe = 'C'; | 56 static const char kMsgChrootMe = 'C'; |
51 static const char kMsgChrootSuccessful = 'O'; | 57 static const char kMsgChrootSuccessful = 'O'; |
52 | 58 |
53 static bool DropRoot(); | 59 static bool DropRoot(); |
54 | 60 |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 setenv(envvar, value, 1 /* overwrite */); | 360 setenv(envvar, value, 1 /* overwrite */); |
355 unsetenv(saved_envvar); | 361 unsetenv(saved_envvar); |
356 } | 362 } |
357 | 363 |
358 free(saved_envvar); | 364 free(saved_envvar); |
359 } | 365 } |
360 | 366 |
361 return true; | 367 return true; |
362 } | 368 } |
363 | 369 |
| 370 bool CheckAndExportApiVersion() { |
| 371 // Check the environment to see if a specific API version was requested. |
| 372 // assume version 0 if none. |
| 373 long api_number = -1; |
| 374 char *api_string = getenv(kSandboxEnvironmentApiRequest); |
| 375 if (!api_string) { |
| 376 api_number = 0; |
| 377 } else { |
| 378 errno = 0; |
| 379 char* endptr = NULL; |
| 380 api_number = strtol(api_string, &endptr, 10); |
| 381 if (!endptr || *endptr || errno != 0) |
| 382 return false; |
| 383 } |
| 384 |
| 385 // Warn only for now. |
| 386 if (api_number != kSUIDSandboxApiNumber) { |
| 387 fprintf(stderr, "The setuid sandbox provides API version %ld, " |
| 388 "but you need %ld\n" |
| 389 "Please read " |
| 390 "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment." |
| 391 "\n\n", |
| 392 kSUIDSandboxApiNumber, |
| 393 api_number); |
| 394 } |
| 395 |
| 396 // Export our version so that the sandboxed process can verify it did not |
| 397 // use an old sandbox. |
| 398 char version_string[64]; |
| 399 snprintf(version_string, sizeof(version_string), "%ld", |
| 400 kSUIDSandboxApiNumber); |
| 401 if (setenv(kSandboxEnvironmentApiProvides, version_string, 1)) { |
| 402 perror("setenv"); |
| 403 return false; |
| 404 } |
| 405 |
| 406 return true; |
| 407 } |
| 408 |
364 int main(int argc, char **argv) { | 409 int main(int argc, char **argv) { |
365 if (argc <= 1) { | 410 if (argc <= 1) { |
366 if (argc == 0) { | 411 if (argc <= 0) { |
367 return 1; | 412 return 1; |
368 } | 413 } |
369 | 414 |
370 fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]); | 415 fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]); |
371 return 1; | 416 return 1; |
372 } | 417 } |
373 | 418 |
| 419 // Allow someone to query our API version |
| 420 if (argc == 2 && 0 == strcmp(argv[1], kSuidSandboxGetApiSwitch)) { |
| 421 printf("%ld\n", kSUIDSandboxApiNumber); |
| 422 return 0; |
| 423 } |
| 424 |
374 // In the SUID sandbox, if we succeed in calling MoveToNewNamespaces() | 425 // In the SUID sandbox, if we succeed in calling MoveToNewNamespaces() |
375 // below, then the zygote and all the renderers are in an alternate PID | 426 // below, then the zygote and all the renderers are in an alternate PID |
376 // namespace and do not know their real PIDs. As such, they report the wrong | 427 // namespace and do not know their real PIDs. As such, they report the wrong |
377 // PIDs to the task manager. | 428 // PIDs to the task manager. |
378 // | 429 // |
379 // To fix this, when the zygote spawns a new renderer, it gives the renderer | 430 // To fix this, when the zygote spawns a new renderer, it gives the renderer |
380 // a dummy socket, which has a unique inode number. Then it asks the sandbox | 431 // a dummy socket, which has a unique inode number. Then it asks the sandbox |
381 // host to find the PID of the process holding that fd by searching /proc. | 432 // host to find the PID of the process holding that fd by searching /proc. |
382 // | 433 // |
383 // Since the zygote and renderers are all spawned by this setuid executable, | 434 // Since the zygote and renderers are all spawned by this setuid executable, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 if (argc == 3 && (0 == strcmp(argv[1], kAdjustLowMemMarginSwitch))) { | 470 if (argc == 3 && (0 == strcmp(argv[1], kAdjustLowMemMarginSwitch))) { |
420 char* endptr = NULL; | 471 char* endptr = NULL; |
421 errno = 0; | 472 errno = 0; |
422 unsigned long margin_mb = strtoul(argv[2], &endptr, 10); | 473 unsigned long margin_mb = strtoul(argv[2], &endptr, 10); |
423 if (!endptr || *endptr || errno != 0) | 474 if (!endptr || *endptr || errno != 0) |
424 return 1; | 475 return 1; |
425 return AdjustLowMemoryMargin(margin_mb); | 476 return AdjustLowMemoryMargin(margin_mb); |
426 } | 477 } |
427 #endif | 478 #endif |
428 | 479 |
| 480 // Protect the core setuid sandbox functionality with an API version |
| 481 if (!CheckAndExportApiVersion()) { |
| 482 return 1; |
| 483 } |
| 484 |
429 if (!MoveToNewNamespaces()) | 485 if (!MoveToNewNamespaces()) |
430 return 1; | 486 return 1; |
431 if (!SpawnChrootHelper()) | 487 if (!SpawnChrootHelper()) |
432 return 1; | 488 return 1; |
433 if (!DropRoot()) | 489 if (!DropRoot()) |
434 return 1; | 490 return 1; |
435 if (!SetupChildEnvironment()) | 491 if (!SetupChildEnvironment()) |
436 return 1; | 492 return 1; |
437 | 493 |
438 execv(argv[1], &argv[1]); | 494 execv(argv[1], &argv[1]); |
439 FatalError("execv failed"); | 495 FatalError("execv failed"); |
440 | 496 |
441 return 1; | 497 return 1; |
442 } | 498 } |
OLD | NEW |