Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 #include <fcntl.h> | |
| 9 #include <sys/stat.h> | |
| 10 #include <sys/types.h> | |
| 11 #include <unistd.h> | |
| 12 | |
| 13 #include "base/basictypes.h" | |
| 14 #include "base/callback.h" | |
| 15 #include "base/command_line.h" | |
| 16 #include "base/compiler_specific.h" | |
| 17 #include "base/logging.h" | |
| 18 #include "base/memory/scoped_ptr.h" | |
| 19 #include "base/posix/eintr_wrapper.h" | |
| 20 #include "build/build_config.h" | |
| 21 #include "components/nacl/common/nacl_switches.h" | |
| 22 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h" | |
| 23 #include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h" | |
| 24 #include "sandbox/linux/services/credentials.h" | |
| 25 #include "sandbox/linux/services/thread_helpers.h" | |
| 26 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | |
| 27 | |
| 28 namespace nacl { | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 // This is a poor man's check on whether we are sandboxed. | |
| 33 bool IsSandboxed() { | |
| 34 int proc_fd = open("/proc/self/exe", O_RDONLY); | |
| 35 if (proc_fd >= 0) { | |
| 36 PCHECK(0 == IGNORE_EINTR(close(proc_fd))); | |
| 37 return false; | |
| 38 } | |
| 39 return true; | |
| 40 } | |
| 41 | |
| 42 } // namespace | |
| 43 | |
| 44 NaClSandbox::NaClSandbox() | |
| 45 : layer_one_enabled_(false), | |
| 46 layer_one_sealed_(false), | |
| 47 layer_two_enabled_(false), | |
| 48 layer_two_is_non_sfi_(false), | |
| 49 proc_fd_(-1) { | |
| 50 proc_fd_.reset( | |
| 51 HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC))); | |
| 52 PCHECK(proc_fd_.is_valid()); | |
| 53 } | |
| 54 | |
| 55 NaClSandbox::~NaClSandbox() { | |
| 56 } | |
| 57 | |
| 58 bool NaClSandbox::IsSingleThreaded() { | |
| 59 CHECK(proc_fd_.is_valid()); | |
| 60 base::ScopedFD proc_self_task(HANDLE_EINTR(openat( | |
| 61 proc_fd_.get(), "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC))); | |
| 62 PCHECK(proc_self_task.is_valid()); | |
| 63 return sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); | |
| 64 } | |
| 65 | |
| 66 bool NaClSandbox::HasOpenDirectory() { | |
| 67 CHECK(proc_fd_.is_valid()); | |
| 68 sandbox::Credentials credentials; | |
| 69 return credentials.HasOpenDirectory(proc_fd_.get()); | |
| 70 } | |
| 71 | |
| 72 void NaClSandbox::InitializeLayerOneSandbox() { | |
| 73 // Check that IsSandboxed() works. We should not be sandboxed at this point. | |
| 74 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!"; | |
| 75 scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client( | |
| 76 sandbox::SetuidSandboxClient::Create()); | |
| 77 // Close the file descriptor that is an artefact of how the setuid sandbox | |
| 78 // works. | |
| 79 PCHECK(0 == IGNORE_EINTR(close( | |
| 80 setuid_sandbox_client->GetUniqueToChildFileDescriptor()))); | |
| 81 const bool suid_sandbox_child = setuid_sandbox_client->IsSuidSandboxChild(); | |
| 82 | |
| 83 if (suid_sandbox_child) { | |
| 84 // Make sure that no directory file descriptor is open, as it would bypass | |
| 85 // the setuid sandbox model. | |
| 86 CHECK(!HasOpenDirectory()); | |
| 87 | |
| 88 // Get sandboxed. | |
| 89 CHECK(setuid_sandbox_client->ChrootMe()); | |
| 90 CHECK(IsSandboxed()); | |
| 91 layer_one_enabled_ = true; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { | |
| 96 // seccomp-bpf only applies to the current thread, so it's critical to only | |
| 97 // have a single thread running here. | |
| 98 DCHECK(!layer_one_sealed_); | |
| 99 CHECK(IsSingleThreaded()); | |
| 100 if (uses_nonsfi_mode) { | |
| 101 layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(); | |
| 102 layer_two_is_non_sfi_ = true; | |
| 103 } else { | |
| 104 layer_two_enabled_ = nacl::InitializeBPFSandbox(); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 void NaClSandbox::SealLayerOneSandbox() { | |
| 109 if (!layer_two_enabled_) { | |
| 110 // If nothing prevents us, check that there is no superfluous directory | |
| 111 // open. | |
| 112 CHECK(!HasOpenDirectory()); | |
| 113 } | |
| 114 proc_fd_.reset(); | |
| 115 layer_one_sealed_ = true; | |
| 116 } | |
| 117 | |
| 118 void NaClSandbox::CheckSandboxingStateWithPolicy() { | |
| 119 static const char kItIsDangerousMsg[] = " it is dangerous."; | |
|
Mark Seaborn
2014/04/29 00:28:22
How about "this is dangerous", otherwise it seems
jln (very slow on Chromium)
2014/04/29 01:28:32
Done.
| |
| 120 static const char kItIsNotAllowedMsg[] = | |
| 121 " this is not allowed in this configuration."; | |
| 122 | |
| 123 const bool no_sandbox_for_non_sfi_ok = | |
| 124 CommandLine::ForCurrentProcess()->HasSwitch( | |
| 125 switches::kNaClDangerousNoSandboxNonSfi); | |
| 126 const bool can_be_no_sandbox = | |
| 127 !layer_two_is_non_sfi_ || no_sandbox_for_non_sfi_ok; | |
| 128 | |
| 129 if (!layer_one_enabled_ || !layer_one_sealed_) { | |
| 130 static const char kNoSuidMsg[] = "The SUID sandbox is not engaged,"; | |
|
Mark Seaborn
2014/04/29 00:28:22
Nit: comma splice, use ":" or ";" instead of ",".
jln (very slow on Chromium)
2014/04/29 01:28:32
Done.
| |
| 131 if (can_be_no_sandbox) | |
| 132 LOG(ERROR) << kNoSuidMsg << kItIsDangerousMsg; | |
| 133 else | |
| 134 LOG(FATAL) << kNoSuidMsg << kItIsNotAllowedMsg; | |
| 135 } | |
| 136 | |
| 137 if (!layer_two_enabled_) { | |
| 138 static const char kNoBpfMsg[] = "The seccomp-bpf sandbox is not engaged,"; | |
| 139 if (can_be_no_sandbox) | |
| 140 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; | |
| 141 else | |
| 142 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 } // namespace nacl | |
| OLD | NEW |