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/stat.h> | 6 #include <sys/stat.h> |
7 #include <sys/types.h> | 7 #include <sys/types.h> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/eintr_wrapper.h" | 10 #include "base/eintr_wrapper.h" |
| 11 #include "base/file_util.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "base/memory/singleton.h" | 13 #include "base/memory/singleton.h" |
| 14 #include "base/time.h" |
13 #include "content/common/sandbox_linux.h" | 15 #include "content/common/sandbox_linux.h" |
14 #include "content/common/seccomp_sandbox.h" | 16 #include "content/common/seccomp_sandbox.h" |
| 17 #include "content/common/sandbox_seccomp_bpf_linux.h" |
15 #include "content/public/common/content_switches.h" | 18 #include "content/public/common/content_switches.h" |
16 #include "content/public/common/sandbox_linux.h" | 19 #include "content/public/common/sandbox_linux.h" |
17 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | 20 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" |
18 | 21 |
19 #if defined(SECCOMP_BPF_SANDBOX) | 22 namespace { |
20 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 23 |
| 24 void LogSandboxStarted(const std::string& sandbox_name) { |
| 25 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 26 const std::string process_type = |
| 27 command_line.GetSwitchValueASCII(switches::kProcessType); |
| 28 const std::string activated_sandbox = |
| 29 "Activated " + sandbox_name + " sandbox for process type: " + |
| 30 process_type + "."; |
| 31 #if defined(OS_CHROMEOS) |
| 32 LOG(WARNING) << activated_sandbox; |
| 33 #else |
| 34 VLOG(1) << activated_sandbox; |
21 #endif | 35 #endif |
22 | 36 } |
23 namespace { | |
24 | 37 |
25 // Implement the command line enabling logic for seccomp-legacy. | 38 // Implement the command line enabling logic for seccomp-legacy. |
26 bool IsSeccompLegacyDesired() { | 39 bool IsSeccompLegacyDesired() { |
27 #if defined(SECCOMP_SANDBOX) | 40 #if defined(SECCOMP_SANDBOX) |
28 #if defined(NDEBUG) | 41 #if defined(NDEBUG) |
29 // Off by default; allow turning on with a switch. | 42 // Off by default; allow turning on with a switch. |
30 return CommandLine::ForCurrentProcess()->HasSwitch( | 43 return CommandLine::ForCurrentProcess()->HasSwitch( |
31 switches::kEnableSeccompSandbox); | 44 switches::kEnableSeccompSandbox); |
32 #else | 45 #else |
33 // On by default; allow turning off with a switch. | 46 // On by default; allow turning off with a switch. |
34 return !CommandLine::ForCurrentProcess()->HasSwitch( | 47 return !CommandLine::ForCurrentProcess()->HasSwitch( |
35 switches::kDisableSeccompSandbox); | 48 switches::kDisableSeccompSandbox); |
36 #endif // NDEBUG | 49 #endif // NDEBUG |
37 #endif // SECCOMP_SANDBOX | 50 #endif // SECCOMP_SANDBOX |
38 return false; | 51 return false; |
39 } | 52 } |
40 | 53 |
| 54 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are |
| 55 // supported. |
| 56 bool ShouldEnableSeccompLegacy(const std::string& process_type) { |
| 57 if (IsSeccompLegacyDesired() && |
| 58 process_type == switches::kRendererProcess) { |
| 59 return true; |
| 60 } else { |
| 61 return false; |
| 62 } |
| 63 } |
| 64 |
41 } // namespace | 65 } // namespace |
42 | 66 |
43 namespace content { | 67 namespace content { |
44 | 68 |
45 LinuxSandbox::LinuxSandbox() | 69 LinuxSandbox::LinuxSandbox() |
46 : proc_fd_(-1), | 70 : proc_fd_(-1), |
47 pre_initialized_(false), | 71 pre_initialized_(false), |
48 seccomp_legacy_supported_(false), | 72 seccomp_legacy_supported_(false), |
| 73 seccomp_bpf_supported_(false), |
49 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { | 74 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { |
50 if (setuid_sandbox_client_ == NULL) { | 75 if (setuid_sandbox_client_ == NULL) { |
51 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; | 76 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; |
52 } | 77 } |
53 } | 78 } |
54 | 79 |
55 LinuxSandbox::~LinuxSandbox() { | 80 LinuxSandbox::~LinuxSandbox() { |
56 } | 81 } |
57 | 82 |
58 LinuxSandbox* LinuxSandbox::GetInstance() { | 83 LinuxSandbox* LinuxSandbox::GetInstance() { |
59 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); | 84 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); |
60 CHECK(instance); | 85 CHECK(instance); |
61 return instance; | 86 return instance; |
62 } | 87 } |
63 | 88 |
64 void LinuxSandbox::PreinitializeSandboxBegin() { | 89 void LinuxSandbox::PreinitializeSandboxBegin() { |
65 CHECK(!pre_initialized_); | 90 CHECK(!pre_initialized_); |
66 seccomp_legacy_supported_ = false; | 91 seccomp_legacy_supported_ = false; |
| 92 seccomp_bpf_supported_ = false; |
67 #if defined(SECCOMP_SANDBOX) | 93 #if defined(SECCOMP_SANDBOX) |
68 if (IsSeccompLegacyDesired()) { | 94 if (IsSeccompLegacyDesired()) { |
69 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); | 95 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); |
70 if (proc_fd_ < 0) { | 96 if (proc_fd_ < 0) { |
71 LOG(ERROR) << "Cannot access \"/proc\". Disabling seccomp-legacy " | 97 LOG(ERROR) << "Cannot access \"/proc\". Disabling seccomp-legacy " |
72 "sandboxing."; | 98 "sandboxing."; |
73 // Now is a good time to figure out if we can support seccomp sandboxing | 99 // Now is a good time to figure out if we can support seccomp sandboxing |
74 // at all. We will call SupportsSeccompSandbox again later, when actually | 100 // at all. We will call SupportsSeccompSandbox again later, when actually |
75 // enabling it, but we allow the implementation to cache some information. | 101 // enabling it, but we allow the implementation to cache some information. |
76 // This is the only place where we will log full lack of seccomp-legacy | 102 // This is the only place where we will log full lack of seccomp-legacy |
77 // support. | 103 // support. |
78 } else if (!SupportsSeccompSandbox(proc_fd_)) { | 104 } else if (!SupportsSeccompSandbox(proc_fd_)) { |
79 VLOG(1) << "Lacking support for seccomp-legacy sandbox."; | 105 VLOG(1) << "Lacking support for seccomp-legacy sandbox."; |
80 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | 106 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); |
81 proc_fd_ = -1; | 107 proc_fd_ = -1; |
82 } else { | 108 } else { |
83 seccomp_legacy_supported_ = true; | 109 seccomp_legacy_supported_ = true; |
84 } | 110 } |
85 } | 111 } |
86 #endif // SECCOMP_SANDBOX | 112 #endif // SECCOMP_SANDBOX |
87 #if defined(SECCOMP_BPF_SANDBOX) | |
88 // Similarly, we "pre-warm" the code that detects supports for seccomp BPF. | 113 // Similarly, we "pre-warm" the code that detects supports for seccomp BPF. |
89 // TODO(jln): Use proc_fd_ here too once we're comfortable it does not create | 114 // TODO(jln): Use proc_fd_ here too once we're comfortable it does not create |
90 // an additional security risk. | 115 // an additional security risk. |
91 if (playground2::Sandbox::supportsSeccompSandbox(-1) != | 116 if (SandboxSeccompBpf::IsSeccompBpfDesired()) { |
92 playground2::Sandbox::STATUS_AVAILABLE) { | 117 if (!SandboxSeccompBpf::SupportsSandbox()) { |
93 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; | 118 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; |
| 119 } else { |
| 120 seccomp_bpf_supported_ = true; |
| 121 } |
94 } | 122 } |
95 #endif // SECCOMP_BPF_SANDBOX | |
96 pre_initialized_ = true; | 123 pre_initialized_ = true; |
97 } | 124 } |
98 | 125 |
99 // Once we finally know our process type, we can cleanup proc_fd_ | 126 // Once we finally know our process type, we can cleanup proc_fd_ |
100 // or pass it to seccomp-legacy. | 127 // or pass it to seccomp-legacy. |
101 void LinuxSandbox::PreinitializeSandboxFinish( | 128 void LinuxSandbox::PreinitializeSandboxFinish( |
102 const std::string& process_type) { | 129 const std::string& process_type) { |
103 CHECK(pre_initialized_); | 130 CHECK(pre_initialized_); |
104 if (proc_fd_ >= 0) { | 131 if (proc_fd_ >= 0) { |
105 if (ShouldEnableSeccompLegacy(process_type)) { | 132 if (ShouldEnableSeccompLegacy(process_type)) { |
106 #if defined(SECCOMP_SANDBOX) | 133 #if defined(SECCOMP_SANDBOX) |
107 SeccompSandboxSetProcFd(proc_fd_); | 134 SeccompSandboxSetProcFd(proc_fd_); |
108 #endif | 135 #endif |
109 } else { | 136 } else { |
110 DCHECK_GE(proc_fd_, 0); | 137 DCHECK_GE(proc_fd_, 0); |
111 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); | 138 CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); |
112 } | 139 } |
113 proc_fd_ = -1; | 140 proc_fd_ = -1; |
114 } | 141 } |
115 } | 142 } |
116 | 143 |
117 void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { | 144 void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { |
118 PreinitializeSandboxBegin(); | 145 PreinitializeSandboxBegin(); |
119 PreinitializeSandboxFinish(process_type); | 146 PreinitializeSandboxFinish(process_type); |
120 } | 147 } |
121 | 148 |
122 int LinuxSandbox::GetStatus() { | 149 int LinuxSandbox::GetStatus() const { |
123 CHECK(pre_initialized_); | 150 CHECK(pre_initialized_); |
124 int sandbox_flags = 0; | 151 int sandbox_flags = 0; |
125 if (setuid_sandbox_client_->IsSandboxed()) { | 152 if (setuid_sandbox_client_->IsSandboxed()) { |
126 sandbox_flags |= kSandboxLinuxSUID; | 153 sandbox_flags |= kSandboxLinuxSUID; |
127 if (setuid_sandbox_client_->IsInNewPIDNamespace()) | 154 if (setuid_sandbox_client_->IsInNewPIDNamespace()) |
128 sandbox_flags |= kSandboxLinuxPIDNS; | 155 sandbox_flags |= kSandboxLinuxPIDNS; |
129 if (setuid_sandbox_client_->IsInNewNETNamespace()) | 156 if (setuid_sandbox_client_->IsInNewNETNamespace()) |
130 sandbox_flags |= kSandboxLinuxNetNS; | 157 sandbox_flags |= kSandboxLinuxNetNS; |
131 } | 158 } |
132 if (seccomp_legacy_supported_) { | 159 if (seccomp_legacy_supported() && |
| 160 ShouldEnableSeccompLegacy(switches::kRendererProcess)) { |
| 161 // We report whether the sandbox will be activated when renderers go |
| 162 // through sandbox initialization. |
133 sandbox_flags |= kSandboxLinuxSeccomp; | 163 sandbox_flags |= kSandboxLinuxSeccomp; |
134 } | 164 } |
135 return sandbox_flags; | 165 return sandbox_flags; |
136 } | 166 } |
137 | 167 |
| 168 bool LinuxSandbox::IsSingleThreaded() const { |
| 169 // TODO(jln): re-implement this properly and use our proc_fd_ if available. |
| 170 // Possibly racy, but it's ok because this is more of a debug check to catch |
| 171 // new threaded situations arising during development. |
| 172 int num_threads = file_util::CountFilesCreatedAfter( |
| 173 FilePath("/proc/self/task"), |
| 174 base::Time::UnixEpoch()); |
| 175 |
| 176 // We pass the test if we don't know ( == 0), because the setuid sandbox |
| 177 // will prevent /proc access in some contexts. |
| 178 return num_threads == 1 || num_threads == 0; |
| 179 } |
| 180 |
138 sandbox::SetuidSandboxClient* | 181 sandbox::SetuidSandboxClient* |
139 LinuxSandbox::setuid_sandbox_client() const { | 182 LinuxSandbox::setuid_sandbox_client() const { |
140 return setuid_sandbox_client_.get(); | 183 return setuid_sandbox_client_.get(); |
141 } | 184 } |
142 | 185 |
143 // For seccomp-legacy, we implement the policy inline, here. | 186 // For seccomp-legacy, we implement the policy inline, here. |
144 bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { | 187 bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { |
145 if (!pre_initialized_) | 188 if (!pre_initialized_) |
146 PreinitializeSandbox(process_type); | 189 PreinitializeSandbox(process_type); |
147 if (ShouldEnableSeccompLegacy(process_type)) { | 190 if (seccomp_legacy_supported() && ShouldEnableSeccompLegacy(process_type)) { |
148 // SupportsSeccompSandbox() returns a cached result, as we already | 191 // SupportsSeccompSandbox() returns a cached result, as we already |
149 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us | 192 // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us |
150 // to not pass in a file descriptor for "/proc". | 193 // to not pass in a file descriptor for "/proc". |
151 #if defined(SECCOMP_SANDBOX) | 194 #if defined(SECCOMP_SANDBOX) |
152 if (SupportsSeccompSandbox(-1)) { | 195 if (SupportsSeccompSandbox(-1)) { |
153 StartSeccompSandbox(); | 196 StartSeccompSandbox(); |
| 197 LogSandboxStarted("seccomp-legacy"); |
154 return true; | 198 return true; |
155 } | 199 } |
156 #endif | 200 #endif |
157 } | 201 } |
158 return false; | 202 return false; |
159 } | 203 } |
160 | 204 |
161 // For seccomp-bpf, we will use the seccomp-bpf policy class. | 205 // For seccomp-bpf, we use the SandboxSeccompBpf class. |
162 // TODO(jln): implement this. | |
163 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { | 206 bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { |
164 CHECK(pre_initialized_); | 207 if (!pre_initialized_) |
165 NOTREACHED(); | 208 PreinitializeSandbox(process_type); |
166 return false; | 209 bool started_bpf_sandbox = false; |
| 210 if (seccomp_bpf_supported()) |
| 211 started_bpf_sandbox = SandboxSeccompBpf::StartSandbox(process_type); |
| 212 |
| 213 if (started_bpf_sandbox) |
| 214 LogSandboxStarted("seccomp-bpf"); |
| 215 |
| 216 return started_bpf_sandbox; |
167 } | 217 } |
168 | 218 |
169 // Our "policy" on whether or not to enable seccomp-legacy. Only renderers are | 219 bool LinuxSandbox::seccomp_legacy_supported() const { |
170 // supported. | |
171 bool LinuxSandbox::ShouldEnableSeccompLegacy( | |
172 const std::string& process_type) { | |
173 CHECK(pre_initialized_); | 220 CHECK(pre_initialized_); |
174 if (IsSeccompLegacyDesired() && | 221 return seccomp_legacy_supported_; |
175 seccomp_legacy_supported_ && | 222 } |
176 process_type == switches::kRendererProcess) { | 223 |
177 return true; | 224 bool LinuxSandbox::seccomp_bpf_supported() const { |
178 } else { | 225 CHECK(pre_initialized_); |
179 return false; | 226 return seccomp_bpf_supported_; |
180 } | |
181 } | 227 } |
182 | 228 |
183 } // namespace content | 229 } // namespace content |
184 | 230 |
OLD | NEW |