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), |
107 seccomp_bpf_started_(false), | 111 seccomp_bpf_started_(false), |
108 sandbox_status_flags_(kSandboxLinuxInvalid), | 112 sandbox_status_flags_(kSandboxLinuxInvalid), |
109 pre_initialized_(false), | 113 pre_initialized_(false), |
110 seccomp_bpf_supported_(false), | 114 seccomp_bpf_supported_(false), |
111 yama_is_enforcing_(false), | 115 yama_is_enforcing_(false), |
| 116 initialize_sandbox_ran_(false), |
112 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) | 117 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) |
113 { | 118 { |
114 if (setuid_sandbox_client_ == NULL) { | 119 if (setuid_sandbox_client_ == NULL) { |
115 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; | 120 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; |
116 } | 121 } |
117 #if defined(ANY_OF_AMTLU_SANITIZER) | 122 #if defined(ANY_OF_AMTLU_SANITIZER) |
118 sanitizer_args_ = make_scoped_ptr(new __sanitizer_sandbox_arguments); | 123 sanitizer_args_ = make_scoped_ptr(new __sanitizer_sandbox_arguments); |
119 *sanitizer_args_ = {0}; | 124 *sanitizer_args_ = {0}; |
120 #endif | 125 #endif |
121 } | 126 } |
122 | 127 |
123 LinuxSandbox::~LinuxSandbox() { | 128 LinuxSandbox::~LinuxSandbox() { |
| 129 if (pre_initialized_) { |
| 130 CHECK(initialize_sandbox_ran_); |
| 131 } |
124 } | 132 } |
125 | 133 |
126 LinuxSandbox* LinuxSandbox::GetInstance() { | 134 LinuxSandbox* LinuxSandbox::GetInstance() { |
127 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); | 135 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); |
128 CHECK(instance); | 136 CHECK(instance); |
129 return instance; | 137 return instance; |
130 } | 138 } |
131 | 139 |
132 void LinuxSandbox::PreinitializeSandbox() { | 140 void LinuxSandbox::PreinitializeSandbox() { |
133 CHECK(!pre_initialized_); | 141 CHECK(!pre_initialized_); |
134 seccomp_bpf_supported_ = false; | 142 seccomp_bpf_supported_ = false; |
135 #if defined(ANY_OF_AMTLU_SANITIZER) | 143 #if defined(ANY_OF_AMTLU_SANITIZER) |
136 // Sanitizers need to open some resources before the sandbox is enabled. | 144 // Sanitizers need to open some resources before the sandbox is enabled. |
137 // This should not fork, not launch threads, not open a directory. | 145 // This should not fork, not launch threads, not open a directory. |
138 __sanitizer_sandbox_on_notify(sanitizer_args()); | 146 __sanitizer_sandbox_on_notify(sanitizer_args()); |
139 sanitizer_args_.reset(); | 147 sanitizer_args_.reset(); |
140 #endif | 148 #endif |
141 | 149 |
142 #if !defined(NDEBUG) | 150 #if !defined(NDEBUG) |
143 // The in-process stack dumping needs to open /proc/self/maps and cache | 151 // 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 | 152 // its contents before the sandbox is enabled. It also pre-opens the |
145 // object files that are already loaded in the process address space. | 153 // object files that are already loaded in the process address space. |
146 base::debug::EnableInProcessStackDumpingForSandbox(); | 154 base::debug::EnableInProcessStackDumpingForSandbox(); |
| 155 #endif // !defined(NDEBUG) |
147 | 156 |
148 // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't | 157 // Open proc_fd_. It would break the security of the setuid sandbox if it was |
149 // produce a sandbox escape in Release mode. | 158 // not closed. |
| 159 // If LinuxSandbox::PreinitializeSandbox() runs, InitializeSandbox() must run |
| 160 // as well. |
150 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC); | 161 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC); |
151 CHECK_GE(proc_fd_, 0); | 162 CHECK_GE(proc_fd_, 0); |
152 #endif // !defined(NDEBUG) | |
153 // We "pre-warm" the code that detects supports for seccomp BPF. | 163 // We "pre-warm" the code that detects supports for seccomp BPF. |
154 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { | 164 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { |
155 if (!SandboxSeccompBPF::SupportsSandbox()) { | 165 if (!SandboxSeccompBPF::SupportsSandbox()) { |
156 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; | 166 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; |
157 } else { | 167 } else { |
158 seccomp_bpf_supported_ = true; | 168 seccomp_bpf_supported_ = true; |
159 } | 169 } |
160 } | 170 } |
161 | 171 |
162 // Yama is a "global", system-level status. We assume it will not regress | 172 // Yama is a "global", system-level status. We assume it will not regress |
163 // after startup. | 173 // after startup. |
164 const int yama_status = Yama::GetStatus(); | 174 const int yama_status = Yama::GetStatus(); |
165 yama_is_enforcing_ = (yama_status & Yama::STATUS_PRESENT) && | 175 yama_is_enforcing_ = (yama_status & Yama::STATUS_PRESENT) && |
166 (yama_status & Yama::STATUS_ENFORCING); | 176 (yama_status & Yama::STATUS_ENFORCING); |
167 pre_initialized_ = true; | 177 pre_initialized_ = true; |
168 } | 178 } |
169 | 179 |
| 180 std::vector<int> LinuxSandbox::GetFileDescriptorsToClose() { |
| 181 return std::vector<int>{proc_fd_}; |
| 182 } |
| 183 |
170 bool LinuxSandbox::InitializeSandbox() { | 184 bool LinuxSandbox::InitializeSandbox() { |
171 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 185 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
172 return linux_sandbox->InitializeSandboxImpl(); | 186 return linux_sandbox->InitializeSandboxImpl(); |
173 } | 187 } |
174 | 188 |
175 void LinuxSandbox::StopThread(base::Thread* thread) { | 189 void LinuxSandbox::StopThread(base::Thread* thread) { |
176 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 190 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
177 linux_sandbox->StopThreadImpl(thread); | 191 linux_sandbox->StopThreadImpl(thread); |
178 } | 192 } |
179 | 193 |
(...skipping 22 matching lines...) Expand all Loading... |
202 } | 216 } |
203 } | 217 } |
204 | 218 |
205 return sandbox_status_flags_; | 219 return sandbox_status_flags_; |
206 } | 220 } |
207 | 221 |
208 // Threads are counted via /proc/self/task. This is a little hairy because of | 222 // 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 | 223 // PID namespaces and existing sandboxes, so "self" must really be used instead |
210 // of using the pid. | 224 // of using the pid. |
211 bool LinuxSandbox::IsSingleThreaded() const { | 225 bool LinuxSandbox::IsSingleThreaded() const { |
212 bool is_single_threaded = false; | |
213 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); | 226 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
214 | 227 |
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()) | 228 CHECK(proc_self_task.is_valid()) |
221 << "Could not count threads, the sandbox was not " | 229 << "Could not count threads, the sandbox was not " |
222 << "pre-initialized properly."; | 230 << "pre-initialized properly."; |
223 #endif // !defined(NDEBUG) | |
224 | 231 |
225 if (!proc_self_task.is_valid()) { | 232 const bool is_single_threaded = |
226 // Pretend to be monothreaded if it can't be determined (for instance the | 233 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 | 234 |
234 return is_single_threaded; | 235 return is_single_threaded; |
235 } | 236 } |
236 | 237 |
237 bool LinuxSandbox::seccomp_bpf_started() const { | 238 bool LinuxSandbox::seccomp_bpf_started() const { |
238 return seccomp_bpf_started_; | 239 return seccomp_bpf_started_; |
239 } | 240 } |
240 | 241 |
241 sandbox::SetuidSandboxClient* | 242 sandbox::SetuidSandboxClient* |
242 LinuxSandbox::setuid_sandbox_client() const { | 243 LinuxSandbox::setuid_sandbox_client() const { |
243 return setuid_sandbox_client_.get(); | 244 return setuid_sandbox_client_.get(); |
244 } | 245 } |
245 | 246 |
246 // For seccomp-bpf, we use the SandboxSeccompBPF class. | 247 // For seccomp-bpf, we use the SandboxSeccompBPF class. |
247 bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { | 248 bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { |
248 CHECK(!seccomp_bpf_started_); | 249 CHECK(!seccomp_bpf_started_); |
249 CHECK(pre_initialized_); | 250 CHECK(pre_initialized_); |
250 if (seccomp_bpf_supported()) | 251 if (seccomp_bpf_supported()) { |
251 seccomp_bpf_started_ = SandboxSeccompBPF::StartSandbox(process_type); | 252 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
| 253 seccomp_bpf_started_ = |
| 254 SandboxSeccompBPF::StartSandbox(process_type, proc_self_task.Pass()); |
| 255 } |
252 | 256 |
253 if (seccomp_bpf_started_) | 257 if (seccomp_bpf_started_) { |
254 LogSandboxStarted("seccomp-bpf"); | 258 LogSandboxStarted("seccomp-bpf"); |
| 259 } |
255 | 260 |
256 return seccomp_bpf_started_; | 261 return seccomp_bpf_started_; |
257 } | 262 } |
258 | 263 |
259 bool LinuxSandbox::InitializeSandboxImpl() { | 264 bool LinuxSandbox::InitializeSandboxImpl() { |
| 265 DCHECK(!initialize_sandbox_ran_); |
| 266 initialize_sandbox_ran_ = true; |
| 267 |
260 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 268 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
261 const std::string process_type = | 269 const std::string process_type = |
262 command_line->GetSwitchValueASCII(switches::kProcessType); | 270 command_line->GetSwitchValueASCII(switches::kProcessType); |
263 | 271 |
264 // We need to make absolutely sure that our sandbox is "sealed" before | 272 // We need to make absolutely sure that our sandbox is "sealed" before |
265 // returning. | 273 // returning. |
266 // Unretained() since the current object is a Singleton. | 274 // Unretained() since the current object is a Singleton. |
267 base::ScopedClosureRunner sandbox_sealer( | 275 base::ScopedClosureRunner sandbox_sealer( |
268 base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(this))); | 276 base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(this))); |
269 // Make sure that this function enables sandboxes as promised by GetStatus(). | 277 // Make sure that this function enables sandboxes as promised by GetStatus(). |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 | 414 |
407 void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { | 415 void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { |
408 DCHECK(thread); | 416 DCHECK(thread); |
409 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); | 417 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
410 PCHECK(proc_self_task.is_valid()); | 418 PCHECK(proc_self_task.is_valid()); |
411 CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(), | 419 CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(), |
412 thread)); | 420 thread)); |
413 } | 421 } |
414 | 422 |
415 } // namespace content | 423 } // namespace content |
OLD | NEW |