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 |