andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 1 | # Linux `SUID` Sandbox |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 2 | |
brettw | 20d800c | 2016-04-12 00:10:49 | [diff] [blame] | 3 | *IMPORTANT NOTE: The Linux SUID sandbox is almost but not completely removed. |
| 4 | See https://bugs.chromium.org/p/chromium/issues/detail?id=598454 |
| 5 | This page is mostly out-of-date.* |
| 6 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 7 | With [r20110](https://crrev.com/20110), Chromium on Linux can now sandbox its |
| 8 | renderers using a `SUID` helper binary. This is one of |
| 9 | [our layer-1 sandboxing solutions](linux_sandboxing.md). |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 10 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 11 | ## `SUID` helper executable |
| 12 | |
| 13 | The `SUID` helper binary is called `chrome_sandbox` and you must build it |
| 14 | separately from the main 'chrome' target. To use this sandbox, you have to |
| 15 | specify its path in the `linux_sandbox_path` GYP variable. When spawning the |
sriramsr | 55d7efa | 2015-12-09 19:49:10 | [diff] [blame] | 16 | [zygote process](linux_zygote.md), if the `SUID` sandbox is enabled, Chromium |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 17 | will check for the sandbox binary at the location specified by |
| 18 | `linux_sandbox_path`. For Google Chrome, this is set to |
| 19 | `/opt/google/chrome/chrome-sandbox`, and early version had this value hard coded |
| 20 | in `chrome/browser/zygote_host_linux.cc`. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 21 | |
| 22 | |
| 23 | In order for the sandbox to be used, the following conditions must be met: |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 24 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 25 | * The sandbox binary must be executable by the Chromium process. |
| 26 | * It must be `SUID` and executable by other. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 27 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 28 | If these conditions are met then the sandbox binary is used to launch the zygote |
| 29 | process. Once the zygote has started, it asks a helper process to chroot it to a |
| 30 | temp directory. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 31 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 32 | ## `CLONE_NEWPID` method |
| 33 | |
| 34 | The sandbox does three things to restrict the authority of a sandboxed process. |
| 35 | The `SUID` helper is responsible for the first two: |
| 36 | |
| 37 | * The `SUID` helper chroots the process. This takes away access to the |
| 38 | filesystem namespace. |
| 39 | * The `SUID` helper puts the process in a PID namespace using the |
| 40 | `CLONE_NEWPID` option to |
| 41 | [clone()](http://www.kernel.org/doc/man-pages/online/pages/man2/clone.2.html). |
| 42 | This stops the sandboxed process from being able to `ptrace()` or `kill()` |
| 43 | unsandboxed processes. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 44 | |
| 45 | In addition: |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 46 | |
| 47 | * The [Linux Zygote](linux_zygote.md) startup code sets the process to be |
| 48 | _undumpable_ using |
| 49 | [prctl()](http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html). |
| 50 | This stops sandboxed processes from being able to `ptrace()` each other. |
| 51 | More specifically, it stops the sandboxed process from being `ptrace()`'d by |
| 52 | any other process. This can be switched off with the |
| 53 | `--allow-sandbox-debugging` option. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 54 | |
| 55 | Limitations: |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 56 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 57 | * Not all kernel versions support `CLONE_NEWPID`. If the `SUID` helper is run |
| 58 | on a kernel that does not support `CLONE_NEWPID`, it will ignore the problem |
| 59 | without a warning, but the protection offered by the sandbox will be |
| 60 | substantially reduced. See LinuxPidNamespaceSupport for how to test whether |
| 61 | your system supports PID namespaces. |
| 62 | * This does not restrict network access. |
| 63 | * This does not prevent processes within a given sandbox from sending each |
| 64 | other signals or killing each other. |
| 65 | * Setting a process to be undumpable is not irreversible. A sandboxed process |
| 66 | can make itself dumpable again, opening itself up to being taken over by |
| 67 | another process (either unsandboxed or within the same sandbox). |
| 68 | * Breakpad (the crash reporting tool) makes use of this. If a process |
| 69 | crashes, Breakpad makes it dumpable in order to use ptrace() to halt |
| 70 | threads and capture the process's state at the time of the crash. This |
| 71 | opens a small window of vulnerability. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 72 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 73 | ## `setuid()` method |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 74 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 75 | _This is an alternative to the `CLONE_NEWPID` method; it is not currently |
| 76 | implemented in the Chromium codebase._ |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 77 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 78 | Instead of using `CLONE_NEWPID`, the `SUID` helper can use `setuid()` to put the |
| 79 | process into a currently-unused UID, which is allocated out of a range of UIDs. |
| 80 | In order to ensure that the `UID` has not been allocated for another sandbox, |
| 81 | the `SUID` helper uses |
| 82 | [getrlimit()](http://www.kernel.org/doc/man-pages/online/pages/man2/getrlimit.2.html) |
| 83 | to set `RLIMIT_NPROC` temporarily to a soft limit of 1. (Note that the docs |
| 84 | specify that [setuid()](http://www.kernel.org/doc/man-pages/online/pages/man2/setuid.2.html) |
| 85 | returns `EAGAIN` if `RLIMIT_NPROC` is exceeded.) We can reset `RLIMIT_NPROC` |
| 86 | afterwards in order to allow the sandboxed process to fork child processes. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 87 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 88 | As before, the `SUID` helper chroots the process. |
| 89 | |
| 90 | As before, LinuxZygote can set itself to be undumpable to stop processes in the |
| 91 | sandbox from being able to `ptrace()` each other. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 92 | |
| 93 | Limitations: |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 94 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 95 | * It is not possible for an unsandboxed process to `ptrace()` a sandboxed |
| 96 | process because they run under different UIDs. This makes debugging harder. |
| 97 | There is no equivalent of the `--allow-sandbox-debugging` other than turning |
| 98 | the sandbox off with `--no-sandbox`. |
| 99 | * The `SUID` helper can check that a `UID` is unused before it uses it (hence |
| 100 | this is safe if the `SUID` helper is installed into multiple chroots), but |
| 101 | it cannot prevent other root processes from putting processes into this |
| 102 | `UID` after the sandbox has been started. This means we should make the |
| 103 | `UID` range configurable, or distributions should reserve a `UID` range. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 104 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 105 | ## `CLONE_NEWNET` method |
| 106 | |
| 107 | The `SUID` helper uses |
| 108 | [CLONE_NEWNET](http://www.kernel.org/doc/man-pages/online/pages/man2/clone.2.html) |
| 109 | to restrict network access. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 110 | |
| 111 | ## Future work |
| 112 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 113 | We are splitting the `SUID` sandbox into a separate project which will support |
| 114 | both the `CLONE_NEWNS` and `setuid()` methods: |
| 115 | http://code.google.com/p/setuid-sandbox/ |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 116 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 117 | Having the `SUID` helper as a separate project should make it easier for |
| 118 | distributions to review and package. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 119 | |
| 120 | ## Possible extensions |
| 121 | |
| 122 | ## History |
| 123 | |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 124 | Older versions of the sandbox helper process will _only_ run |
| 125 | `/opt/google/chrome/chrome`. This string is hard coded |
| 126 | (`sandbox/linux/suid/sandbox.cc`). If your package is going to place the |
| 127 | Chromium binary somewhere else you need to modify this string. |
andybons | 3322f76 | 2015-08-24 21:37:09 | [diff] [blame] | 128 | |
| 129 | ## See also |
andybons | ad92aa3 | 2015-08-31 02:27:44 | [diff] [blame] | 130 | |
| 131 | * [LinuxSUIDSandboxDevelopment](linux_suid_sandbox_development.md) |
| 132 | * [LinuxSandboxing](linux_sandboxing.md) |
| 133 | * General information on Chromium sandboxing: |
xiaoyin.l | 1003c0b | 2016-12-06 02:51:17 | [diff] [blame] | 134 | https://dev.chromium.org/developers/design-documents/sandbox |