blob: 4e4007dbd4a9fa165c9dbc3ce6250f8e9caa9d0f [file] [log] [blame]
Ben Chan6f391cb2012-03-21 17:38:21 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ben Chanf68ea492011-08-23 10:11:08 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Chan5ccd9fe2013-11-13 18:28:27 -08005#include "cros-disks/sandboxed_process.h"
Ben Chanf68ea492011-08-23 10:11:08 -07006
François Degros54abc1d2020-02-05 18:43:21 +11007#include <utility>
8
Sergei Datsenko495f5da2019-06-06 17:44:23 +10009#include <stdlib.h>
10
Anand K Mistry956a5502019-03-06 17:12:59 +110011#include <sys/mount.h>
Sergei Datsenkocd676b72019-05-10 11:42:05 +100012#include <sys/wait.h>
Sergei Datsenko495f5da2019-06-06 17:44:23 +100013#include <unistd.h>
Anand K Mistry956a5502019-03-06 17:12:59 +110014
Sergei Datsenko495f5da2019-06-06 17:44:23 +100015#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090016#include <base/check.h>
Sergei Datsenko495f5da2019-06-06 17:44:23 +100017#include <base/files/file_util.h>
18#include <base/files/scoped_file.h>
Ben Chanf68ea492011-08-23 10:11:08 -070019#include <base/logging.h>
Qijiang Fan886c4692021-02-19 11:54:10 +090020#include <base/notreached.h>
François Degros2ca49ef2019-10-02 15:02:36 +100021#include <base/posix/safe_strerror.h>
Ben Chanf68ea492011-08-23 10:11:08 -070022#include <chromeos/libminijail.h>
23
Anand K Mistry956a5502019-03-06 17:12:59 +110024#include "cros-disks/mount_options.h"
François Degros5593b8c2019-07-25 12:27:42 +100025#include "cros-disks/quote.h"
Sergei Datsenko495f5da2019-06-06 17:44:23 +100026#include "cros-disks/sandboxed_init.h"
Anand K Mistry956a5502019-03-06 17:12:59 +110027
Ben Chanf68ea492011-08-23 10:11:08 -070028namespace cros_disks {
Sergei Datsenko495f5da2019-06-06 17:44:23 +100029namespace {
30
François Degrosee318212020-07-14 14:11:42 +100031int Exec(char* const args[], char* const env[]) {
François Degros5593b8c2019-07-25 12:27:42 +100032 const char* const path = args[0];
François Degrosee318212020-07-14 14:11:42 +100033 execve(path, args, env);
François Degrosa97ad492019-10-04 12:12:12 +100034 const int ret =
35 (errno == ENOENT ? MINIJAIL_ERR_NO_COMMAND : MINIJAIL_ERR_NO_ACCESS);
36 PLOG(ERROR) << "Cannot exec " << quote(path);
37 return ret;
Sergei Datsenko495f5da2019-06-06 17:44:23 +100038}
39
40} // namespace
41
Ben Chande0e3f62017-09-26 06:28:39 -070042SandboxedProcess::SandboxedProcess() : jail_(minijail_new()) {
Ben Chanf68ea492011-08-23 10:11:08 -070043 CHECK(jail_) << "Failed to create a process jail";
44}
45
46SandboxedProcess::~SandboxedProcess() {
47 minijail_destroy(jail_);
48}
49
Ben Chan213c6d92019-04-10 16:21:52 -070050void SandboxedProcess::LoadSeccompFilterPolicy(const std::string& policy_file) {
Ben Chan98f8ae02011-10-04 16:34:34 -070051 minijail_parse_seccomp_filters(jail_, policy_file.c_str());
52 minijail_use_seccomp_filter(jail_);
53}
54
Ben Chan0dd41882017-05-24 00:46:10 -070055void SandboxedProcess::NewCgroupNamespace() {
56 minijail_namespace_cgroups(jail_);
57}
58
59void SandboxedProcess::NewIpcNamespace() {
60 minijail_namespace_ipc(jail_);
61}
62
Ben Chan44125df2017-05-22 11:29:11 -070063void SandboxedProcess::NewMountNamespace() {
64 minijail_namespace_vfs(jail_);
65}
66
Jorge Lucangeli Obes0a388a22020-04-06 11:43:21 -040067void SandboxedProcess::EnterExistingMountNamespace(const std::string& ns_path) {
68 minijail_namespace_enter_vfs(jail_, ns_path.c_str());
69}
70
Sergei Datsenko495f5da2019-06-06 17:44:23 +100071void SandboxedProcess::NewPidNamespace() {
72 minijail_namespace_pids(jail_);
73 minijail_run_as_init(jail_);
Sergei Datsenko1c8f2152019-06-19 15:21:21 +100074 minijail_reset_signal_mask(jail_);
75 minijail_reset_signal_handlers(jail_);
Sergei Datsenko495f5da2019-06-06 17:44:23 +100076 run_custom_init_ = true;
77}
78
Sergei Datsenko1cf9f3d2019-01-02 14:39:48 +110079bool SandboxedProcess::SetUpMinimalMounts() {
80 if (minijail_bind(jail_, "/", "/", 0))
81 return false;
82 if (minijail_bind(jail_, "/proc", "/proc", 0))
83 return false;
84 minijail_remount_proc_readonly(jail_);
Sergei Datsenkod3d5c4c2021-02-03 14:45:59 +110085 minijail_mount_tmp_size(jail_, 128 * 1024 * 1024);
Anand K Mistry238aae12019-01-22 15:02:46 +110086
87 // Create a minimal /dev with a very restricted set of device nodes.
88 minijail_mount_dev(jail_);
Sergei Datsenko82e70912019-10-23 10:51:08 +110089 if (minijail_bind(jail_, "/dev/log", "/dev/log", 0))
90 return false;
Sergei Datsenko1cf9f3d2019-01-02 14:39:48 +110091 return true;
92}
93
94bool SandboxedProcess::BindMount(const std::string& from,
95 const std::string& to,
Anand K Mistry956a5502019-03-06 17:12:59 +110096 bool writeable,
97 bool recursive) {
Sergei Datsenko3928f782020-12-31 09:14:04 +110098 int flags = MS_BIND;
Anand K Mistry956a5502019-03-06 17:12:59 +110099 if (!writeable) {
100 flags |= MS_RDONLY;
101 }
102 if (recursive) {
103 flags |= MS_REC;
104 }
105 return minijail_mount(jail_, from.c_str(), to.c_str(), "", flags) == 0;
Sergei Datsenko1cf9f3d2019-01-02 14:39:48 +1100106}
107
108bool SandboxedProcess::Mount(const std::string& src,
109 const std::string& to,
110 const std::string& type,
111 const char* data) {
112 return minijail_mount_with_data(jail_, src.c_str(), to.c_str(), type.c_str(),
113 0, data) == 0;
114}
115
116bool SandboxedProcess::EnterPivotRoot() {
Allen Webb2b6e35d2019-02-21 10:06:31 -0800117 return minijail_enter_pivot_root(jail_, "/mnt/empty") == 0;
Sergei Datsenko1cf9f3d2019-01-02 14:39:48 +1100118}
119
Ben Chan0dd41882017-05-24 00:46:10 -0700120void SandboxedProcess::NewNetworkNamespace() {
121 minijail_namespace_net(jail_);
122}
123
Ben Chan44125df2017-05-22 11:29:11 -0700124void SandboxedProcess::SkipRemountPrivate() {
125 minijail_skip_remount_private(jail_);
126}
127
Ben Chan0dd41882017-05-24 00:46:10 -0700128void SandboxedProcess::SetNoNewPrivileges() {
129 minijail_no_new_privs(jail_);
130}
131
Ben Chanf68ea492011-08-23 10:11:08 -0700132void SandboxedProcess::SetCapabilities(uint64_t capabilities) {
133 minijail_use_caps(jail_, capabilities);
134}
135
136void SandboxedProcess::SetGroupId(gid_t group_id) {
137 minijail_change_gid(jail_, group_id);
138}
139
140void SandboxedProcess::SetUserId(uid_t user_id) {
141 minijail_change_uid(jail_, user_id);
142}
143
François Degros54abc1d2020-02-05 18:43:21 +1100144void SandboxedProcess::SetSupplementaryGroupIds(base::span<const gid_t> gids) {
145 minijail_set_supplementary_gids(jail_, gids.size(), gids.data());
146}
147
Derek Basehore1709caf2020-07-17 17:06:38 -0700148bool SandboxedProcess::AddToCgroup(const std::string& cgroup) {
149 return minijail_add_to_cgroup(jail_, cgroup.c_str()) == 0;
150}
151
Austin Tankiang93185022019-05-20 14:13:20 +1000152void SandboxedProcess::CloseOpenFds() {
153 minijail_close_open_fds(jail_);
154}
155
156bool SandboxedProcess::PreserveFile(const base::File& file) {
157 return minijail_preserve_fd(jail_, file.GetPlatformFile(),
158 file.GetPlatformFile()) == 0;
159}
160
François Degros1ef69942019-10-01 15:31:17 +1000161pid_t SandboxedProcess::StartImpl(base::ScopedFD in_fd,
162 base::ScopedFD out_fd,
163 base::ScopedFD err_fd) {
François Degros5593b8c2019-07-25 12:27:42 +1000164 char* const* const args = GetArguments();
165 DCHECK(args && args[0]);
François Degrosee318212020-07-14 14:11:42 +1000166 char* const* const env = GetEnvironment();
167 DCHECK(env);
François Degros87d8a122019-09-20 14:50:08 +1000168
Ben Chanacac3952012-04-24 22:50:01 -0700169 pid_t child_pid = kInvalidProcessId;
François Degros1ef69942019-10-01 15:31:17 +1000170
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000171 if (!run_custom_init_) {
François Degros1ef69942019-10-01 15:31:17 +1000172 minijail_preserve_fd(jail_, in_fd.get(), STDIN_FILENO);
173 minijail_preserve_fd(jail_, out_fd.get(), STDOUT_FILENO);
174 minijail_preserve_fd(jail_, err_fd.get(), STDERR_FILENO);
175
François Degrosee318212020-07-14 14:11:42 +1000176 const int ret = minijail_run_env_pid_pipes(
177 jail_, args[0], args, env, &child_pid, nullptr, nullptr, nullptr);
François Degros87d8a122019-09-20 14:50:08 +1000178 if (ret < 0) {
François Degrosee318212020-07-14 14:11:42 +1000179 LOG(ERROR) << "Cannot start minijail process: "
François Degros87d8a122019-09-20 14:50:08 +1000180 << base::safe_strerror(-ret);
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000181 return kInvalidProcessId;
182 }
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000183 } else {
François Degros1ef69942019-10-01 15:31:17 +1000184 SandboxedInit init(std::move(in_fd), std::move(out_fd), std::move(err_fd),
185 SubprocessPipe::Open(SubprocessPipe::kChildToParent,
186 &custom_init_control_fd_));
François Degros87d8a122019-09-20 14:50:08 +1000187
188 // Create child process.
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000189 child_pid = minijail_fork(jail_);
François Degros87d8a122019-09-20 14:50:08 +1000190 if (child_pid < 0) {
191 LOG(ERROR) << "Cannot run minijail_fork: "
192 << base::safe_strerror(-child_pid);
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000193 return kInvalidProcessId;
194 }
François Degros87d8a122019-09-20 14:50:08 +1000195
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000196 if (child_pid == 0) {
François Degros87d8a122019-09-20 14:50:08 +1000197 // In child process.
François Degrosee318212020-07-14 14:11:42 +1000198 init.RunInsideSandboxNoReturn(base::BindOnce(Exec, args, env));
François Degros87d8a122019-09-20 14:50:08 +1000199 NOTREACHED();
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000200 } else {
François Degros87d8a122019-09-20 14:50:08 +1000201 // In parent process.
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000202 CHECK(base::SetNonBlocking(custom_init_control_fd_.get()));
203 }
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000204 }
François Degros87d8a122019-09-20 14:50:08 +1000205
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000206 return child_pid;
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000207}
208
209int SandboxedProcess::WaitImpl() {
François Degros2ca49ef2019-10-02 15:02:36 +1000210 while (true) {
211 const int status = minijail_wait(jail_);
212 if (status >= 0) {
213 return status;
214 }
215
216 const int err = -status;
217 if (err != EINTR) {
218 LOG(ERROR) << "Cannot wait for process " << pid() << ": "
219 << base::safe_strerror(err);
220 return MINIJAIL_ERR_INIT;
221 }
222 }
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000223}
224
François Degros92bbea42019-09-13 10:42:52 +1000225int SandboxedProcess::WaitNonBlockingImpl() {
François Degros02c5c712019-10-03 13:00:11 +1000226 int exit_code;
François Degros92bbea42019-09-13 10:42:52 +1000227
228 if (run_custom_init_ &&
François Degros02c5c712019-10-03 13:00:11 +1000229 SandboxedInit::PollLauncherStatus(&custom_init_control_fd_, &exit_code)) {
230 return exit_code;
Sergei Datsenko495f5da2019-06-06 17:44:23 +1000231 }
232
François Degros92bbea42019-09-13 10:42:52 +1000233 // TODO(chromium:971667) Use Minijail's non-blocking wait once it exists.
François Degros02c5c712019-10-03 13:00:11 +1000234 int wstatus;
François Degros92bbea42019-09-13 10:42:52 +1000235 const pid_t child_pid = pid();
236 const int ret = waitpid(child_pid, &wstatus, WNOHANG);
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000237 if (ret < 0) {
François Degros92bbea42019-09-13 10:42:52 +1000238 PLOG(ERROR) << "Cannot wait for process " << child_pid;
239 return MINIJAIL_ERR_INIT;
Ben Chanacac3952012-04-24 22:50:01 -0700240 }
241
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000242 if (ret == 0) {
François Degros92bbea42019-09-13 10:42:52 +1000243 // Process is still running.
244 return -1;
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000245 }
Ben Chanf68ea492011-08-23 10:11:08 -0700246
François Degros92bbea42019-09-13 10:42:52 +1000247 return SandboxedInit::WStatusToStatus(wstatus);
Ben Chanf68ea492011-08-23 10:11:08 -0700248}
249
Sergei Datsenkof5553d12020-11-25 07:51:59 +1100250int FakeSandboxedProcess::OnProcessLaunch(
251 const std::vector<std::string>& argv) {
252 return 0;
253}
254
255pid_t FakeSandboxedProcess::StartImpl(base::ScopedFD,
256 base::ScopedFD,
257 base::ScopedFD) {
258 DCHECK(!ret_code_);
259 ret_code_ = OnProcessLaunch(arguments());
260 return 42;
261}
262
263int FakeSandboxedProcess::WaitImpl() {
264 DCHECK(ret_code_);
265 return ret_code_.value();
266}
267
268int FakeSandboxedProcess::WaitNonBlockingImpl() {
269 if (ret_code_)
270 return ret_code_.value();
271 return -1;
272}
273
Ben Chanf68ea492011-08-23 10:11:08 -0700274} // namespace cros_disks