| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" | 5 #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <sys/prctl.h> | 9 #include <sys/prctl.h> |
| 10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 // This is a poor man's check on whether we are sandboxed. | 41 // This is a poor man's check on whether we are sandboxed. |
| 42 bool IsSandboxed() { | 42 bool IsSandboxed() { |
| 43 int proc_fd = open("/proc/self/exe", O_RDONLY); | 43 int proc_fd = open("/proc/self/exe", O_RDONLY); |
| 44 if (proc_fd >= 0) { | 44 if (proc_fd >= 0) { |
| 45 PCHECK(0 == IGNORE_EINTR(close(proc_fd))); | 45 PCHECK(0 == IGNORE_EINTR(close(proc_fd))); |
| 46 return false; | 46 return false; |
| 47 } | 47 } |
| 48 return true; | 48 return true; |
| 49 } | 49 } |
| 50 | 50 |
| 51 // Open a new file descriptor to /proc/self/task/ by using | |
| 52 // |proc_fd|. | |
| 53 base::ScopedFD GetProcSelfTask(int proc_fd) { | |
| 54 base::ScopedFD proc_self_task(HANDLE_EINTR( | |
| 55 openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC))); | |
| 56 PCHECK(proc_self_task.is_valid()); | |
| 57 return proc_self_task.Pass(); | |
| 58 } | |
| 59 | |
| 60 bool MaybeSetProcessNonDumpable() { | 51 bool MaybeSetProcessNonDumpable() { |
| 61 const base::CommandLine& command_line = | 52 const base::CommandLine& command_line = |
| 62 *base::CommandLine::ForCurrentProcess(); | 53 *base::CommandLine::ForCurrentProcess(); |
| 63 if (command_line.HasSwitch(switches::kAllowSandboxDebugging)) { | 54 if (command_line.HasSwitch(switches::kAllowSandboxDebugging)) { |
| 64 return true; | 55 return true; |
| 65 } | 56 } |
| 66 | 57 |
| 67 if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) != 0) { | 58 if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) != 0) { |
| 68 PLOG(ERROR) << "Failed to set non-dumpable flag"; | 59 PLOG(ERROR) << "Failed to set non-dumpable flag"; |
| 69 return false; | 60 return false; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 proc_fd_.reset( | 106 proc_fd_.reset( |
| 116 HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC))); | 107 HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC))); |
| 117 PCHECK(proc_fd_.is_valid()); | 108 PCHECK(proc_fd_.is_valid()); |
| 118 } | 109 } |
| 119 | 110 |
| 120 NaClSandbox::~NaClSandbox() { | 111 NaClSandbox::~NaClSandbox() { |
| 121 } | 112 } |
| 122 | 113 |
| 123 bool NaClSandbox::IsSingleThreaded() { | 114 bool NaClSandbox::IsSingleThreaded() { |
| 124 CHECK(proc_fd_.is_valid()); | 115 CHECK(proc_fd_.is_valid()); |
| 125 base::ScopedFD proc_self_task(GetProcSelfTask(proc_fd_.get())); | 116 return sandbox::ThreadHelpers::IsSingleThreaded(proc_fd_.get()); |
| 126 return sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); | |
| 127 } | 117 } |
| 128 | 118 |
| 129 bool NaClSandbox::HasOpenDirectory() { | 119 bool NaClSandbox::HasOpenDirectory() { |
| 130 CHECK(proc_fd_.is_valid()); | 120 CHECK(proc_fd_.is_valid()); |
| 131 return sandbox::ProcUtil::HasOpenDirectory(proc_fd_.get()); | 121 return sandbox::ProcUtil::HasOpenDirectory(proc_fd_.get()); |
| 132 } | 122 } |
| 133 | 123 |
| 134 void NaClSandbox::InitializeLayerOneSandbox() { | 124 void NaClSandbox::InitializeLayerOneSandbox() { |
| 135 // Check that IsSandboxed() works. We should not be sandboxed at this point. | 125 // Check that IsSandboxed() works. We should not be sandboxed at this point. |
| 136 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!"; | 126 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!"; |
| 137 | 127 |
| 138 if (setuid_sandbox_client_->IsSuidSandboxChild()) { | 128 if (setuid_sandbox_client_->IsSuidSandboxChild()) { |
| 139 setuid_sandbox_client_->CloseDummyFile(); | 129 setuid_sandbox_client_->CloseDummyFile(); |
| 140 | 130 |
| 141 // Make sure that no directory file descriptor is open, as it would bypass | 131 // Make sure that no directory file descriptor is open, as it would bypass |
| 142 // the setuid sandbox model. | 132 // the setuid sandbox model. |
| 143 CHECK(!HasOpenDirectory()); | 133 CHECK(!HasOpenDirectory()); |
| 144 | 134 |
| 145 // Get sandboxed. | 135 // Get sandboxed. |
| 146 CHECK(setuid_sandbox_client_->ChrootMe()); | 136 CHECK(setuid_sandbox_client_->ChrootMe()); |
| 147 CHECK(MaybeSetProcessNonDumpable()); | 137 CHECK(MaybeSetProcessNonDumpable()); |
| 148 CHECK(IsSandboxed()); | 138 CHECK(IsSandboxed()); |
| 149 layer_one_enabled_ = true; | 139 layer_one_enabled_ = true; |
| 150 } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) { | 140 } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) { |
| 151 CHECK(sandbox::Credentials::MoveToNewUserNS()); | 141 CHECK(sandbox::Credentials::MoveToNewUserNS()); |
| 152 // This relies on SealLayerOneSandbox() to be called later. | 142 // This relies on SealLayerOneSandbox() to be called later since this |
| 153 CHECK(!HasOpenDirectory()); | 143 // class is keeping a file descriptor to /proc/. |
| 154 CHECK(sandbox::Credentials::DropFileSystemAccess()); | 144 CHECK(sandbox::Credentials::DropFileSystemAccess(proc_fd_.get())); |
| 155 CHECK(IsSingleThreaded()); | 145 CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd_.get())); |
| 156 CHECK(sandbox::Credentials::DropAllCapabilities()); | |
| 157 CHECK(IsSandboxed()); | 146 CHECK(IsSandboxed()); |
| 158 layer_one_enabled_ = true; | 147 layer_one_enabled_ = true; |
| 159 } | 148 } |
| 160 } | 149 } |
| 161 | 150 |
| 162 void NaClSandbox::CheckForExpectedNumberOfOpenFds() { | 151 void NaClSandbox::CheckForExpectedNumberOfOpenFds() { |
| 163 // We expect to have the following FDs open: | 152 // We expect to have the following FDs open: |
| 164 // 1-3) stdin, stdout, stderr. | 153 // 1-3) stdin, stdout, stderr. |
| 165 // 4) The /dev/urandom FD used by base::GetUrandomFD(). | 154 // 4) The /dev/urandom FD used by base::GetUrandomFD(). |
| 166 // 5) A dummy pipe FD used to overwrite kSandboxIPCChannel. | 155 // 5) A dummy pipe FD used to overwrite kSandboxIPCChannel. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 182 | 171 |
| 183 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { | 172 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { |
| 184 // seccomp-bpf only applies to the current thread, so it's critical to only | 173 // seccomp-bpf only applies to the current thread, so it's critical to only |
| 185 // have a single thread running here. | 174 // have a single thread running here. |
| 186 DCHECK(!layer_one_sealed_); | 175 DCHECK(!layer_one_sealed_); |
| 187 CHECK(IsSingleThreaded()); | 176 CHECK(IsSingleThreaded()); |
| 188 CheckForExpectedNumberOfOpenFds(); | 177 CheckForExpectedNumberOfOpenFds(); |
| 189 | 178 |
| 190 RestrictAddressSpaceUsage(); | 179 RestrictAddressSpaceUsage(); |
| 191 | 180 |
| 192 base::ScopedFD proc_self_task(GetProcSelfTask(proc_fd_.get())); | 181 // Pass proc_fd_ ownership to the BPF sandbox, which guarantees it will |
| 193 | 182 // be closed. There is no point in keeping it around since the BPF policy |
| 183 // will prevent its usage. |
| 194 if (uses_nonsfi_mode) { | 184 if (uses_nonsfi_mode) { |
| 195 layer_two_enabled_ = | 185 layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(proc_fd_.Pass()); |
| 196 nacl::nonsfi::InitializeBPFSandbox(proc_self_task.Pass()); | |
| 197 layer_two_is_nonsfi_ = true; | 186 layer_two_is_nonsfi_ = true; |
| 198 } else { | 187 } else { |
| 199 layer_two_enabled_ = nacl::InitializeBPFSandbox(proc_self_task.Pass()); | 188 layer_two_enabled_ = nacl::InitializeBPFSandbox(proc_fd_.Pass()); |
| 200 } | 189 } |
| 201 } | 190 } |
| 202 | 191 |
| 203 void NaClSandbox::SealLayerOneSandbox() { | 192 void NaClSandbox::SealLayerOneSandbox() { |
| 204 if (!layer_two_enabled_) { | 193 if (proc_fd_.is_valid() && !layer_two_enabled_) { |
| 205 // If nothing prevents us, check that there is no superfluous directory | 194 // If nothing prevents us, check that there is no superfluous directory |
| 206 // open. | 195 // open. |
| 207 CHECK(!HasOpenDirectory()); | 196 CHECK(!HasOpenDirectory()); |
| 208 } | 197 } |
| 209 proc_fd_.reset(); | 198 proc_fd_.reset(); |
| 210 layer_one_sealed_ = true; | 199 layer_one_sealed_ = true; |
| 211 } | 200 } |
| 212 | 201 |
| 213 void NaClSandbox::CheckSandboxingStateWithPolicy() { | 202 void NaClSandbox::CheckSandboxingStateWithPolicy() { |
| 214 static const char kItIsDangerousMsg[] = " this is dangerous."; | 203 static const char kItIsDangerousMsg[] = " this is dangerous."; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 234 static const char kNoBpfMsg[] = | 223 static const char kNoBpfMsg[] = |
| 235 "The seccomp-bpf sandbox is not engaged for NaCl:"; | 224 "The seccomp-bpf sandbox is not engaged for NaCl:"; |
| 236 if (can_be_no_sandbox) | 225 if (can_be_no_sandbox) |
| 237 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; | 226 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; |
| 238 else | 227 else |
| 239 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; | 228 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; |
| 240 } | 229 } |
| 241 } | 230 } |
| 242 | 231 |
| 243 } // namespace nacl | 232 } // namespace nacl |
| OLD | NEW |