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

Side by Side Diff: content/browser/zygote_host/zygote_communication_linux.cc

Issue 1976403002: Fix logic for checking chrome-sandbox setuid binary (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rickyz feedback Created 4 years, 7 months 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "content/browser/zygote_host/zygote_communication_linux.h" 5 #include "content/browser/zygote_host/zygote_communication_linux.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 #include <sys/socket.h> 8 #include <sys/socket.h>
9 9
10 #include "base/base_switches.h" 10 #include "base/base_switches.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/metrics/sparse_histogram.h" 14 #include "base/metrics/sparse_histogram.h"
15 #include "base/path_service.h" 15 #include "base/path_service.h"
16 #include "base/pickle.h" 16 #include "base/pickle.h"
17 #include "base/posix/eintr_wrapper.h" 17 #include "base/posix/eintr_wrapper.h"
18 #include "base/posix/unix_domain_socket_linux.h" 18 #include "base/posix/unix_domain_socket_linux.h"
19 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
20 #include "content/browser/zygote_host/zygote_host_impl_linux.h" 19 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
21 #include "content/common/child_process_sandbox_support_impl_linux.h"
22 #include "content/common/zygote_commands_linux.h" 20 #include "content/common/zygote_commands_linux.h"
23 #include "content/public/browser/content_browser_client.h" 21 #include "content/public/browser/content_browser_client.h"
22 #include "content/public/common/content_client.h"
24 #include "content/public/common/content_switches.h" 23 #include "content/public/common/content_switches.h"
25 #include "content/public/common/result_codes.h" 24 #include "content/public/common/result_codes.h"
26 #include "sandbox/linux/services/namespace_sandbox.h"
27 #include "sandbox/linux/suid/client/setuid_sandbox_host.h"
28 #include "ui/display/display_switches.h" 25 #include "ui/display/display_switches.h"
29 #include "ui/gfx/switches.h"
30 26
31 namespace content { 27 namespace content {
32 28
33 namespace {
34
35 // Receive a fixed message on fd and return the sender's PID.
36 // Returns true if the message received matches the expected message.
37 bool ReceiveFixedMessage(int fd,
38 const char* expect_msg,
39 size_t expect_len,
40 base::ProcessId* sender_pid) {
41 char buf[expect_len + 1];
42 std::vector<base::ScopedFD> fds_vec;
43
44 const ssize_t len = base::UnixDomainSocket::RecvMsgWithPid(
45 fd, buf, sizeof(buf), &fds_vec, sender_pid);
46 if (static_cast<size_t>(len) != expect_len)
47 return false;
48 if (memcmp(buf, expect_msg, expect_len) != 0)
49 return false;
50 if (!fds_vec.empty())
51 return false;
52 return true;
53 }
54
55 } // namespace
56
57 ZygoteCommunication::ZygoteCommunication() 29 ZygoteCommunication::ZygoteCommunication()
58 : control_fd_(-1), 30 : control_fd_(),
59 control_lock_(), 31 control_lock_(),
60 pid_(), 32 pid_(),
61 list_of_running_zygote_children_(), 33 list_of_running_zygote_children_(),
62 child_tracking_lock_(), 34 child_tracking_lock_(),
63 sandbox_status_(0), 35 sandbox_status_(0),
64 have_read_sandbox_status_word_(false), 36 have_read_sandbox_status_word_(false),
65 init_(false) {} 37 init_(false) {}
66 38
67 ZygoteCommunication::~ZygoteCommunication() {} 39 ZygoteCommunication::~ZygoteCommunication() {}
68 40
69 bool ZygoteCommunication::SendMessage(const base::Pickle& data, 41 bool ZygoteCommunication::SendMessage(const base::Pickle& data,
70 const std::vector<int>* fds) { 42 const std::vector<int>* fds) {
71 DCHECK_NE(-1, control_fd_); 43 DCHECK(control_fd_.is_valid());
72 CHECK(data.size() <= kZygoteMaxMessageLength) 44 CHECK(data.size() <= kZygoteMaxMessageLength)
73 << "Trying to send too-large message to zygote (sending " << data.size() 45 << "Trying to send too-large message to zygote (sending " << data.size()
74 << " bytes, max is " << kZygoteMaxMessageLength << ")"; 46 << " bytes, max is " << kZygoteMaxMessageLength << ")";
75 CHECK(!fds || fds->size() <= base::UnixDomainSocket::kMaxFileDescriptors) 47 CHECK(!fds || fds->size() <= base::UnixDomainSocket::kMaxFileDescriptors)
76 << "Trying to send message with too many file descriptors to zygote " 48 << "Trying to send message with too many file descriptors to zygote "
77 << "(sending " << fds->size() << ", max is " 49 << "(sending " << fds->size() << ", max is "
78 << base::UnixDomainSocket::kMaxFileDescriptors << ")"; 50 << base::UnixDomainSocket::kMaxFileDescriptors << ")";
79 51
80 return base::UnixDomainSocket::SendMsg(control_fd_, data.data(), data.size(), 52 return base::UnixDomainSocket::SendMsg(control_fd_.get(), data.data(),
53 data.size(),
81 fds ? *fds : std::vector<int>()); 54 fds ? *fds : std::vector<int>());
82 } 55 }
83 56
84 ssize_t ZygoteCommunication::ReadSandboxStatus() { 57 ssize_t ZygoteCommunication::ReadSandboxStatus() {
85 DCHECK_NE(-1, control_fd_); 58 DCHECK(control_fd_.is_valid());
86 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, 59 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote,
87 // but don't wait for the reply. Thus, the first time that we read from the 60 // but don't wait for the reply. Thus, the first time that we read from the
88 // zygote, we get the reply to that request. 61 // zygote, we get the reply to that request.
89 ssize_t bytes_read = HANDLE_EINTR( 62 ssize_t bytes_read = HANDLE_EINTR(
90 read(control_fd_, &sandbox_status_, sizeof(sandbox_status_))); 63 read(control_fd_.get(), &sandbox_status_, sizeof(sandbox_status_)));
91 if (bytes_read != sizeof(sandbox_status_)) { 64 if (bytes_read != sizeof(sandbox_status_)) {
92 return -1; 65 return -1;
93 } 66 }
94 return bytes_read; 67 return bytes_read;
95 } 68 }
96 69
97 ssize_t ZygoteCommunication::ReadReply(void* buf, size_t buf_len) { 70 ssize_t ZygoteCommunication::ReadReply(void* buf, size_t buf_len) {
98 DCHECK_NE(-1, control_fd_); 71 DCHECK(control_fd_.is_valid());
99 if (!have_read_sandbox_status_word_) { 72 if (!have_read_sandbox_status_word_) {
100 if (ReadSandboxStatus() == -1) { 73 if (ReadSandboxStatus() == -1) {
101 return -1; 74 return -1;
102 } 75 }
103 have_read_sandbox_status_word_ = true; 76 have_read_sandbox_status_word_ = true;
104 UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_); 77 UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_);
105 } 78 }
106 79
107 return HANDLE_EINTR(read(control_fd_, buf, buf_len)); 80 return HANDLE_EINTR(read(control_fd_.get(), buf, buf_len));
108 } 81 }
109 82
110 pid_t ZygoteCommunication::ForkRequest( 83 pid_t ZygoteCommunication::ForkRequest(
111 const std::vector<std::string>& argv, 84 const std::vector<std::string>& argv,
112 std::unique_ptr<FileDescriptorInfo> mapping, 85 std::unique_ptr<FileDescriptorInfo> mapping,
113 const std::string& process_type) { 86 const std::string& process_type) {
114 DCHECK(init_); 87 DCHECK(init_);
115 88
116 base::Pickle pickle; 89 base::Pickle pickle;
117 int raw_socks[2]; 90 int raw_socks[2];
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 231
259 void ZygoteCommunication::Init() { 232 void ZygoteCommunication::Init() {
260 CHECK(!init_); 233 CHECK(!init_);
261 234
262 base::FilePath chrome_path; 235 base::FilePath chrome_path;
263 CHECK(PathService::Get(base::FILE_EXE, &chrome_path)); 236 CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
264 base::CommandLine cmd_line(chrome_path); 237 base::CommandLine cmd_line(chrome_path);
265 238
266 cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess); 239 cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess);
267 240
268 int fds[2];
269 CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
270 CHECK(base::UnixDomainSocket::EnableReceiveProcessId(fds[0]));
271 base::FileHandleMappingVector fds_to_map;
272 fds_to_map.push_back(std::make_pair(fds[1], kZygoteSocketPairFd));
273
274 base::LaunchOptions options;
275 const base::CommandLine& browser_command_line = 241 const base::CommandLine& browser_command_line =
276 *base::CommandLine::ForCurrentProcess(); 242 *base::CommandLine::ForCurrentProcess();
277 if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) { 243 if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) {
278 cmd_line.PrependWrapper( 244 cmd_line.PrependWrapper(
279 browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix)); 245 browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix));
280 } 246 }
281 // Append any switches from the browser process that need to be forwarded on 247 // Append any switches from the browser process that need to be forwarded on
282 // to the zygote/renderers. 248 // to the zygote/renderers.
283 // Should this list be obtained from browser_render_process_host.cc? 249 // Should this list be obtained from browser_render_process_host.cc?
284 static const char* const kForwardSwitches[] = { 250 static const char* const kForwardSwitches[] = {
285 switches::kAllowSandboxDebugging, switches::kAndroidFontsPath, 251 switches::kAllowSandboxDebugging, switches::kAndroidFontsPath,
286 switches::kDisableSeccompFilterSandbox, 252 switches::kDisableSeccompFilterSandbox,
287 switches::kEnableHeapProfiling, 253 switches::kEnableHeapProfiling,
288 switches::kEnableLogging, // Support, e.g., --enable-logging=stderr. 254 switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
289 // Zygote process needs to know what resources to have loaded when it 255 // Zygote process needs to know what resources to have loaded when it
290 // becomes a renderer process. 256 // becomes a renderer process.
291 switches::kForceDeviceScaleFactor, switches::kLoggingLevel, 257 switches::kForceDeviceScaleFactor, switches::kLoggingLevel,
292 switches::kNoSandbox, switches::kPpapiInProcess, 258 switches::kNoSandbox, switches::kPpapiInProcess,
293 switches::kRegisterPepperPlugins, switches::kV, switches::kVModule, 259 switches::kRegisterPepperPlugins, switches::kV, switches::kVModule,
294 }; 260 };
295 cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches, 261 cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
296 arraysize(kForwardSwitches)); 262 arraysize(kForwardSwitches));
297 263
298 GetContentClient()->browser()->AppendExtraCommandLineSwitches(&cmd_line, -1); 264 GetContentClient()->browser()->AppendExtraCommandLineSwitches(&cmd_line, -1);
299 265
300 const bool using_namespace_sandbox = 266 pid_ = ZygoteHostImpl::GetInstance()->LaunchZygote(&cmd_line, &control_fd_);
301 ZygoteHostImpl::GetInstance()->ShouldUseNamespaceSandbox();
302 // A non empty sandbox_cmd means we want a SUID sandbox.
303 const bool using_suid_sandbox =
304 !ZygoteHostImpl::GetInstance()->SandboxCommand().empty() &&
305 !using_namespace_sandbox;
306
307 // Start up the sandbox host process and get the file descriptor for the
308 // renderers to talk to it.
309 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
310 fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD()));
311
312 base::ScopedFD dummy_fd;
313 if (using_suid_sandbox) {
314 std::unique_ptr<sandbox::SetuidSandboxHost> sandbox_host(
315 sandbox::SetuidSandboxHost::Create());
316 sandbox_host->PrependWrapper(&cmd_line);
317 sandbox_host->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd);
318 sandbox_host->SetupLaunchEnvironment();
319 }
320
321 options.fds_to_remap = &fds_to_map;
322 base::Process process =
323 using_namespace_sandbox
324 ? sandbox::NamespaceSandbox::LaunchProcess(cmd_line, options)
325 : base::LaunchProcess(cmd_line, options);
326 CHECK(process.IsValid()) << "Failed to launch zygote process";
327
328 dummy_fd.reset();
329
330 if (using_suid_sandbox || using_namespace_sandbox) {
331 // The SUID sandbox will execute the zygote in a new PID namespace, and
332 // the main zygote process will then fork from there. Watch now our
333 // elaborate dance to find and validate the zygote's PID.
334
335 // First we receive a message from the zygote boot process.
336 base::ProcessId boot_pid;
337 CHECK(ReceiveFixedMessage(fds[0], kZygoteBootMessage,
338 sizeof(kZygoteBootMessage), &boot_pid));
339
340 // Within the PID namespace, the zygote boot process thinks it's PID 1,
341 // but its real PID can never be 1. This gives us a reliable test that
342 // the kernel is translating the sender's PID to our namespace.
343 CHECK_GT(boot_pid, 1)
344 << "Received invalid process ID for zygote; kernel might be too old? "
345 "See crbug.com/357670 or try using --"
346 << switches::kDisableSetuidSandbox << " to workaround.";
347
348 // Now receive the message that the zygote's ready to go, along with the
349 // main zygote process's ID.
350 CHECK(ReceiveFixedMessage(fds[0], kZygoteHelloMessage,
351 sizeof(kZygoteHelloMessage), &pid_));
352 CHECK_GT(pid_, 1);
353
354 if (process.Pid() != pid_) {
355 // Reap the sandbox.
356 base::EnsureProcessGetsReaped(process.Pid());
357 }
358 } else {
359 // Not using the SUID sandbox.
360 // Note that ~base::Process() will reset the internal value, but there's no
361 // real "handle" on POSIX so that is safe.
362 pid_ = process.Pid();
363 }
364
365 close(fds[1]);
366 control_fd_ = fds[0];
367
368 ZygoteHostImpl::GetInstance()->AddZygotePid(pid_);
369 267
370 base::Pickle pickle; 268 base::Pickle pickle;
371 pickle.WriteInt(kZygoteCommandGetSandboxStatus); 269 pickle.WriteInt(kZygoteCommandGetSandboxStatus);
372 if (!SendMessage(pickle, NULL)) 270 if (!SendMessage(pickle, NULL))
373 LOG(FATAL) << "Cannot communicate with zygote"; 271 LOG(FATAL) << "Cannot communicate with zygote";
374 272
375 init_ = true; 273 init_ = true;
376 } 274 }
377 275
378 base::TerminationStatus ZygoteCommunication::GetTerminationStatus( 276 base::TerminationStatus ZygoteCommunication::GetTerminationStatus(
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 } 328 }
431 if (ReadSandboxStatus() == -1) { 329 if (ReadSandboxStatus() == -1) {
432 return 0; 330 return 0;
433 } 331 }
434 have_read_sandbox_status_word_ = true; 332 have_read_sandbox_status_word_ = true;
435 UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_); 333 UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_);
436 return sandbox_status_; 334 return sandbox_status_;
437 } 335 }
438 336
439 } // namespace content 337 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/zygote_host/zygote_communication_linux.h ('k') | content/browser/zygote_host/zygote_host_impl_linux.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698