Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: content/common/sandbox_linux/sandbox_linux.cc

Issue 733303004: Linux sandbox: change API to start the sandbox (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address nits from Jorge. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « content/common/sandbox_linux/sandbox_linux.h ('k') | content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698