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

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