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 #include <dirent.h> | 5 #include <dirent.h> |
6 #include <fcntl.h> | 6 #include <fcntl.h> |
7 #include <sys/resource.h> | 7 #include <sys/resource.h> |
8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
9 #include <sys/time.h> | 9 #include <sys/time.h> |
10 #include <sys/types.h> | 10 #include <sys/types.h> |
11 #include <unistd.h> | 11 #include <unistd.h> |
12 | 12 |
13 #include <limits> | 13 #include <limits> |
14 #include <string> | |
15 #include <vector> | |
14 | 16 |
15 #include "base/bind.h" | 17 #include "base/bind.h" |
16 #include "base/callback_helpers.h" | 18 #include "base/callback_helpers.h" |
17 #include "base/command_line.h" | 19 #include "base/command_line.h" |
18 #include "base/debug/stack_trace.h" | 20 #include "base/debug/stack_trace.h" |
19 #include "base/files/scoped_file.h" | 21 #include "base/files/scoped_file.h" |
20 #include "base/logging.h" | 22 #include "base/logging.h" |
21 #include "base/macros.h" | 23 #include "base/macros.h" |
22 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/scoped_ptr.h" |
23 #include "base/memory/singleton.h" | 25 #include "base/memory/singleton.h" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 #endif | 85 #endif |
84 } | 86 } |
85 | 87 |
86 // Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be | 88 // Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be |
87 // -1. Will return -1 on error and set errno like open(2). | 89 // -1. Will return -1 on error and set errno like open(2). |
88 int OpenProcTaskFd(int proc_fd) { | 90 int OpenProcTaskFd(int proc_fd) { |
89 int proc_self_task = -1; | 91 int proc_self_task = -1; |
90 if (proc_fd >= 0) { | 92 if (proc_fd >= 0) { |
91 // If a handle to /proc is available, use it. This allows to bypass file | 93 // If a handle to /proc is available, use it. This allows to bypass file |
92 // system restrictions. | 94 // system restrictions. |
93 proc_self_task = openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY); | 95 proc_self_task = |
96 openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); | |
94 } else { | 97 } else { |
95 // Otherwise, make an attempt to access the file system directly. | 98 // Otherwise, make an attempt to access the file system directly. |
96 proc_self_task = open("/proc/self/task/", O_RDONLY | O_DIRECTORY); | 99 proc_self_task = |
100 open("/proc/self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); | |
97 } | 101 } |
98 return proc_self_task; | 102 return proc_self_task; |
99 } | 103 } |
100 | 104 |
101 } // namespace | 105 } // namespace |
102 | 106 |
103 namespace content { | 107 namespace content { |
104 | 108 |
105 LinuxSandbox::LinuxSandbox() | 109 LinuxSandbox::LinuxSandbox() |
106 : proc_fd_(-1), | 110 : proc_fd_(-1), |
(...skipping 30 matching lines...) Expand all Loading... | |
137 // This should not fork, not launch threads, not open a directory. | 141 // This should not fork, not launch threads, not open a directory. |
138 __sanitizer_sandbox_on_notify(sanitizer_args()); | 142 __sanitizer_sandbox_on_notify(sanitizer_args()); |
139 sanitizer_args_.reset(); | 143 sanitizer_args_.reset(); |
140 #endif | 144 #endif |
141 | 145 |
142 #if !defined(NDEBUG) | 146 #if !defined(NDEBUG) |
143 // The in-process stack dumping needs to open /proc/self/maps and cache | 147 // The in-process stack dumping needs to open /proc/self/maps and cache |
144 // its contents before the sandbox is enabled. It also pre-opens the | 148 // its contents before the sandbox is enabled. It also pre-opens the |
145 // object files that are already loaded in the process address space. | 149 // object files that are already loaded in the process address space. |
146 base::debug::EnableInProcessStackDumpingForSandbox(); | 150 base::debug::EnableInProcessStackDumpingForSandbox(); |
151 #endif // !defined(NDEBUG) | |
147 | 152 |
148 // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't | 153 // Open proc_fd_. It would break the security of the setuid sandbox if it was |
149 // produce a sandbox escape in Release mode. | 154 // not closed. |
155 // If LinuxSandbox::PreinitializeSandbox() runs, InitializeSandbox() must run | |
mdempsky
2014/11/24 21:58:23
Can we CHECK this in ~LinuxSandbox()?
jln (very slow on Chromium)
2014/11/24 22:45:48
Done.
| |
156 // as well. | |
150 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC); | 157 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC); |
151 CHECK_GE(proc_fd_, 0); | 158 CHECK_GE(proc_fd_, 0); |
152 #endif // !defined(NDEBUG) | |
153 // We "pre-warm" the code that detects supports for seccomp BPF. | 159 // We "pre-warm" the code that detects supports for seccomp BPF. |
154 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { | 160 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { |
155 if (!SandboxSeccompBPF::SupportsSandbox()) { | 161 if (!SandboxSeccompBPF::SupportsSandbox()) { |
156 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; | 162 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; |
157 } else { | 163 } else { |
158 seccomp_bpf_supported_ = true; | 164 seccomp_bpf_supported_ = true; |
159 } | 165 } |
160 } | 166 } |
161 | 167 |
162 // Yama is a "global", system-level status. We assume it will not regress | 168 // Yama is a "global", system-level status. We assume it will not regress |
163 // after startup. | 169 // after startup. |
164 const int yama_status = Yama::GetStatus(); | 170 const int yama_status = Yama::GetStatus(); |
165 yama_is_enforcing_ = (yama_status & Yama::STATUS_PRESENT) && | 171 yama_is_enforcing_ = (yama_status & Yama::STATUS_PRESENT) && |
166 (yama_status & Yama::STATUS_ENFORCING); | 172 (yama_status & Yama::STATUS_ENFORCING); |
167 pre_initialized_ = true; | 173 pre_initialized_ = true; |
168 } | 174 } |
169 | 175 |
176 std::vector<int> LinuxSandbox::GetFileDescriptorsToClose() { | |
177 return std::vector<int>{proc_fd_}; | |
178 } | |
179 | |
170 bool LinuxSandbox::InitializeSandbox() { | 180 bool LinuxSandbox::InitializeSandbox() { |
171 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 181 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
172 return linux_sandbox->InitializeSandboxImpl(); | 182 return linux_sandbox->InitializeSandboxImpl(); |
173 } | 183 } |
174 | 184 |
175 void LinuxSandbox::StopThread(base::Thread* thread) { | 185 void LinuxSandbox::StopThread(base::Thread* thread) { |
176 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 186 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
177 linux_sandbox->StopThreadImpl(thread); | 187 linux_sandbox->StopThreadImpl(thread); |
178 } | 188 } |
179 | 189 |
(...skipping 22 matching lines...) Expand all Loading... | |
202 } | 212 } |
203 } | 213 } |
204 | 214 |
205 return sandbox_status_flags_; | 215 return sandbox_status_flags_; |
206 } | 216 } |
207 | 217 |
208 // Threads are counted via /proc/self/task. This is a little hairy because of | 218 // Threads are counted via /proc/self/task. This is a little hairy because of |
209 // PID namespaces and existing sandboxes, so "self" must really be used instead | 219 // PID namespaces and existing sandboxes, so "self" must really be used instead |
210 // of using the pid. | 220 // of using the pid. |
211 bool LinuxSandbox::IsSingleThreaded() const { | 221 bool LinuxSandbox::IsSingleThreaded() const { |
212 bool is_single_threaded = false; | |
213 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); | 222 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
214 | 223 |
215 // In Debug mode, it's mandatory to be able to count threads to catch bugs. | |
216 #if !defined(NDEBUG) | |
217 // Using CHECK here since we want to check all the cases where | |
218 // !defined(NDEBUG) | |
219 // gets built. | |
220 CHECK(proc_self_task.is_valid()) | 224 CHECK(proc_self_task.is_valid()) |
221 << "Could not count threads, the sandbox was not " | 225 << "Could not count threads, the sandbox was not " |
222 << "pre-initialized properly."; | 226 << "pre-initialized properly."; |
223 #endif // !defined(NDEBUG) | |
224 | 227 |
225 if (!proc_self_task.is_valid()) { | 228 const bool is_single_threaded = |
226 // Pretend to be monothreaded if it can't be determined (for instance the | 229 sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); |
227 // setuid sandbox is already engaged but no proc_fd_ is available). | |
228 is_single_threaded = true; | |
229 } else { | |
230 is_single_threaded = | |
231 sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); | |
232 } | |
233 | 230 |
234 return is_single_threaded; | 231 return is_single_threaded; |
235 } | 232 } |
236 | 233 |
237 bool LinuxSandbox::seccomp_bpf_started() const { | 234 bool LinuxSandbox::seccomp_bpf_started() const { |
238 return seccomp_bpf_started_; | 235 return seccomp_bpf_started_; |
239 } | 236 } |
240 | 237 |
241 sandbox::SetuidSandboxClient* | 238 sandbox::SetuidSandboxClient* |
242 LinuxSandbox::setuid_sandbox_client() const { | 239 LinuxSandbox::setuid_sandbox_client() const { |
243 return setuid_sandbox_client_.get(); | 240 return setuid_sandbox_client_.get(); |
244 } | 241 } |
245 | 242 |
246 // For seccomp-bpf, we use the SandboxSeccompBPF class. | 243 // For seccomp-bpf, we use the SandboxSeccompBPF class. |
247 bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { | 244 bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { |
248 CHECK(!seccomp_bpf_started_); | 245 CHECK(!seccomp_bpf_started_); |
249 CHECK(pre_initialized_); | 246 CHECK(pre_initialized_); |
250 if (seccomp_bpf_supported()) | 247 if (seccomp_bpf_supported()) { |
251 seccomp_bpf_started_ = SandboxSeccompBPF::StartSandbox(process_type); | 248 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
249 seccomp_bpf_started_ = | |
250 SandboxSeccompBPF::StartSandbox(process_type, proc_self_task.Pass()); | |
251 } | |
252 | 252 |
253 if (seccomp_bpf_started_) | 253 if (seccomp_bpf_started_) { |
254 LogSandboxStarted("seccomp-bpf"); | 254 LogSandboxStarted("seccomp-bpf"); |
255 } | |
255 | 256 |
256 return seccomp_bpf_started_; | 257 return seccomp_bpf_started_; |
257 } | 258 } |
258 | 259 |
259 bool LinuxSandbox::InitializeSandboxImpl() { | 260 bool LinuxSandbox::InitializeSandboxImpl() { |
260 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 261 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
261 const std::string process_type = | 262 const std::string process_type = |
262 command_line->GetSwitchValueASCII(switches::kProcessType); | 263 command_line->GetSwitchValueASCII(switches::kProcessType); |
263 | 264 |
264 // We need to make absolutely sure that our sandbox is "sealed" before | 265 // We need to make absolutely sure that our sandbox is "sealed" before |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 | 407 |
407 void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { | 408 void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { |
408 DCHECK(thread); | 409 DCHECK(thread); |
409 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); | 410 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
410 PCHECK(proc_self_task.is_valid()); | 411 PCHECK(proc_self_task.is_valid()); |
411 CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(), | 412 CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(), |
412 thread)); | 413 thread)); |
413 } | 414 } |
414 | 415 |
415 } // namespace content | 416 } // namespace content |
OLD | NEW |