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
3 // found in the LICENSE file.
4 
5 #include "services/service_manager/zygote/zygote_main.h"
6 
7 #include <dlfcn.h>
8 #include <fcntl.h>
9 #include <pthread.h>
10 #include <signal.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <string.h>
14 #if !defined(OS_BSD)
15 #include <sys/prctl.h>
16 #endif
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20 
21 #include <utility>
22 
23 #include "base/bind.h"
24 #include "base/compiler_specific.h"
25 #include "base/posix/eintr_wrapper.h"
26 #include "base/posix/unix_domain_socket.h"
27 #include "base/rand_util.h"
28 #include "base/strings/safe_sprintf.h"
29 #include "base/strings/string_number_conversions.h"
30 #include "base/system/sys_info.h"
31 #include "build/build_config.h"
32 #include "sandbox/linux/services/credentials.h"
33 #include "sandbox/linux/services/init_process_reaper.h"
34 #include "sandbox/linux/services/libc_interceptor.h"
35 #include "sandbox/linux/services/namespace_sandbox.h"
36 #include "sandbox/linux/services/thread_helpers.h"
37 #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
38 #include "services/service_manager/embedder/descriptors.h"
39 #include "services/service_manager/embedder/switches.h"
40 #include "services/service_manager/sandbox/linux/sandbox_debug_handling_linux.h"
41 #include "services/service_manager/sandbox/linux/sandbox_linux.h"
42 #include "services/service_manager/sandbox/sandbox.h"
43 #include "services/service_manager/sandbox/switches.h"
44 #include "services/service_manager/zygote/common/common_sandbox_support_linux.h"
45 #include "services/service_manager/zygote/common/zygote_commands_linux.h"
46 #include "services/service_manager/zygote/common/zygote_fork_delegate_linux.h"
47 #include "services/service_manager/zygote/zygote_linux.h"
48 #include "third_party/icu/source/i18n/unicode/timezone.h"
49 
50 namespace service_manager {
51 
52 namespace {
53 
CloseFds(const std::vector<int> & fds)54 void CloseFds(const std::vector<int>& fds) {
55   for (const auto& it : fds) {
56     PCHECK(0 == IGNORE_EINTR(close(it)));
57   }
58 }
59 
ClosureFromTwoClosures(base::OnceClosure one,base::OnceClosure two)60 base::OnceClosure ClosureFromTwoClosures(base::OnceClosure one,
61                                          base::OnceClosure two) {
62   return base::BindOnce(
63       [](base::OnceClosure one, base::OnceClosure two) {
64         if (!one.is_null())
65           std::move(one).Run();
66         if (!two.is_null())
67           std::move(two).Run();
68       },
69       std::move(one), std::move(two));
70 }
71 
72 }  // namespace
73 
74 // This function triggers the static and lazy construction of objects that need
75 // to be created before imposing the sandbox.
ZygotePreSandboxInit()76 static void ZygotePreSandboxInit() {
77   base::RandUint64();
78 
79   base::SysInfo::AmountOfPhysicalMemory();
80   base::SysInfo::NumberOfProcessors();
81 
82   // ICU DateFormat class (used in base/time_format.cc) needs to get the
83   // Olson timezone ID by accessing the zoneinfo files on disk. After
84   // TimeZone::createDefault is called once here, the timezone ID is
85   // cached and there's no more need to access the file system.
86   std::unique_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
87 }
88 
CreateInitProcessReaper(base::OnceClosure post_fork_parent_callback)89 static bool CreateInitProcessReaper(
90     base::OnceClosure post_fork_parent_callback) {
91   // The current process becomes init(1), this function returns from a
92   // newly created process.
93   if (!sandbox::CreateInitProcessReaper(std::move(post_fork_parent_callback))) {
94     LOG(ERROR) << "Error creating an init process to reap zombies";
95     return false;
96   }
97   return true;
98 }
99 
100 // Enter the setuid sandbox. This requires the current process to have been
101 // created through the setuid sandbox.
EnterSuidSandbox(sandbox::SetuidSandboxClient * setuid_sandbox,base::OnceClosure post_fork_parent_callback)102 static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox,
103                              base::OnceClosure post_fork_parent_callback) {
104 #if !defined(OS_BSD)
105   DCHECK(setuid_sandbox);
106   DCHECK(setuid_sandbox->IsSuidSandboxChild());
107 
108   // Use the SUID sandbox.  This still allows the seccomp sandbox to
109   // be enabled by the process later.
110 
111   if (!setuid_sandbox->IsSuidSandboxUpToDate()) {
112     LOG(WARNING) << "You are using a wrong version of the setuid binary!\n"
113                     "Please read "
114                     "https://chromium.googlesource.com/chromium/src/+/master/"
115                     "docs/linux/suid_sandbox_development.md."
116                     "\n\n";
117   }
118 
119   if (!setuid_sandbox->ChrootMe())
120     return false;
121 
122   if (setuid_sandbox->IsInNewPIDNamespace()) {
123     CHECK_EQ(1, getpid())
124         << "The SUID sandbox created a new PID namespace but Zygote "
125            "is not the init process. Please, make sure the SUID "
126            "binary is up to date.";
127   }
128 
129   if (getpid() == 1) {
130     // The setuid sandbox has created a new PID namespace and we need
131     // to assume the role of init.
132     CHECK(CreateInitProcessReaper(std::move(post_fork_parent_callback)));
133   }
134 
135   CHECK(service_manager::SandboxDebugHandling::SetDumpableStatusAndHandlers());
136   return true;
137 #else
138   return false;
139 #endif
140 }
141 
DropAllCapabilities(int proc_fd)142 static void DropAllCapabilities(int proc_fd) {
143   CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd));
144 }
145 
EnterNamespaceSandbox(service_manager::SandboxLinux * linux_sandbox,base::OnceClosure post_fork_parent_callback)146 static void EnterNamespaceSandbox(service_manager::SandboxLinux* linux_sandbox,
147                                   base::OnceClosure post_fork_parent_callback) {
148   linux_sandbox->EngageNamespaceSandbox(true /* from_zygote */);
149   if (getpid() == 1) {
150     CHECK(CreateInitProcessReaper(ClosureFromTwoClosures(
151         base::BindOnce(DropAllCapabilities, linux_sandbox->proc_fd()),
152         std::move(post_fork_parent_callback))));
153   }
154 }
155 
EnterLayerOneSandbox(service_manager::SandboxLinux * linux_sandbox,const bool using_layer1_sandbox,const bool using_layer2_sandbox,base::OnceClosure post_fork_parent_callback)156 static void EnterLayerOneSandbox(service_manager::SandboxLinux* linux_sandbox,
157                                  const bool using_layer1_sandbox,
158                                  const bool using_layer2_sandbox,
159                                  base::OnceClosure post_fork_parent_callback) {
160   DCHECK(linux_sandbox);
161 
162   ZygotePreSandboxInit();
163 
164 // Check that the pre-sandbox initialization didn't spawn threads.
165 // It's not just our code which may do so - some system-installed libraries
166 // are known to be culprits, e.g. lttng.
167 #if !defined(THREAD_SANITIZER)
168   if (using_layer1_sandbox || using_layer2_sandbox)
169   CHECK(sandbox::ThreadHelpers::IsSingleThreaded());
170 #endif
171 
172   sandbox::SetuidSandboxClient* setuid_sandbox =
173       linux_sandbox->setuid_sandbox_client();
174   if (setuid_sandbox->IsSuidSandboxChild()) {
175     CHECK(
176         EnterSuidSandbox(setuid_sandbox, std::move(post_fork_parent_callback)))
177         << "Failed to enter setuid sandbox";
178   } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) {
179     EnterNamespaceSandbox(linux_sandbox, std::move(post_fork_parent_callback));
180   } else {
181     CHECK(!using_layer1_sandbox);
182   }
183 }
184 
ZygoteMain(std::vector<std::unique_ptr<ZygoteForkDelegate>> fork_delegates)185 bool ZygoteMain(
186     std::vector<std::unique_ptr<ZygoteForkDelegate>> fork_delegates) {
187 #if !defined(OS_BSD)
188   sandbox::SetAmZygoteOrRenderer(true, GetSandboxFD());
189 
190   auto* linux_sandbox = service_manager::SandboxLinux::GetInstance();
191 
192   // Skip pre-initializing sandbox when sandbox is disabled for
193   // https://crbug.com/444900.
194   bool using_layer2_sandbox = false;
195   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
196           service_manager::switches::kNoSandbox) &&
197       !base::CommandLine::ForCurrentProcess()->HasSwitch(
198           service_manager::switches::kNoZygoteSandbox)) {
199     // This will pre-initialize the various sandboxes that need it.
200     using_layer2_sandbox = linux_sandbox->PreinitializeSandbox();
201   }
202 
203   const bool using_setuid_sandbox =
204       linux_sandbox->setuid_sandbox_client()->IsSuidSandboxChild();
205   const bool using_namespace_sandbox =
206       sandbox::NamespaceSandbox::InNewUserNamespace();
207   const bool using_layer1_sandbox =
208       using_setuid_sandbox || using_namespace_sandbox;
209 
210   if (using_setuid_sandbox) {
211     linux_sandbox->setuid_sandbox_client()->CloseDummyFile();
212   }
213 
214   if (using_layer1_sandbox) {
215     // Let the ZygoteHost know we're booting up.
216     if (!base::UnixDomainSocket::SendMsg(
217             kZygoteSocketPairFd, kZygoteBootMessage, sizeof(kZygoteBootMessage),
218             std::vector<int>())) {
219       // This is not a CHECK failure because the browser process could either
220       // crash or quickly exit while the zygote is starting. In either case a
221       // zygote crash is not useful. https://crbug.com/692227
222       PLOG(ERROR) << "Failed sending zygote boot message";
223       _exit(1);
224     }
225   }
226 
227   VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size()
228           << " fork delegates";
229   for (const auto& fork_delegate : fork_delegates) {
230     fork_delegate->Init(GetSandboxFD(), using_layer1_sandbox);
231   }
232 
233   // Turn on the first layer of the sandbox if the configuration warrants it.
234   EnterLayerOneSandbox(
235       linux_sandbox, using_layer1_sandbox, using_layer2_sandbox,
236       base::BindOnce(CloseFds, linux_sandbox->GetFileDescriptorsToClose()));
237 
238   const int sandbox_flags = linux_sandbox->GetStatus();
239   const bool setuid_sandbox_engaged =
240       !!(sandbox_flags & service_manager::SandboxLinux::kSUID);
241   CHECK_EQ(using_setuid_sandbox, setuid_sandbox_engaged);
242 
243   const bool namespace_sandbox_engaged =
244       !!(sandbox_flags & service_manager::SandboxLinux::kUserNS);
245   CHECK_EQ(using_namespace_sandbox, namespace_sandbox_engaged);
246 
247   Zygote zygote(sandbox_flags, std::move(fork_delegates),
248                 base::GlobalDescriptors::Descriptor(
249                     static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD()));
250 
251   // This function call can return multiple times, once per fork().
252   return zygote.ProcessRequests();
253 #else
254   return false;
255 #endif
256 }
257 
258 }  // namespace service_manager
259