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

Side by Side Diff: content/browser/zygote_host/zygote_host_impl_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: fix typo 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
« no previous file with comments | « content/browser/zygote_host/zygote_host_impl_linux.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "content/browser/zygote_host/zygote_host_impl_linux.h" 5 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
6 6
7 #include <sys/socket.h>
8
7 #include "base/allocator/allocator_extension.h" 9 #include "base/allocator/allocator_extension.h"
8 #include "base/command_line.h"
9 #include "base/files/file_enumerator.h" 10 #include "base/files/file_enumerator.h"
11 #include "base/posix/unix_domain_socket_linux.h"
10 #include "base/process/kill.h" 12 #include "base/process/kill.h"
11 #include "base/process/memory.h" 13 #include "base/process/memory.h"
12 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
13 #include "content/public/browser/content_browser_client.h" 15 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
16 #include "content/common/child_process_sandbox_support_impl_linux.h"
17 #include "content/common/zygote_commands_linux.h"
14 #include "content/public/common/content_switches.h" 18 #include "content/public/common/content_switches.h"
15 #include "sandbox/linux/services/credentials.h" 19 #include "sandbox/linux/services/credentials.h"
20 #include "sandbox/linux/services/namespace_sandbox.h"
21 #include "sandbox/linux/suid/client/setuid_sandbox_host.h"
16 #include "sandbox/linux/suid/common/sandbox.h" 22 #include "sandbox/linux/suid/common/sandbox.h"
17 23
18 namespace content { 24 namespace content {
19 25
26 namespace {
27
28 // Receive a fixed message on fd and return the sender's PID.
29 // Returns true if the message received matches the expected message.
30 bool ReceiveFixedMessage(int fd,
31 const char* expect_msg,
32 size_t expect_len,
33 base::ProcessId* sender_pid) {
34 char buf[expect_len + 1];
rickyz (no longer on Chrome) 2016/05/20 23:41:44 Didn't originate in your change, but I wonder why
mdempsky 2016/05/21 00:05:07 With framed-message socket types like SOCK_DATAGRA
35 std::vector<base::ScopedFD> fds_vec;
36
37 const ssize_t len = base::UnixDomainSocket::RecvMsgWithPid(
38 fd, buf, sizeof(buf), &fds_vec, sender_pid);
39 if (static_cast<size_t>(len) != expect_len)
40 return false;
41 if (memcmp(buf, expect_msg, expect_len) != 0)
42 return false;
43 if (!fds_vec.empty())
44 return false;
45 return true;
46 }
47
48 } // namespace
49
20 // static 50 // static
21 ZygoteHost* ZygoteHost::GetInstance() { 51 ZygoteHost* ZygoteHost::GetInstance() {
22 return ZygoteHostImpl::GetInstance(); 52 return ZygoteHostImpl::GetInstance();
23 } 53 }
24 54
25 ZygoteHostImpl::ZygoteHostImpl() 55 ZygoteHostImpl::ZygoteHostImpl()
26 : should_use_namespace_sandbox_(true), 56 : use_namespace_sandbox_(false),
57 use_suid_sandbox_(false),
27 use_suid_sandbox_for_adj_oom_score_(false), 58 use_suid_sandbox_for_adj_oom_score_(false),
28 sandbox_binary_(), 59 sandbox_binary_(),
29 zygote_pids_lock_(), 60 zygote_pids_lock_(),
30 zygote_pids_() {} 61 zygote_pids_() {}
31 62
32 ZygoteHostImpl::~ZygoteHostImpl() {} 63 ZygoteHostImpl::~ZygoteHostImpl() {}
33 64
34 // static 65 // static
35 ZygoteHostImpl* ZygoteHostImpl::GetInstance() { 66 ZygoteHostImpl* ZygoteHostImpl::GetInstance() {
36 return base::Singleton<ZygoteHostImpl>::get(); 67 return base::Singleton<ZygoteHostImpl>::get();
37 } 68 }
38 69
39 void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { 70 void ZygoteHostImpl::Init(const base::CommandLine& command_line) {
40 sandbox_binary_ = sandbox_cmd; 71 if (command_line.HasSwitch(switches::kNoSandbox)) {
41 72 return;
42 const base::CommandLine& command_line =
43 *base::CommandLine::ForCurrentProcess();
44 if (command_line.HasSwitch(switches::kNoSandbox) ||
45 command_line.HasSwitch(switches::kDisableNamespaceSandbox) ||
46 !sandbox::Credentials::CanCreateProcessInNewUserNS()) {
47 should_use_namespace_sandbox_ = false;
48 } 73 }
49 74
50 const bool using_namespace_sandbox = ShouldUseNamespaceSandbox(); 75 {
51 // A non empty sandbox_cmd means we want a SUID sandbox. 76 std::unique_ptr<sandbox::SetuidSandboxHost> setuid_sandbox_host(
52 const bool using_suid_sandbox = 77 sandbox::SetuidSandboxHost::Create());
53 !sandbox_binary_.empty() && !using_namespace_sandbox; 78 sandbox_binary_ = setuid_sandbox_host->GetSandboxBinaryPath().value();
79 }
54 80
55 // Use the SUID sandbox for adjusting OOM scores when we are using the setuid 81 if (!command_line.HasSwitch(switches::kDisableNamespaceSandbox) &&
56 // sandbox. This is needed beacuse the processes are non-dumpable, so 82 sandbox::Credentials::CanCreateProcessInNewUserNS()) {
57 // /proc/pid/oom_score_adj can only be written by root. 83 use_namespace_sandbox_ = true;
58 use_suid_sandbox_for_adj_oom_score_ = using_suid_sandbox;
59 84
60 #if defined(OS_CHROMEOS) 85 #if defined(OS_CHROMEOS)
61 // Chrome OS has a kernel patch that restricts oom_score_adj. See 86 // Chrome OS has a kernel patch that restricts oom_score_adj. See
62 // crbug.com/576409 for details. 87 // crbug.com/576409 for details.
63 if (!sandbox_binary_.empty()) { 88 if (!sandbox_binary_.empty()) {
64 use_suid_sandbox_for_adj_oom_score_ = true; 89 use_suid_sandbox_for_adj_oom_score_ = true;
90 } else {
91 LOG(ERROR) << "SUID sandbox binary is missing. Won't be able to adjust "
92 "OOM scores.";
93 }
94 #endif
95 } else if (!command_line.HasSwitch(switches::kDisableSetuidSandbox) &&
96 !sandbox_binary_.empty()) {
97 use_suid_sandbox_ = true;
98
99 // Use the SUID sandbox for adjusting OOM scores when we are using
100 // the setuid sandbox. This is needed beacuse the processes are
101 // non-dumpable, so /proc/pid/oom_score_adj can only be written by
102 // root.
103 use_suid_sandbox_for_adj_oom_score_ = use_suid_sandbox_;
104 } else {
105 LOG(FATAL)
106 << "No usable sandbox! Update your kernel or see "
107 "https://chromium.googlesource.com/chromium/src/+/master/"
108 "docs/linux_suid_sandbox_development.md for more information on "
109 "developing with the SUID sandbox. "
110 "If you want to live dangerously and need an immediate workaround, "
111 "you can try using --"
112 << switches::kNoSandbox << ".";
65 } 113 }
66 #endif
67 } 114 }
68 115
69 void ZygoteHostImpl::AddZygotePid(pid_t pid) { 116 void ZygoteHostImpl::AddZygotePid(pid_t pid) {
70 base::AutoLock lock(zygote_pids_lock_); 117 base::AutoLock lock(zygote_pids_lock_);
71 zygote_pids_.insert(pid); 118 zygote_pids_.insert(pid);
72 } 119 }
73 120
74 bool ZygoteHostImpl::IsZygotePid(pid_t pid) { 121 bool ZygoteHostImpl::IsZygotePid(pid_t pid) {
75 base::AutoLock lock(zygote_pids_lock_); 122 base::AutoLock lock(zygote_pids_lock_);
76 return zygote_pids_.find(pid) != zygote_pids_.end(); 123 return zygote_pids_.find(pid) != zygote_pids_.end();
77 } 124 }
78 125
79 const std::string& ZygoteHostImpl::SandboxCommand() const {
80 return sandbox_binary_;
81 }
82
83 void ZygoteHostImpl::SetRendererSandboxStatus(int status) { 126 void ZygoteHostImpl::SetRendererSandboxStatus(int status) {
84 renderer_sandbox_status_ = status; 127 renderer_sandbox_status_ = status;
85 } 128 }
86 129
87 int ZygoteHostImpl::GetRendererSandboxStatus() const { 130 int ZygoteHostImpl::GetRendererSandboxStatus() const {
88 return renderer_sandbox_status_; 131 return renderer_sandbox_status_;
89 } 132 }
90 133
91 bool ZygoteHostImpl::ShouldUseNamespaceSandbox() { 134 pid_t ZygoteHostImpl::LaunchZygote(base::CommandLine* cmd_line,
92 return should_use_namespace_sandbox_; 135 base::ScopedFD* control_fd) {
136 int fds[2];
137 CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
138 CHECK(base::UnixDomainSocket::EnableReceiveProcessId(fds[0]));
139
140 base::FileHandleMappingVector fds_to_map;
141 fds_to_map.push_back(std::make_pair(fds[1], kZygoteSocketPairFd));
142
143 // Start up the sandbox host process and get the file descriptor for the
144 // renderers to talk to it.
145 const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
146 fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD()));
147
148 base::LaunchOptions options;
149 base::ScopedFD dummy_fd;
150 if (use_suid_sandbox_) {
151 std::unique_ptr<sandbox::SetuidSandboxHost> sandbox_host(
152 sandbox::SetuidSandboxHost::Create());
153 sandbox_host->PrependWrapper(cmd_line);
154 sandbox_host->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd);
155 sandbox_host->SetupLaunchEnvironment();
156 }
157
158 options.fds_to_remap = &fds_to_map;
159 base::Process process =
160 use_namespace_sandbox_
161 ? sandbox::NamespaceSandbox::LaunchProcess(*cmd_line, options)
162 : base::LaunchProcess(*cmd_line, options);
163 CHECK(process.IsValid()) << "Failed to launch zygote process";
164
165 dummy_fd.reset();
166 close(fds[1]);
167 control_fd->reset(fds[0]);
168
169 pid_t pid = process.Pid();
170
171 if (use_namespace_sandbox_ || use_suid_sandbox_) {
172 // The namespace and SUID sandbox will execute the zygote in a new
173 // PID namespace, and the main zygote process will then fork from
174 // there. Watch now our elaborate dance to find and validate the
175 // zygote's PID.
176
177 // First we receive a message from the zygote boot process.
178 base::ProcessId boot_pid;
179 CHECK(ReceiveFixedMessage(fds[0], kZygoteBootMessage,
180 sizeof(kZygoteBootMessage), &boot_pid));
181
182 // Within the PID namespace, the zygote boot process thinks it's PID 1,
183 // but its real PID can never be 1. This gives us a reliable test that
184 // the kernel is translating the sender's PID to our namespace.
185 CHECK_GT(boot_pid, 1)
186 << "Received invalid process ID for zygote; kernel might be too old? "
187 "See crbug.com/357670 or try using --"
188 << switches::kNoSandbox << " to workaround.";
189
190 // Now receive the message that the zygote's ready to go, along with the
191 // main zygote process's ID.
192 pid_t real_pid;
193 CHECK(ReceiveFixedMessage(fds[0], kZygoteHelloMessage,
194 sizeof(kZygoteHelloMessage), &real_pid));
195 CHECK_GT(real_pid, 1);
196
197 if (real_pid != pid) {
198 // Reap the sandbox.
199 base::EnsureProcessGetsReaped(pid);
200 }
201 pid = real_pid;
202 }
203
204 AddZygotePid(pid);
205 return pid;
93 } 206 }
94 207
95 #if !defined(OS_OPENBSD) 208 #if !defined(OS_OPENBSD)
96 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, 209 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
97 int score) { 210 int score) {
98 // 1) You can't change the oom_score_adj of a non-dumpable process 211 // 1) You can't change the oom_score_adj of a non-dumpable process
99 // (EPERM) unless you're root. Because of this, we can't set the 212 // (EPERM) unless you're root. Because of this, we can't set the
100 // oom_adj from the browser process. 213 // oom_adj from the browser process.
101 // 214 //
102 // 2) We can't set the oom_score_adj before entering the sandbox 215 // 2) We can't set the oom_score_adj before entering the sandbox
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 if (sandbox_helper_process.IsValid()) 271 if (sandbox_helper_process.IsValid())
159 base::EnsureProcessGetsReaped(sandbox_helper_process.Pid()); 272 base::EnsureProcessGetsReaped(sandbox_helper_process.Pid());
160 } else if (!use_suid_sandbox_for_adj_oom_score_) { 273 } else if (!use_suid_sandbox_for_adj_oom_score_) {
161 if (!base::AdjustOOMScore(pid, score)) 274 if (!base::AdjustOOMScore(pid, score))
162 PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid; 275 PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid;
163 } 276 }
164 } 277 }
165 #endif 278 #endif
166 279
167 } // namespace content 280 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/zygote_host/zygote_host_impl_linux.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698