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 <fcntl.h> | 5 #include <fcntl.h> |
6 #include <sys/resource.h> | 6 #include <sys/resource.h> |
7 #include <sys/stat.h> | 7 #include <sys/stat.h> |
8 #include <sys/time.h> | 8 #include <sys/time.h> |
9 #include <sys/types.h> | 9 #include <sys/types.h> |
10 | 10 |
11 #include <limits> | 11 #include <limits> |
12 | 12 |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/memory/singleton.h" | 16 #include "base/memory/singleton.h" |
17 #include "base/posix/eintr_wrapper.h" | 17 #include "base/posix/eintr_wrapper.h" |
18 #include "base/time.h" | 18 #include "base/time.h" |
19 #include "content/common/sandbox_linux.h" | 19 #include "content/common/sandbox_linux.h" |
20 #include "content/common/seccomp_sandbox.h" | 20 #include "content/common/seccomp_sandbox.h" |
21 #include "content/common/sandbox_seccomp_bpf_linux.h" | 21 #include "content/common/sandbox_seccomp_bpf_linux.h" |
22 #include "content/public/common/content_switches.h" | 22 #include "content/public/common/content_switches.h" |
23 #include "content/public/common/sandbox_linux.h" | 23 #include "content/public/common/sandbox_linux.h" |
24 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | 24 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" |
25 | 25 |
| 26 using content::LinuxSandbox; |
| 27 |
26 namespace { | 28 namespace { |
27 | 29 |
28 void LogSandboxStarted(const std::string& sandbox_name) { | 30 void LogSandboxStarted(const std::string& sandbox_name) { |
29 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 31 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
30 const std::string process_type = | 32 const std::string process_type = |
31 command_line.GetSwitchValueASCII(switches::kProcessType); | 33 command_line.GetSwitchValueASCII(switches::kProcessType); |
32 const std::string activated_sandbox = | 34 const std::string activated_sandbox = |
33 "Activated " + sandbox_name + " sandbox for process type: " + | 35 "Activated " + sandbox_name + " sandbox for process type: " + |
34 process_type + "."; | 36 process_type + "."; |
35 #if defined(OS_CHROMEOS) | 37 #if defined(OS_CHROMEOS) |
(...skipping 16 matching lines...) Expand all Loading... |
52 #else | 54 #else |
53 // On by default. Allow turning off with a switch. | 55 // On by default. Allow turning off with a switch. |
54 return !command_line->HasSwitch(switches::kDisableSeccompSandbox); | 56 return !command_line->HasSwitch(switches::kDisableSeccompSandbox); |
55 #endif // NDEBUG | 57 #endif // NDEBUG |
56 #endif // SECCOMP_SANDBOX | 58 #endif // SECCOMP_SANDBOX |
57 return false; | 59 return false; |
58 } | 60 } |
59 | 61 |
60 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are | 62 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are |
61 // supported. | 63 // supported. |
62 bool ShouldEnableSeccompLegacy(const std::string& process_type) { | 64 bool ShouldEnableSeccompLegacy(LinuxSandbox::SandboxConfig sandbox_config) { |
63 if (IsSeccompLegacyDesired() && | 65 if (IsSeccompLegacyDesired() && |
64 process_type == switches::kRendererProcess) { | 66 sandbox_config == LinuxSandbox::SANDBOX_CONFIG_RENDERER) { |
65 return true; | 67 return true; |
66 } else { | 68 } else { |
67 return false; | 69 return false; |
68 } | 70 } |
69 } | 71 } |
70 | 72 |
71 bool AddResourceLimit(int resource, rlim_t limit) { | 73 bool AddResourceLimit(int resource, rlim_t limit) { |
72 struct rlimit old_rlimit; | 74 struct rlimit old_rlimit; |
73 if (getrlimit(resource, &old_rlimit)) | 75 if (getrlimit(resource, &old_rlimit)) |
74 return false; | 76 return false; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 } else { | 151 } else { |
150 seccomp_bpf_supported_ = true; | 152 seccomp_bpf_supported_ = true; |
151 } | 153 } |
152 } | 154 } |
153 pre_initialized_ = true; | 155 pre_initialized_ = true; |
154 } | 156 } |
155 | 157 |
156 // Once we finally know our process type, we can cleanup proc_fd_ | 158 // Once we finally know our process type, we can cleanup proc_fd_ |
157 // or pass it to seccomp-legacy. | 159 // or pass it to seccomp-legacy. |
158 void LinuxSandbox::PreinitializeSandboxFinish( | 160 void LinuxSandbox::PreinitializeSandboxFinish( |
159 const std::string& process_type) { | 161 LinuxSandbox::SandboxConfig sandbox_config) { |
160 CHECK(pre_initialized_); | 162 CHECK(pre_initialized_); |
161 if (proc_fd_ >= 0) { | 163 if (proc_fd_ >= 0) { |
162 if (ShouldEnableSeccompLegacy(process_type)) { | 164 if (ShouldEnableSeccompLegacy(sandbox_config)) { |
163 #if defined(SECCOMP_SANDBOX) | 165 #if defined(SECCOMP_SANDBOX) |
164 SeccompSandboxSetProcFd(proc_fd_); | 166 SeccompSandboxSetProcFd(proc_fd_); |
165 #endif | 167 #endif |
166 } else { | 168 } else { |
167 DCHECK_GE(proc_fd_, 0); | 169 DCHECK_GE(proc_fd_, 0); |
168 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | 170 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); |
169 } | 171 } |
170 proc_fd_ = -1; | 172 proc_fd_ = -1; |
171 } | 173 } |
172 } | 174 } |
173 | 175 |
174 void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { | 176 void LinuxSandbox::PreinitializeSandbox( |
| 177 LinuxSandbox::SandboxConfig sandbox_config) { |
175 PreinitializeSandboxBegin(); | 178 PreinitializeSandboxBegin(); |
176 PreinitializeSandboxFinish(process_type); | 179 PreinitializeSandboxFinish(sandbox_config); |
| 180 } |
| 181 |
| 182 bool LinuxSandbox::InitializeSandbox( |
| 183 enum LinuxSandbox::SandboxConfig sandbox_config) { |
| 184 bool seccomp_legacy_started = false; |
| 185 bool seccomp_bpf_started = false; |
| 186 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
| 187 const std::string process_type = |
| 188 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 189 switches::kProcessType); |
| 190 |
| 191 // No matter what, it's always an error to call InitializeSandbox() after |
| 192 // threads have been created. |
| 193 if (!linux_sandbox->IsSingleThreaded()) { |
| 194 std::string error_message = "InitializeSandbox() called with multiple " |
| 195 "threads in process " + process_type; |
| 196 // TODO(jln): change this into a CHECK() once we are more comfortable it |
| 197 // does not trigger. |
| 198 LOG(ERROR) << error_message; |
| 199 return false; |
| 200 } |
| 201 |
| 202 // Attempt to limit the future size of the address space of the process. |
| 203 linux_sandbox->LimitAddressSpace(sandbox_config); |
| 204 |
| 205 // First, try to enable seccomp-bpf. |
| 206 seccomp_bpf_started = linux_sandbox->StartSeccompBpf(sandbox_config); |
| 207 |
| 208 // If that fails, try to enable seccomp-legacy. |
| 209 if (!seccomp_bpf_started) { |
| 210 seccomp_legacy_started = linux_sandbox->StartSeccompLegacy(sandbox_config); |
| 211 } |
| 212 |
| 213 return seccomp_legacy_started || seccomp_bpf_started; |
177 } | 214 } |
178 | 215 |
179 int LinuxSandbox::GetStatus() const { | 216 int LinuxSandbox::GetStatus() const { |
180 CHECK(pre_initialized_); | 217 CHECK(pre_initialized_); |
181 int sandbox_flags = 0; | 218 int sandbox_flags = 0; |
182 if (setuid_sandbox_client_->IsSandboxed()) { | 219 if (setuid_sandbox_client_->IsSandboxed()) { |
183 sandbox_flags |= kSandboxLinuxSUID; | 220 sandbox_flags |= kSandboxLinuxSUID; |
184 if (setuid_sandbox_client_->IsInNewPIDNamespace()) | 221 if (setuid_sandbox_client_->IsInNewPIDNamespace()) |
185 sandbox_flags |= kSandboxLinuxPIDNS; | 222 sandbox_flags |= kSandboxLinuxPIDNS; |
186 if (setuid_sandbox_client_->IsInNewNETNamespace()) | 223 if (setuid_sandbox_client_->IsInNewNETNamespace()) |
187 sandbox_flags |= kSandboxLinuxNetNS; | 224 sandbox_flags |= kSandboxLinuxNetNS; |
188 } | 225 } |
189 | 226 |
190 if (seccomp_bpf_supported() && | 227 if (seccomp_bpf_supported() && SandboxSeccompBpf::ShouldEnableSeccompBpf( |
191 SandboxSeccompBpf::ShouldEnableSeccompBpf(switches::kRendererProcess)) { | 228 LinuxSandbox::SANDBOX_CONFIG_RENDERER)) { |
192 // We report whether the sandbox will be activated when renderers go | 229 // We report whether the sandbox will be activated when renderers go |
193 // through sandbox initialization. | 230 // through sandbox initialization. |
194 sandbox_flags |= kSandboxLinuxSeccompBpf; | 231 sandbox_flags |= kSandboxLinuxSeccompBpf; |
195 } | 232 } |
196 | 233 |
197 // We only try to enable seccomp-legacy when seccomp-bpf is not supported | 234 // We only try to enable seccomp-legacy when seccomp-bpf is not supported |
198 // or not enabled. | 235 // or not enabled. |
199 if (!(sandbox_flags & kSandboxLinuxSeccompBpf) && | 236 if (!(sandbox_flags & kSandboxLinuxSeccompBpf) && |
200 seccomp_legacy_supported() && | 237 seccomp_legacy_supported() && |
201 ShouldEnableSeccompLegacy(switches::kRendererProcess)) { | 238 ShouldEnableSeccompLegacy(LinuxSandbox::SANDBOX_CONFIG_RENDERER)) { |
202 // Same here, what we report is what we will do for the renderer. | 239 // Same here, what we report is what we will do for the renderer. |
203 sandbox_flags |= kSandboxLinuxSeccompLegacy; | 240 sandbox_flags |= kSandboxLinuxSeccompLegacy; |
204 } | 241 } |
205 return sandbox_flags; | 242 return sandbox_flags; |
206 } | 243 } |
207 | 244 |
208 bool LinuxSandbox::IsSingleThreaded() const { | 245 bool LinuxSandbox::IsSingleThreaded() const { |
209 // TODO(jln): re-implement this properly and use our proc_fd_ if available. | 246 // TODO(jln): re-implement this properly and use our proc_fd_ if available. |
210 // Possibly racy, but it's ok because this is more of a debug check to catch | 247 // Possibly racy, but it's ok because this is more of a debug check to catch |
211 // new threaded situations arising during development. | 248 // new threaded situations arising during development. |
(...skipping 15 matching lines...) Expand all Loading... |
227 bool LinuxSandbox::seccomp_bpf_started() const { | 264 bool LinuxSandbox::seccomp_bpf_started() const { |
228 return seccomp_bpf_started_; | 265 return seccomp_bpf_started_; |
229 } | 266 } |
230 | 267 |
231 sandbox::SetuidSandboxClient* | 268 sandbox::SetuidSandboxClient* |
232 LinuxSandbox::setuid_sandbox_client() const { | 269 LinuxSandbox::setuid_sandbox_client() const { |
233 return setuid_sandbox_client_.get(); | 270 return setuid_sandbox_client_.get(); |
234 } | 271 } |
235 | 272 |
236 // For seccomp-legacy, we implement the policy inline, here. | 273 // For seccomp-legacy, we implement the policy inline, here. |
237 bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { | 274 bool LinuxSandbox::StartSeccompLegacy( |
| 275 LinuxSandbox::SandboxConfig sandbox_config) { |
238 if (!pre_initialized_) | 276 if (!pre_initialized_) |
239 PreinitializeSandbox(process_type); | 277 PreinitializeSandbox(sandbox_config); |
240 if (seccomp_legacy_supported() && ShouldEnableSeccompLegacy(process_type)) { | 278 if (seccomp_legacy_supported() && ShouldEnableSeccompLegacy(sandbox_config)) { |
241 // SupportsSeccompSandbox() returns a cached result, as we already | 279 // SupportsSeccompSandbox() returns a cached result, as we already |
242 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us | 280 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us |
243 // to not pass in a file descriptor for "/proc". | 281 // to not pass in a file descriptor for "/proc". |
244 #if defined(SECCOMP_SANDBOX) | 282 #if defined(SECCOMP_SANDBOX) |
245 if (SupportsSeccompSandbox(-1)) { | 283 if (SupportsSeccompSandbox(-1)) { |
246 StartSeccompSandbox(); | 284 StartSeccompSandbox(); |
247 LogSandboxStarted("seccomp-legacy"); | 285 LogSandboxStarted("seccomp-legacy"); |
248 return true; | 286 return true; |
249 } | 287 } |
250 #endif | 288 #endif |
251 } | 289 } |
252 return false; | 290 return false; |
253 } | 291 } |
254 | 292 |
255 // For seccomp-bpf, we use the SandboxSeccompBpf class. | 293 // For seccomp-bpf, we use the SandboxSeccompBpf class. |
256 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { | 294 bool LinuxSandbox::StartSeccompBpf( |
| 295 LinuxSandbox::SandboxConfig sandbox_config) { |
257 CHECK(!seccomp_bpf_started_); | 296 CHECK(!seccomp_bpf_started_); |
258 if (!pre_initialized_) | 297 if (!pre_initialized_) |
259 PreinitializeSandbox(process_type); | 298 PreinitializeSandbox(sandbox_config); |
260 if (seccomp_bpf_supported()) | 299 if (seccomp_bpf_supported()) |
261 seccomp_bpf_started_ = SandboxSeccompBpf::StartSandbox(process_type); | 300 seccomp_bpf_started_ = SandboxSeccompBpf::StartSandbox(sandbox_config); |
262 | 301 |
263 if (seccomp_bpf_started_) | 302 if (seccomp_bpf_started_) |
264 LogSandboxStarted("seccomp-bpf"); | 303 LogSandboxStarted("seccomp-bpf"); |
265 | 304 |
266 return seccomp_bpf_started_; | 305 return seccomp_bpf_started_; |
267 } | 306 } |
268 | 307 |
269 bool LinuxSandbox::seccomp_legacy_supported() const { | 308 bool LinuxSandbox::seccomp_legacy_supported() const { |
270 CHECK(pre_initialized_); | 309 CHECK(pre_initialized_); |
271 return seccomp_legacy_supported_; | 310 return seccomp_legacy_supported_; |
272 } | 311 } |
273 | 312 |
274 bool LinuxSandbox::seccomp_bpf_supported() const { | 313 bool LinuxSandbox::seccomp_bpf_supported() const { |
275 CHECK(pre_initialized_); | 314 CHECK(pre_initialized_); |
276 return seccomp_bpf_supported_; | 315 return seccomp_bpf_supported_; |
277 } | 316 } |
278 | 317 |
279 bool LinuxSandbox::LimitAddressSpace(const std::string& process_type) { | 318 bool LinuxSandbox::LimitAddressSpace( |
280 (void) process_type; | 319 LinuxSandbox::SandboxConfig sandbox_config) { |
| 320 (void) sandbox_config; |
281 #if !defined(ADDRESS_SANITIZER) | 321 #if !defined(ADDRESS_SANITIZER) |
282 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 322 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
283 if (command_line->HasSwitch(switches::kNoSandbox)) { | 323 if (command_line->HasSwitch(switches::kNoSandbox)) { |
284 return false; | 324 return false; |
285 } | 325 } |
286 | 326 |
287 // Limit the address space to 4GB. | 327 // Limit the address space to 4GB. |
288 // This is in the hope of making some kernel exploits more complex and less | 328 // This is in the hope of making some kernel exploits more complex and less |
289 // reliable. It also limits sprays a little on 64-bit. | 329 // reliable. It also limits sprays a little on 64-bit. |
290 rlim_t address_space_limit = std::numeric_limits<uint32_t>::max(); | 330 rlim_t address_space_limit = std::numeric_limits<uint32_t>::max(); |
291 #if defined(__LP64__) | 331 #if defined(__LP64__) |
292 // On 64 bits, V8 and possibly others will reserve massive memory ranges and | 332 // On 64 bits, V8 and possibly others will reserve massive memory ranges and |
293 // rely on on-demand paging for allocation. Unfortunately, even | 333 // rely on on-demand paging for allocation. Unfortunately, even |
294 // MADV_DONTNEED ranges count towards RLIMIT_AS so this is not an option. | 334 // MADV_DONTNEED ranges count towards RLIMIT_AS so this is not an option. |
295 // See crbug.com/169327 for a discussion. | 335 // See crbug.com/169327 for a discussion. |
296 // For now, increase limit to 16GB for renderer and worker processes to | 336 // For now, increase limit to 16GB for renderer and worker processes to |
297 // accomodate. | 337 // accomodate. |
298 if (process_type == switches::kRendererProcess || | 338 if (sandbox_config == LinuxSandbox::SANDBOX_CONFIG_RENDERER || |
299 process_type == switches::kWorkerProcess) { | 339 sandbox_config == LinuxSandbox::SANDBOX_CONFIG_WORKER) { |
300 address_space_limit = 1L << 34; | 340 address_space_limit = 1L << 34; |
301 } | 341 } |
302 #endif // defined(__LP64__) | 342 #endif // defined(__LP64__) |
303 | 343 |
304 // On all platforms, add a limit to the brk() heap that would prevent | 344 // On all platforms, add a limit to the brk() heap that would prevent |
305 // allocations that can't be index by an int. | 345 // allocations that can't be index by an int. |
306 const rlim_t kNewDataSegmentMaxSize = std::numeric_limits<int>::max(); | 346 const rlim_t kNewDataSegmentMaxSize = std::numeric_limits<int>::max(); |
307 | 347 |
308 bool limited_as = AddResourceLimit(RLIMIT_AS, address_space_limit); | 348 bool limited_as = AddResourceLimit(RLIMIT_AS, address_space_limit); |
309 bool limited_data = AddResourceLimit(RLIMIT_DATA, kNewDataSegmentMaxSize); | 349 bool limited_data = AddResourceLimit(RLIMIT_DATA, kNewDataSegmentMaxSize); |
310 return limited_as && limited_data; | 350 return limited_as && limited_data; |
311 #else | 351 #else |
312 return false; | 352 return false; |
313 #endif // !defined(ADDRESS_SANITIZER) | 353 #endif // !defined(ADDRESS_SANITIZER) |
314 } | 354 } |
315 | 355 |
316 } // namespace content | 356 } // namespace content |
317 | 357 |
OLD | NEW |