OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <fcntl.h> | |
6 #include <sys/stat.h> | |
7 #include <sys/types.h> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/eintr_wrapper.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/singleton.h" | |
13 #include "content/common/sandbox_linux.h" | |
14 #include "content/common/seccomp_sandbox.h" | |
15 #include "content/public/common/content_switches.h" | |
16 #include "content/public/common/sandbox_linux.h" | |
17 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | |
18 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | |
19 | |
20 namespace { | |
21 | |
22 // Implement the command line enabling logic for seccomp-legacy. | |
23 bool IsSeccompLegacyDesired() { | |
24 #if defined(SECCOMP_SANDBOX) | |
25 #if defined(NDEBUG) | |
26 // Off by default; allow turning on with a switch. | |
27 return CommandLine::ForCurrentProcess()->HasSwitch( | |
28 switches::kEnableSeccompSandbox); | |
29 #else | |
30 // On by default; allow turning off with a switch. | |
31 return !CommandLine::ForCurrentProcess()->HasSwitch( | |
32 switches::kDisableSeccompSandbox); | |
33 #endif // NDEBUG | |
34 #endif // SECCOMP_SANDBOX | |
35 return false; | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 namespace content { | |
41 | |
42 LinuxSandbox::LinuxSandbox() | |
43 : proc_fd_(-1), | |
44 pre_initialized_(false), | |
45 seccomp_legacy_supported_(false), | |
46 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { | |
47 if (setuid_sandbox_client_ == NULL) { | |
48 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; | |
49 } | |
50 } | |
51 | |
52 LinuxSandbox::~LinuxSandbox() { | |
53 } | |
54 | |
55 LinuxSandbox* LinuxSandbox::GetInstance() { | |
56 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); | |
57 CHECK(instance); | |
58 return instance; | |
59 } | |
60 | |
61 void LinuxSandbox::PreinitializeSandboxBegin() { | |
62 CHECK(!pre_initialized_); | |
63 seccomp_legacy_supported_ = false; | |
64 #if defined(SECCOMP_SANDBOX) | |
65 if (IsSeccompLegacyDesired()) { | |
66 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); | |
67 if (proc_fd_ < 0) { | |
68 LOG(ERROR) << "Cannot access \"/proc\". Disabling seccomp-legacy " | |
69 "sandboxing."; | |
70 // Now is a good time to figure out if we can support seccomp sandboxing | |
71 // at all. We will call SupportsSeccompSandbox again later, when actually | |
72 // enabling it, but we allow the implementation to cache some information. | |
73 // This is the only place where we will log full lack of seccomp-legacy | |
74 // support. | |
75 } else if (!SupportsSeccompSandbox(proc_fd_)) { | |
76 VLOG(1) << "Lacking support for seccomp-legacy sandbox."; | |
77 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | |
78 proc_fd_ = -1; | |
79 } else { | |
80 seccomp_legacy_supported_ = true; | |
81 } | |
82 } | |
83 #endif // SECCOMP_SANDBOX | |
84 #if defined(SECCOMP_BPF_SANDBOX) | |
85 // Similarly, we "pre-warm" the code that detects supports for seccomp BPF. | |
86 // TODO(jln): Use proc_fd_ here too once we're comfortable it does not create | |
87 // an additional security risk. | |
88 if (playground2::Sandbox::supportsSeccompSandbox(-1) != | |
89 playground2::Sandbox::STATUS_AVAILABLE) { | |
90 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; | |
91 } | |
92 #endif // SECCOMP_BPF_SANDBOX | |
93 pre_initialized_ = true; | |
94 } | |
95 | |
96 // Once we finally know our process type, we can cleanup proc_fd_ | |
97 // or pass it to seccomp-legacy. | |
98 void LinuxSandbox::PreinitializeSandboxFinish( | |
99 const std::string& process_type) { | |
100 CHECK(pre_initialized_); | |
101 if (proc_fd_ >= 0) { | |
102 if (ShouldEnableSeccompLegacy(process_type)) { | |
103 #if defined(SECCOMP_SANDBOX) | |
104 SeccompSandboxSetProcFd(proc_fd_); | |
105 #endif | |
106 } else { | |
107 DCHECK_GE(proc_fd_, 0); | |
108 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | |
109 } | |
110 proc_fd_ = -1; | |
111 } | |
112 } | |
113 | |
114 void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { | |
115 PreinitializeSandboxBegin(); | |
116 PreinitializeSandboxFinish(process_type); | |
117 } | |
118 | |
119 int LinuxSandbox::GetStatus() { | |
120 CHECK(pre_initialized_); | |
121 int sandbox_flags = 0; | |
122 if (setuid_sandbox_client_->IsSandboxed()) { | |
123 sandbox_flags |= kSandboxLinuxSUID; | |
124 if (setuid_sandbox_client_->IsInNewPIDNamespace()) | |
125 sandbox_flags |= kSandboxLinuxPIDNS; | |
126 if (setuid_sandbox_client_->IsInNewNETNamespace()) | |
127 sandbox_flags |= kSandboxLinuxNetNS; | |
128 } | |
129 if (seccomp_legacy_supported_) { | |
130 sandbox_flags |= kSandboxLinuxSeccomp; | |
131 } | |
132 return sandbox_flags; | |
133 } | |
134 | |
135 sandbox::SetuidSandboxClient* | |
136 LinuxSandbox::setuid_sandbox_client() const { | |
137 return setuid_sandbox_client_.get(); | |
138 } | |
139 | |
140 // For seccomp-legacy, we implement the policy inline, here. | |
141 bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { | |
142 if (!pre_initialized_) | |
143 PreinitializeSandbox(process_type); | |
144 if (ShouldEnableSeccompLegacy(process_type)) { | |
145 // SupportsSeccompSandbox() returns a cached result, as we already | |
146 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us | |
147 // to not pass in a file descriptor for "/proc". | |
148 #if defined(SECCOMP_SANDBOX) | |
149 if (SupportsSeccompSandbox(-1)) { | |
150 StartSeccompSandbox(); | |
151 return true; | |
152 } | |
153 #endif | |
154 } | |
155 return false; | |
156 } | |
157 | |
158 // For seccomp-bpf, we will use the seccomp-bpf policy class. | |
159 // TODO(jln): implement this. | |
160 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { | |
161 CHECK(pre_initialized_); | |
162 NOTREACHED(); | |
163 return false; | |
164 } | |
165 | |
166 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are | |
167 // supported. | |
168 bool LinuxSandbox::ShouldEnableSeccompLegacy( | |
169 const std::string& process_type) { | |
170 CHECK(pre_initialized_); | |
171 if (IsSeccompLegacyDesired() && | |
172 seccomp_legacy_supported_ && | |
173 process_type == switches::kRendererProcess) { | |
174 return true; | |
175 } else { | |
176 return false; | |
177 } | |
178 } | |
179 | |
180 } // namespace content | |
181 | |
OLD | NEW |