blob: ddd9764bd6bbf47465306e5b77ee8c4b82c88519 [file] [log] [blame]
Luis Hector Chavez81efb332017-09-18 14:01:29 -07001// Copyright 2016 The Chromium OS 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.
Dylan Reid837c74a2016-01-22 17:25:21 -08004
Dylan Reid837c74a2016-01-22 17:25:21 -08005#include <errno.h>
6#include <fcntl.h>
Dylan Reid837c74a2016-01-22 17:25:21 -08007#include <signal.h>
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07008#include <stdint.h>
Dylan Reid837c74a2016-01-22 17:25:21 -08009#include <stdlib.h>
10#include <string.h>
11#include <sys/mount.h>
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -070012#include <sys/prctl.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080013#include <sys/stat.h>
Yunlian Jiang6b423022018-10-16 14:47:47 -070014#include <sys/sysmacros.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080015#include <sys/types.h>
Dylan Reid2bd9ea92016-04-07 20:57:47 -070016#include <sys/wait.h>
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070017#include <syscall.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080018#include <unistd.h>
19
yusukes32622542018-01-05 18:59:52 -080020#include <algorithm>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070021#include <map>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070022#include <memory>
yusukesbbc37a72017-11-21 09:51:54 -080023#include <ostream>
Stephen Barber771653f2017-10-04 23:48:57 -070024#include <set>
yusukesbbc37a72017-11-21 09:51:54 -080025#include <sstream>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070026#include <string>
yusukes32622542018-01-05 18:59:52 -080027#include <tuple>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070028#include <utility>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070029#include <vector>
30
31#include <base/bind.h>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070032#include <base/callback_helpers.h>
33#include <base/files/file_path.h>
34#include <base/files/file_util.h>
35#include <base/files/scoped_file.h>
Luis Hector Chavez835d39e2017-09-19 15:16:31 -070036#include <base/logging.h>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070037#include <base/macros.h>
38#include <base/strings/string_util.h>
39#include <base/strings/stringprintf.h>
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070040#include <libminijail.h>
Luis Hector Chavez626f5c82017-09-18 11:19:32 -070041#include <scoped_minijail.h>
Mike Frysinger412dbd22017-01-06 01:50:34 -050042
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070043#include "libcontainer/cgroup.h"
Luis Hector Chavez644d2042017-09-19 18:56:44 -070044#include "libcontainer/config.h"
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070045#include "libcontainer/libcontainer.h"
Luis Hector Chavez81efb332017-09-18 14:01:29 -070046#include "libcontainer/libcontainer_util.h"
Yusuke Sato91f11f02016-12-02 16:15:13 -080047
yusukesbbc37a72017-11-21 09:51:54 -080048#define QUOTE(s) ('"' + std::string(s) + '"')
49
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -070050// Not available in sys/prctl.h yet, but supported on some kernels.
51#ifndef PR_SET_CORE_SCHED
52#define PR_SET_CORE_SCHED 0x200
53#endif
54
Luis Hector Chavez5381d002017-09-16 12:54:24 -070055namespace {
56
Luis Hector Chavez81efb332017-09-18 14:01:29 -070057using libcontainer::DeviceMapperDetach;
58using libcontainer::DeviceMapperSetup;
59using libcontainer::GetUsernsOutsideId;
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -070060using libcontainer::Loopdev;
Luis Hector Chavez81efb332017-09-18 14:01:29 -070061using libcontainer::LoopdevDetach;
62using libcontainer::LoopdevSetup;
63using libcontainer::MakeDir;
64using libcontainer::MountExternal;
65using libcontainer::TouchFile;
Mike Frysinger412dbd22017-01-06 01:50:34 -050066
Luis Hector Chavez81efb332017-09-18 14:01:29 -070067constexpr size_t kMaxRlimits = 32; // Linux defines 15 at the time of writing.
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070068
Luis Hector Chavez5381d002017-09-16 12:54:24 -070069struct Mount {
70 std::string name;
71 base::FilePath source;
72 base::FilePath destination;
73 std::string type;
74 std::string data;
75 std::string verity;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070076 int flags;
77 int uid;
78 int gid;
79 int mode;
Luis Hector Chavez5381d002017-09-16 12:54:24 -070080
81 // True if mount should happen in new vfs ns.
82 bool mount_in_ns;
83
84 // True if target should be created if it doesn't exist.
85 bool create;
86
87 // True if target should be mounted via loopback.
88 bool loopback;
Dylan Reid837c74a2016-01-22 17:25:21 -080089};
90
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070091struct Device {
92 // 'c' or 'b' for char or block
93 char type;
94 base::FilePath path;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070095 int fs_permissions;
96 int major;
97 int minor;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070098
Stephen Barber7bae6642017-11-30 10:47:12 -080099 // Copy the major from existing node, ignores |major|.
100 bool copy_major;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700101 // Copy the minor from existing node, ignores |minor|.
102 bool copy_minor;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700103 int uid;
104 int gid;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700105};
106
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700107struct CgroupDevice {
108 bool allow;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700109 char type;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700110
111 // -1 for either major or minor means all.
112 int major;
113 int minor;
114
115 bool read;
116 bool write;
117 bool modify;
Dylan Reid837c74a2016-01-22 17:25:21 -0800118};
119
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700120struct CpuCgroup {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700121 int shares;
122 int quota;
123 int period;
124 int rt_runtime;
125 int rt_period;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800126};
127
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700128struct Rlimit {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700129 int type;
Luis Hector Chavezda352462018-01-30 09:10:00 -0800130 rlim_t cur;
131 rlim_t max;
Dylan Reid93fa4602017-06-06 13:39:31 -0700132};
133
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700134} // namespace
135
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700136// Structure that configures how the container is run.
Dylan Reid837c74a2016-01-22 17:25:21 -0800137struct container_config {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700138 // Path to the root of the container itself.
139 base::FilePath config_root;
140
141 // Path to the root of the container's filesystem.
142 base::FilePath rootfs;
143
144 // Flags that will be passed to mount() for the rootfs.
yusukesb7b9a042017-12-08 13:14:25 -0800145 unsigned long rootfs_mount_flags = 0x0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700146
147 // Path to where the container will be run.
148 base::FilePath premounted_runfs;
149
150 // Path to the file where the pid should be written.
151 base::FilePath pid_file_path;
152
153 // The program to run and args, e.g. "/sbin/init".
154 std::vector<std::string> program_argv;
155
156 // The uid the container will run as.
yusukesb7b9a042017-12-08 13:14:25 -0800157 uid_t uid = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700158
159 // Mapping of UIDs in the container, e.g. "0 100000 1024"
160 std::string uid_map;
161
162 // The gid the container will run as.
yusukesb7b9a042017-12-08 13:14:25 -0800163 gid_t gid = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700164
165 // Mapping of GIDs in the container, e.g. "0 100000 1024"
166 std::string gid_map;
167
Risanfd41aee2018-08-15 14:03:38 +0900168 // The supplementary gids that attached to the container.
169 std::vector<gid_t> additional_gids;
170
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700171 // Syscall table to use or nullptr if none.
172 std::string alt_syscall_table;
173
174 // Filesystems to mount in the new namespace.
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700175 std::vector<Mount> mounts;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700176
Stephen Barber771653f2017-10-04 23:48:57 -0700177 // Namespaces that should be used for the container.
178 std::set<std::string> namespaces;
179
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700180 // Device nodes to create.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700181 std::vector<Device> devices;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700182
183 // Device node cgroup permissions.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700184 std::vector<CgroupDevice> cgroup_devices;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700185
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700186 // CPU cgroup params.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700187 CpuCgroup cpu_cgparams;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700188
189 // Parent dir for cgroup creation
190 base::FilePath cgroup_parent;
191
192 // uid to own the created cgroups
yusukesb7b9a042017-12-08 13:14:25 -0800193 uid_t cgroup_owner = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700194
195 // gid to own the created cgroups
yusukesb7b9a042017-12-08 13:14:25 -0800196 gid_t cgroup_group = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700197
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700198 // Allow the child process to keep open FDs (for stdin/out/err).
yusukesf125f332017-12-08 13:45:15 -0800199 bool keep_fds_open = false;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700200
201 // Array of rlimits for the contained process.
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700202 Rlimit rlimits[kMaxRlimits];
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700203
204 // The number of elements in `rlimits`.
yusukesb7b9a042017-12-08 13:14:25 -0800205 int num_rlimits = 0;
yusukesf125f332017-12-08 13:45:15 -0800206 bool use_capmask = false;
207 bool use_capmask_ambient = false;
yusukesb7b9a042017-12-08 13:14:25 -0800208 uint64_t capmask = 0x0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700209
210 // The mask of securebits to skip when restricting caps.
yusukesb7b9a042017-12-08 13:14:25 -0800211 uint64_t securebits_skip_mask = 0x0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700212
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -0700213 // Core Scheduling policy
214 bool core_sched = false;
215
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700216 // Whether the container needs an extra process to be run as init.
yusukesf125f332017-12-08 13:45:15 -0800217 bool do_init = false;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700218
219 // The SELinux context name the container will run under.
220 std::string selinux_context;
221
222 // A function pointer to be called prior to calling execve(2).
yusukesb7b9a042017-12-08 13:14:25 -0800223 minijail_hook_t pre_start_hook = nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700224
225 // Parameter that will be passed to pre_start_hook().
yusukesb7b9a042017-12-08 13:14:25 -0800226 void* pre_start_hook_payload = nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700227
Luis Hector Chaveze03926a2017-09-28 17:28:49 -0700228 // A list of file descriptors to inherit.
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700229 std::vector<int> inherited_fds;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700230
231 // A list of hooks that will be called upon minijail reaching various states
232 // of execution.
233 std::map<minijail_hook_event_t, std::vector<libcontainer::HookCallback>>
234 hooks;
Dylan Reid837c74a2016-01-22 17:25:21 -0800235};
236
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700237// Container manipulation
238struct container {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700239 std::unique_ptr<libcontainer::Cgroup> cgroup;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700240 ScopedMinijail jail;
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700241 pid_t init_pid = -1;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700242 base::FilePath config_root;
243 base::FilePath runfs;
244 base::FilePath rundir;
245 base::FilePath runfsroot;
246 base::FilePath pid_file_path;
247
248 // Mounts made outside of the minijail.
249 std::vector<base::FilePath> ext_mounts;
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700250 std::vector<Loopdev> loopdevs;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700251 std::vector<std::string> device_mappers;
252 std::string name;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700253
254 std::vector<std::pair<libcontainer::HookState,
255 std::vector<libcontainer::HookCallback>>>
256 hook_states;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700257};
258
259namespace {
260
yusukes4d955472018-01-17 16:41:32 -0800261std::string GetMountFlagsAsString(int flags) {
262#define CHECK_MOUNT_FLAG(flag) \
263 do { \
264 if (flags & flag) \
265 result.push_back(#flag); \
266 } while (false)
267
268 std::vector<std::string> result;
269 CHECK_MOUNT_FLAG(MS_RDONLY);
270 CHECK_MOUNT_FLAG(MS_NOSUID);
271 CHECK_MOUNT_FLAG(MS_NODEV);
272 CHECK_MOUNT_FLAG(MS_NOEXEC);
273 CHECK_MOUNT_FLAG(MS_SYNCHRONOUS);
274 CHECK_MOUNT_FLAG(MS_REMOUNT);
275 CHECK_MOUNT_FLAG(MS_MANDLOCK);
276 CHECK_MOUNT_FLAG(MS_DIRSYNC);
277 CHECK_MOUNT_FLAG(MS_NOATIME);
278 CHECK_MOUNT_FLAG(MS_NODIRATIME);
279 CHECK_MOUNT_FLAG(MS_BIND);
280 CHECK_MOUNT_FLAG(MS_MOVE);
281 CHECK_MOUNT_FLAG(MS_REC);
282 CHECK_MOUNT_FLAG(MS_SILENT);
283 CHECK_MOUNT_FLAG(MS_POSIXACL);
284 CHECK_MOUNT_FLAG(MS_UNBINDABLE);
285 CHECK_MOUNT_FLAG(MS_PRIVATE);
286 CHECK_MOUNT_FLAG(MS_SLAVE);
287 CHECK_MOUNT_FLAG(MS_SHARED);
288 return result.empty() ? "no flags" : base::JoinString(result, " | ");
289
290#undef CHECK_MOUNT_FLAG
291}
292
yusukesbbc37a72017-11-21 09:51:54 -0800293std::ostream& operator<<(std::ostream& stream, const Mount& mount) {
294 stream << "mount:" << std::endl
295 << " name: " << QUOTE(mount.name) << std::endl
296 << " source: " << QUOTE(mount.source.value()) << std::endl
297 << " destination: " << QUOTE(mount.destination.value()) << std::endl
298 << " type: " << QUOTE(mount.type) << std::endl
299 << " data: " << QUOTE(mount.data) << std::endl
300 << " verity: " << QUOTE(mount.verity) << std::endl
yusukes4d955472018-01-17 16:41:32 -0800301 << " flags: 0x" << std::hex << mount.flags << std::dec << " ("
302 << GetMountFlagsAsString(mount.flags) << ")" << std::endl
yusukesbbc37a72017-11-21 09:51:54 -0800303 << " uid: " << mount.uid << std::endl
304 << " gid: " << mount.gid << std::endl
305 << " mode: 0" << std::oct << mount.mode << std::dec << std::endl
306 << " mount_in_ns: " << mount.mount_in_ns << std::endl
307 << " create: " << mount.create << std::endl
308 << " loopback: " << mount.loopback << std::endl;
309
310 return stream;
311}
312
313std::ostream& operator<<(std::ostream& stream, const Device& device) {
314 stream << "device:" << std::endl
315 << " type: " << device.type << std::endl
316 << " path: " << QUOTE(device.path.value()) << std::endl
317 << " fs_permissions: 0" << std::oct << device.fs_permissions
318 << std::dec << std::endl
319 << " major: " << device.major << std::endl
320 << " minor: " << device.minor << std::endl
321 << " copy_minor: " << device.copy_minor << std::endl
322 << " uid: " << device.uid << std::endl
323 << " gid: " << device.gid << std::endl;
324
325 return stream;
326}
327
328std::ostream& operator<<(std::ostream& stream,
329 const CgroupDevice& cgroup_device) {
330 stream << "cgroup_device:" << std::endl
331 << " allow: " << cgroup_device.allow << std::endl
332 << " type: " << cgroup_device.type << std::endl
333 << " major: " << cgroup_device.major << std::endl
334 << " minor: " << cgroup_device.minor << std::endl
335 << " read: " << cgroup_device.read << std::endl
336 << " write: " << cgroup_device.write << std::endl
337 << " modify: " << cgroup_device.modify << std::endl;
338
339 return stream;
340}
341
342std::ostream& operator<<(std::ostream& stream, const CpuCgroup& cpu_cgroup) {
343 stream << "cpu_cgroup:" << std::endl
344 << " shares: " << cpu_cgroup.shares << std::endl
345 << " quota: " << cpu_cgroup.quota << std::endl
346 << " period: " << cpu_cgroup.period << std::endl
347 << " rt_runtime: " << cpu_cgroup.rt_runtime << std::endl
348 << " rt_period: " << cpu_cgroup.rt_period << std::endl;
349
350 return stream;
351}
352
353std::ostream& operator<<(std::ostream& stream, const Rlimit& rlimit) {
354 stream << "rlimit:" << std::endl
355 << " type: " << rlimit.type << std::endl
356 << " cur: " << rlimit.cur << std::endl
357 << " max: " << rlimit.max << std::endl;
358
359 return stream;
360}
361
yusukes32622542018-01-05 18:59:52 -0800362void DumpConfig(std::ostream* stream,
363 const container_config* c,
364 bool sort_vectors) {
365 *stream << "config_root: " << QUOTE(c->config_root.value()) << std::endl
366 << "rootfs: " << QUOTE(c->rootfs.value()) << std::endl
367 << "rootfs_mount_flags: 0x" << std::hex << c->rootfs_mount_flags
yusukes4d955472018-01-17 16:41:32 -0800368 << std::dec << " (" << GetMountFlagsAsString(c->rootfs_mount_flags)
369 << ")" << std::endl
yusukes32622542018-01-05 18:59:52 -0800370 << "premounted_runfs: " << QUOTE(c->premounted_runfs.value())
371 << std::endl
372 << "pid_file_path: " << QUOTE(c->pid_file_path.value()) << std::endl
373 << "program_argv: size=" << c->program_argv.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800374
375 for (const std::string& argv : c->program_argv)
yusukes32622542018-01-05 18:59:52 -0800376 *stream << " " << QUOTE(argv) << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800377
yusukes32622542018-01-05 18:59:52 -0800378 *stream << "uid: " << c->uid << std::endl
379 << "uid_map: " << QUOTE(c->uid_map) << std::endl
380 << "gid: " << c->gid << std::endl
381 << "gid_map: " << QUOTE(c->gid_map) << std::endl
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -0700382 << "alt_syscall_table: " << QUOTE(c->alt_syscall_table) << std::endl
383 << "core_sched:" << (c->core_sched ? "enable" : "disable")
384 << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800385
yusukes32622542018-01-05 18:59:52 -0800386 auto mount_sorted = c->mounts;
387 if (sort_vectors) {
388 std::stable_sort(mount_sorted.begin(), mount_sorted.end(),
389 [](const Mount& lhs, const Mount& rhs) {
390 return std::make_tuple(lhs.destination.value(),
391 lhs.source.value(), lhs.flags) <
392 std::make_tuple(rhs.destination.value(),
393 rhs.source.value(), rhs.flags);
394 });
395 }
396 for (const auto& mount : mount_sorted)
397 *stream << mount;
yusukesbbc37a72017-11-21 09:51:54 -0800398
yusukes32622542018-01-05 18:59:52 -0800399 *stream << "namespaces: size=" << c->namespaces.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800400 for (const std::string& ns : c->namespaces)
yusukes32622542018-01-05 18:59:52 -0800401 *stream << " " << QUOTE(ns) << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800402
yusukes32622542018-01-05 18:59:52 -0800403 auto devices_sorted = c->devices;
404 if (sort_vectors) {
405 std::stable_sort(devices_sorted.begin(), devices_sorted.end(),
406 [](const Device& lhs, const Device& rhs) {
407 return lhs.path.value() < rhs.path.value();
408 });
409 }
410 for (const auto& device : devices_sorted)
411 *stream << device;
yusukesbbc37a72017-11-21 09:51:54 -0800412
yusukes32622542018-01-05 18:59:52 -0800413 auto cgroup_devices_sorted = c->cgroup_devices;
414 if (sort_vectors) {
415 std::stable_sort(cgroup_devices_sorted.begin(), cgroup_devices_sorted.end(),
416 [](const CgroupDevice& lhs, const CgroupDevice& rhs) {
417 return std::make_tuple(lhs.type, lhs.major, lhs.minor) <
418 std::make_tuple(rhs.type, rhs.major, rhs.minor);
419 });
420 }
421 for (const auto& cgroup_device : cgroup_devices_sorted)
422 *stream << cgroup_device;
yusukesbbc37a72017-11-21 09:51:54 -0800423
yusukese67af442017-12-23 00:52:15 -0800424 *stream << c->cpu_cgparams
yusukes32622542018-01-05 18:59:52 -0800425 << "cgroup_parent: " << QUOTE(c->cgroup_parent.value()) << std::endl
426 << "cgroup_owner: " << c->cgroup_owner << std::endl
427 << "cgroup_group: " << c->cgroup_group << std::endl
428 << "keep_fds_open: " << c->keep_fds_open << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800429
yusukes32622542018-01-05 18:59:52 -0800430 *stream << "num_rlimits: " << c->num_rlimits << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800431 for (size_t i = 0; i < c->num_rlimits; ++i)
yusukes32622542018-01-05 18:59:52 -0800432 *stream << c->rlimits[i];
yusukesbbc37a72017-11-21 09:51:54 -0800433
yusukes32622542018-01-05 18:59:52 -0800434 *stream << "use_capmask: " << c->use_capmask << std::endl
435 << "use_capmask_ambient: " << c->use_capmask_ambient << std::endl
436 << "capmask: 0x" << std::hex << c->capmask << std::dec << std::endl
437 << "securebits_skip_mask: 0x" << std::hex << c->securebits_skip_mask
438 << std::dec << std::endl
439 << "do_init: " << c->do_init << std::endl
440 << "selinux_context: " << QUOTE(c->selinux_context) << std::endl
441 << "pre_start_hook: " << reinterpret_cast<void*>(c->pre_start_hook)
442 << std::endl
443 << "pre_start_hook_payload: " << c->pre_start_hook_payload
444 << std::endl
445 << "inherited_fds: size=" << c->inherited_fds.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800446
447 for (int fd : c->inherited_fds)
yusukes32622542018-01-05 18:59:52 -0800448 *stream << " " << fd << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800449
yusukes32622542018-01-05 18:59:52 -0800450 *stream << "hooks: size=" << c->hooks.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800451}
452
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700453// Returns the path for |path_in_container| in the outer namespace.
454base::FilePath GetPathInOuterNamespace(
455 const base::FilePath& root, const base::FilePath& path_in_container) {
456 if (path_in_container.IsAbsolute())
457 return base::FilePath(root.value() + path_in_container.value());
458 return root.Append(path_in_container);
459}
460
461// Make sure the mount target exists in the new rootfs. Create if needed and
462// possible.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700463bool SetupMountDestination(const struct container_config* config,
464 const Mount& mount,
465 const base::FilePath& source,
466 const base::FilePath& dest) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700467 struct stat st_buf;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700468 if (stat(dest.value().c_str(), &st_buf) == 0) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700469 // destination exists.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700470 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700471 }
472
473 // Try to create the destination. Either make directory or touch a file
474 // depending on the source type.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700475 int uid_userns;
476 if (!GetUsernsOutsideId(config->uid_map, mount.uid, &uid_userns))
477 return false;
478 int gid_userns;
479 if (!GetUsernsOutsideId(config->gid_map, mount.gid, &gid_userns))
480 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700481
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700482 if (stat(source.value().c_str(), &st_buf) != 0 || S_ISDIR(st_buf.st_mode) ||
483 S_ISBLK(st_buf.st_mode)) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700484 return MakeDir(dest, uid_userns, gid_userns, mount.mode);
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700485 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700486
487 return TouchFile(dest, uid_userns, gid_userns, mount.mode);
488}
489
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700490// Unmounts anything we mounted in this mount namespace in the opposite order
491// that they were mounted.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700492bool UnmountExternalMounts(struct container* c) {
493 bool ret = true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700494
495 for (auto it = c->ext_mounts.rbegin(); it != c->ext_mounts.rend(); ++it) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700496 if (umount(it->value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700497 PLOG(ERROR) << "Failed to unmount " << it->value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700498 ret = false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700499 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700500 }
501 c->ext_mounts.clear();
502
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700503 for (auto it = c->loopdevs.rbegin(); it != c->loopdevs.rend(); ++it) {
504 if (!LoopdevDetach(&(*it)))
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700505 ret = false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700506 }
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700507 c->loopdevs.clear();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700508
509 for (auto it = c->device_mappers.rbegin(); it != c->device_mappers.rend();
510 ++it) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700511 if (!DeviceMapperDetach(*it))
512 ret = false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700513 }
514 c->device_mappers.clear();
515
516 return ret;
517}
518
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700519bool DoContainerMount(struct container* c,
520 const struct container_config* config,
521 const Mount& mount) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700522 base::FilePath dest =
523 GetPathInOuterNamespace(c->runfsroot, mount.destination);
524
525 // If it's a bind mount relative to rootfs, append source to
526 // rootfs path, otherwise source path is absolute.
527 base::FilePath source;
528 if ((mount.flags & MS_BIND) && !mount.source.IsAbsolute()) {
529 source = GetPathInOuterNamespace(c->runfsroot, mount.source);
530 } else if (mount.loopback && !mount.source.IsAbsolute() &&
531 !c->config_root.empty()) {
532 source = GetPathInOuterNamespace(c->config_root, mount.source);
533 } else {
534 source = mount.source;
535 }
536
537 // Only create the destinations for external mounts, minijail will take
538 // care of those mounted in the new namespace.
539 if (mount.create && !mount.mount_in_ns) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700540 if (!SetupMountDestination(config, mount, source, dest))
541 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700542 }
543 if (mount.loopback) {
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700544 Loopdev loopdev;
545 if (!LoopdevSetup(source, &loopdev))
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700546 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700547
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700548 // Replace the mount source with the loopback device path.
549 source = loopdev.path;
550
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700551 // Save this to cleanup when shutting down.
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700552 c->loopdevs.emplace_back(std::move(loopdev));
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700553 }
554 if (!mount.verity.empty()) {
555 // Set this device up via dm-verity.
556 std::string dm_name;
557 base::FilePath dm_source = source;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700558 if (!DeviceMapperSetup(dm_source, mount.verity, &source, &dm_name))
559 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700560
561 // Save this to cleanup when shutting down.
562 c->device_mappers.push_back(dm_name);
563 }
564 if (mount.mount_in_ns) {
565 // We can mount this with minijail.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700566 if (minijail_mount_with_data(
567 c->jail.get(), source.value().c_str(),
568 mount.destination.value().c_str(), mount.type.c_str(), mount.flags,
569 mount.data.empty() ? nullptr : mount.data.c_str()) != 0) {
570 return false;
571 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700572 } else {
573 // Mount this externally and unmount it on exit.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700574 if (!MountExternal(source.value(), dest.value(), mount.type, mount.flags,
575 mount.data)) {
576 return false;
577 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700578 // Save this to unmount when shutting down.
579 c->ext_mounts.push_back(dest);
580 }
581
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700582 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700583}
584
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700585bool DoContainerMounts(struct container* c,
586 const struct container_config* config) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700587 UnmountExternalMounts(c);
588
589 // This will run in all the error cases.
590 base::ScopedClosureRunner teardown(base::Bind(
591 base::IgnoreResult(&UnmountExternalMounts), base::Unretained(c)));
592
593 for (const auto& mount : config->mounts) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700594 if (!DoContainerMount(c, config, mount))
595 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700596 }
597
598 // The mounts have been done successfully, no need to tear them down anymore.
599 ignore_result(teardown.Release());
600
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700601 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700602}
603
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700604bool ContainerCreateDevice(const struct container* c,
605 const struct container_config* config,
606 const Device& dev,
Stephen Barber7bae6642017-11-30 10:47:12 -0800607 int major,
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700608 int minor) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700609 mode_t mode = dev.fs_permissions;
610 switch (dev.type) {
611 case 'b':
612 mode |= S_IFBLK;
613 break;
614 case 'c':
615 mode |= S_IFCHR;
616 break;
617 default:
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700618 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700619 }
620
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700621 int uid_userns;
622 if (!GetUsernsOutsideId(config->uid_map, dev.uid, &uid_userns))
623 return false;
624 int gid_userns;
625 if (!GetUsernsOutsideId(config->gid_map, dev.gid, &gid_userns))
626 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700627
628 base::FilePath path = GetPathInOuterNamespace(c->runfsroot, dev.path);
Luis Hector Chavez92278e82017-10-16 11:30:27 -0700629 if (!libcontainer::CreateDirectoryOwnedBy(path.DirName(), 0755, uid_userns,
630 gid_userns)) {
Luis Hector Chavez5d51abb2017-10-11 17:05:57 -0700631 PLOG(ERROR) << "Failed to create parent directory for " << path.value();
632 return false;
633 }
Stephen Barber7bae6642017-11-30 10:47:12 -0800634 if (mknod(path.value().c_str(), mode, makedev(major, minor)) != 0 &&
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700635 errno != EEXIST) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700636 PLOG(ERROR) << "Failed to mknod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700637 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700638 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700639 if (chown(path.value().c_str(), uid_userns, gid_userns) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700640 PLOG(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700641 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700642 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700643 if (chmod(path.value().c_str(), dev.fs_permissions) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700644 PLOG(ERROR) << "Failed to chmod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700645 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700646 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700647
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700648 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700649}
650
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700651bool MountRunfs(struct container* c, const struct container_config* config) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700652 {
653 std::string runfs_template = base::StringPrintf(
654 "%s/%s_XXXXXX", c->rundir.value().c_str(), c->name.c_str());
655 // TODO(lhchavez): Replace this with base::CreateTemporaryDirInDir().
656 char* runfs_path = mkdtemp(const_cast<char*>(runfs_template.c_str()));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700657 if (!runfs_path) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700658 PLOG(ERROR) << "Failed to mkdtemp in " << c->rundir.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700659 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700660 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700661 c->runfs = base::FilePath(runfs_path);
662 }
663
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700664 int uid_userns;
665 if (!GetUsernsOutsideId(config->uid_map, config->uid, &uid_userns))
666 return false;
667 int gid_userns;
668 if (!GetUsernsOutsideId(config->gid_map, config->gid, &gid_userns))
669 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700670
671 // Make sure the container uid can access the rootfs.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700672 if (chmod(c->runfs.value().c_str(), 0700) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700673 PLOG(ERROR) << "Failed to chmod " << c->runfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700674 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700675 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700676 if (chown(c->runfs.value().c_str(), uid_userns, gid_userns) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700677 PLOG(ERROR) << "Failed to chown " << c->runfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700678 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700679 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700680
681 c->runfsroot = c->runfs.Append("root");
682
683 constexpr mode_t kRootDirMode = 0660;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700684 if (mkdir(c->runfsroot.value().c_str(), kRootDirMode) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700685 PLOG(ERROR) << "Failed to mkdir " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700686 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700687 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700688 if (chmod(c->runfsroot.value().c_str(), kRootDirMode) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700689 PLOG(ERROR) << "Failed to chmod " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700690 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700691 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700692
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700693 if (mount(config->rootfs.value().c_str(), c->runfsroot.value().c_str(), "",
694 MS_BIND | (config->rootfs_mount_flags & MS_REC), nullptr) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700695 PLOG(ERROR) << "Failed to bind-mount " << config->rootfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700696 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700697 }
698
699 // MS_BIND ignores any flags passed to it (except MS_REC). We need a
700 // second call to mount() to actually set them.
701 if (config->rootfs_mount_flags &&
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700702 mount(config->rootfs.value().c_str(), c->runfsroot.value().c_str(), "",
703 (config->rootfs_mount_flags & ~MS_REC), nullptr) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700704 PLOG(ERROR) << "Failed to remount " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700705 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700706 }
707
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700708 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700709}
710
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700711bool CreateDeviceNodes(struct container* c,
712 const struct container_config* config,
713 pid_t container_pid) {
714 for (const auto& dev : config->devices) {
Stephen Barber7bae6642017-11-30 10:47:12 -0800715 int major = dev.major;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700716 int minor = dev.minor;
717
Stephen Barber7bae6642017-11-30 10:47:12 -0800718 if (dev.copy_major || dev.copy_minor) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700719 struct stat st_buff;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700720 if (stat(dev.path.value().c_str(), &st_buff) != 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700721 continue;
Stephen Barber7bae6642017-11-30 10:47:12 -0800722
723 if (dev.copy_major)
724 major = major(st_buff.st_rdev);
725 if (dev.copy_minor)
726 minor = minor(st_buff.st_rdev);
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700727 }
Stephen Barber7bae6642017-11-30 10:47:12 -0800728 if (major < 0 || minor < 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700729 continue;
Stephen Barber7bae6642017-11-30 10:47:12 -0800730 if (!ContainerCreateDevice(c, config, dev, major, minor))
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700731 return false;
732 }
733
734 return true;
735}
736
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700737bool DeviceSetup(struct container* c, const struct container_config* config) {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700738 c->cgroup->DenyAllDevices();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700739
740 for (const auto& dev : config->cgroup_devices) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700741 if (!c->cgroup->AddDevice(dev.allow, dev.major, dev.minor, dev.read,
742 dev.write, dev.modify, dev.type)) {
743 return false;
744 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700745 }
746
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700747 for (const auto& loopdev : c->loopdevs) {
748 if (!c->cgroup->AddDevice(1, major(loopdev.info.lo_rdevice),
749 minor(loopdev.info.lo_rdevice), 1, 0, 0, 'b')) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700750 return false;
751 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700752 }
753
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700754 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700755}
756
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -0700757int SetCoreSched(void* payload) {
758 int ret = prctl(PR_SET_CORE_SCHED, 1);
759 if (ret != 0 && errno != EINVAL) {
760 // Bubble error, minijail will abort child process.
761 return -errno;
762 }
763 // Success or unsupported on this kernel, continue.
764 return 0;
765}
766
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700767int Setexeccon(void* payload) {
768 char* init_domain = reinterpret_cast<char*>(payload);
769 pid_t tid = syscall(SYS_gettid);
770
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700771 if (tid < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700772 PLOG(ERROR) << "Failed to gettid";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700773 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700774 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700775
776 std::string exec_path =
777 base::StringPrintf("/proc/self/task/%d/attr/exec", tid);
778
779 base::ScopedFD fd(open(exec_path.c_str(), O_WRONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700780 if (!fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700781 PLOG(ERROR) << "Failed to open " << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700782 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700783 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700784
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700785 if (!base::WriteFileDescriptor(fd.get(), init_domain, strlen(init_domain))) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700786 PLOG(ERROR) << "Failed to write the SELinux label to " << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700787 return -errno;
788 }
789
790 return 0;
791}
792
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700793bool ContainerTeardown(struct container* c) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700794 UnmountExternalMounts(c);
795 if (!c->runfsroot.empty() && !c->runfs.empty()) {
796 /* |c->runfsroot| may have been mounted recursively. Thus use
797 * MNT_DETACH to "immediately disconnect the filesystem and all
798 * filesystems mounted below it from each other and from the
799 * mount table". Otherwise one would need to unmount every
800 * single dependent mount before unmounting |c->runfsroot|
801 * itself.
802 */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700803 if (umount2(c->runfsroot.value().c_str(), MNT_DETACH) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700804 PLOG(ERROR) << "Failed to detach " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700805 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700806 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700807 if (rmdir(c->runfsroot.value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700808 PLOG(ERROR) << "Failed to rmdir " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700809 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700810 }
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700811 c->runfsroot = base::FilePath();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700812 }
813 if (!c->pid_file_path.empty()) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700814 if (unlink(c->pid_file_path.value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700815 PLOG(ERROR) << "Failed to unlink " << c->pid_file_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700816 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700817 }
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700818 c->pid_file_path = base::FilePath();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700819 }
820 if (!c->runfs.empty()) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700821 if (rmdir(c->runfs.value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700822 PLOG(ERROR) << "Failed to rmdir " << c->runfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700823 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700824 }
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700825 c->runfs = base::FilePath();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700826 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700827 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700828}
829
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700830void CancelContainerStart(struct container* c) {
831 if (c->init_pid != -1)
832 container_kill(c);
833 ContainerTeardown(c);
834}
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700835
836} // namespace
837
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700838struct container_config* container_config_create() {
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700839 return new (std::nothrow) struct container_config();
Dylan Reid837c74a2016-01-22 17:25:21 -0800840}
841
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700842void container_config_destroy(struct container_config* c) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700843 if (c == nullptr)
844 return;
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700845 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -0800846}
847
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700848int container_config_config_root(struct container_config* c,
849 const char* config_root) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700850 c->config_root = base::FilePath(config_root);
851 return 0;
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500852}
853
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700854const char* container_config_get_config_root(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700855 return c->config_root.value().c_str();
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500856}
857
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700858int container_config_rootfs(struct container_config* c, const char* rootfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700859 c->rootfs = base::FilePath(rootfs);
860 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800861}
862
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700863const char* container_config_get_rootfs(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700864 return c->rootfs.value().c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700865}
866
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700867void container_config_rootfs_mount_flags(struct container_config* c,
868 unsigned long rootfs_mount_flags) {
869 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
870 * simply check against zero later. MS_BIND is also added to avoid
871 * re-mounting the original filesystem, since the rootfs is always
872 * bind-mounted.
873 */
874 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700875}
876
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700877unsigned long container_config_get_rootfs_mount_flags(
878 const struct container_config* c) {
879 return c->rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700880}
881
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700882int container_config_premounted_runfs(struct container_config* c,
883 const char* runfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700884 c->premounted_runfs = base::FilePath(runfs);
885 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700886}
887
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700888const char* container_config_get_premounted_runfs(
889 const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700890 return c->premounted_runfs.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700891}
892
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700893int container_config_pid_file(struct container_config* c, const char* path) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700894 c->pid_file_path = base::FilePath(path);
895 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700896}
897
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700898const char* container_config_get_pid_file(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700899 return c->pid_file_path.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700900}
901
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700902int container_config_program_argv(struct container_config* c,
903 const char** argv,
904 size_t num_args) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700905 if (num_args < 1) {
906 errno = EINVAL;
907 return -1;
908 }
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700909 c->program_argv.clear();
910 c->program_argv.reserve(num_args);
911 for (size_t i = 0; i < num_args; ++i)
912 c->program_argv.emplace_back(argv[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700913 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800914}
915
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700916size_t container_config_get_num_program_args(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700917 return c->program_argv.size();
Dylan Reid11456722016-05-02 11:24:50 -0700918}
919
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700920const char* container_config_get_program_arg(const struct container_config* c,
921 size_t index) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700922 if (index >= c->program_argv.size())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700923 return nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700924 return c->program_argv[index].c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700925}
926
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700927void container_config_uid(struct container_config* c, uid_t uid) {
928 c->uid = uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700929}
930
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700931uid_t container_config_get_uid(const struct container_config* c) {
932 return c->uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700933}
934
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700935int container_config_uid_map(struct container_config* c, const char* uid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700936 c->uid_map = uid_map;
937 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800938}
939
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700940void container_config_gid(struct container_config* c, gid_t gid) {
941 c->gid = gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700942}
943
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700944gid_t container_config_get_gid(const struct container_config* c) {
945 return c->gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700946}
947
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700948int container_config_gid_map(struct container_config* c, const char* gid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700949 c->gid_map = gid_map;
950 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800951}
952
Risanfd41aee2018-08-15 14:03:38 +0900953void container_config_additional_gids(struct container_config* c,
954 const gid_t* gids,
955 size_t num_gids) {
956 c->additional_gids.assign(gids, gids + num_gids);
957}
958
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700959int container_config_alt_syscall_table(struct container_config* c,
960 const char* alt_syscall_table) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700961 c->alt_syscall_table = alt_syscall_table;
962 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800963}
964
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700965int container_config_add_rlimit(struct container_config* c,
966 int type,
Luis Hector Chavezda352462018-01-30 09:10:00 -0800967 rlim_t cur,
968 rlim_t max) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700969 if (c->num_rlimits >= kMaxRlimits) {
970 errno = ENOMEM;
971 return -1;
972 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700973 c->rlimits[c->num_rlimits].type = type;
974 c->rlimits[c->num_rlimits].cur = cur;
975 c->rlimits[c->num_rlimits].max = max;
976 c->num_rlimits++;
977 return 0;
Dylan Reid93fa4602017-06-06 13:39:31 -0700978}
979
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700980int container_config_add_mount(struct container_config* c,
981 const char* name,
982 const char* source,
983 const char* destination,
984 const char* type,
985 const char* data,
986 const char* verity,
987 int flags,
988 int uid,
989 int gid,
990 int mode,
991 int mount_in_ns,
992 int create,
993 int loopback) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700994 if (name == nullptr || source == nullptr || destination == nullptr ||
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700995 type == nullptr) {
996 errno = EINVAL;
997 return -1;
998 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800999
Tom Hughes25f969a2020-08-27 15:57:27 -07001000 c->mounts.emplace_back(
1001 Mount{name, base::FilePath(source), base::FilePath(destination), type,
1002 data ? data : "", verity ? verity : "", flags, uid, gid, mode,
1003 mount_in_ns != 0, create != 0, loopback != 0});
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001004
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001005 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001006}
1007
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001008int container_config_add_cgroup_device(struct container_config* c,
1009 int allow,
1010 char type,
1011 int major,
1012 int minor,
1013 int read,
1014 int write,
1015 int modify) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001016 c->cgroup_devices.emplace_back(CgroupDevice{
1017 allow != 0, type, major, minor, read != 0, write != 0, modify != 0});
Dylan Reid4843d6b2017-03-31 18:14:30 -07001018
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001019 return 0;
Dylan Reid4843d6b2017-03-31 18:14:30 -07001020}
1021
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001022int container_config_add_device(struct container_config* c,
1023 char type,
1024 const char* path,
1025 int fs_permissions,
1026 int major,
1027 int minor,
Stephen Barber7bae6642017-11-30 10:47:12 -08001028 int copy_major,
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001029 int copy_minor,
1030 int uid,
1031 int gid,
1032 int read_allowed,
1033 int write_allowed,
1034 int modify_allowed) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001035 if (path == nullptr) {
1036 errno = EINVAL;
1037 return -1;
1038 }
Stephen Barber7bae6642017-11-30 10:47:12 -08001039 /* If using a dynamic major/minor number, ensure that major/minor is -1. */
1040 if ((copy_major && (major != -1)) || (copy_minor && (minor != -1))) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001041 errno = EINVAL;
1042 return -1;
1043 }
Dylan Reid355d5e42016-04-29 16:53:31 -07001044
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001045 if (read_allowed || write_allowed || modify_allowed) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001046 if (container_config_add_cgroup_device(c, 1, type, major, minor,
1047 read_allowed, write_allowed,
1048 modify_allowed) != 0) {
1049 errno = ENOMEM;
1050 return -1;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001051 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001052 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001053
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001054 c->devices.emplace_back(Device{
Tom Hughes25f969a2020-08-27 15:57:27 -07001055 type,
1056 base::FilePath(path),
1057 fs_permissions,
1058 major,
1059 minor,
1060 copy_major != 0,
1061 copy_minor != 0,
1062 uid,
1063 gid,
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001064 });
1065
1066 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001067}
1068
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -07001069int container_config_set_core_sched(struct container_config* c, int enable) {
1070 c->core_sched = enable;
1071 return 0;
1072}
1073
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001074int container_config_set_cpu_shares(struct container_config* c, int shares) {
1075 /* CPU shares must be 2 or higher. */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001076 if (shares < 2) {
1077 errno = EINVAL;
1078 return -1;
1079 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001080
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001081 c->cpu_cgparams.shares = shares;
1082 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +08001083}
1084
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001085int container_config_set_cpu_cfs_params(struct container_config* c,
1086 int quota,
1087 int period) {
1088 /*
1089 * quota could be set higher than period to utilize more than one CPU.
1090 * quota could also be set as -1 to indicate the cgroup does not adhere
1091 * to any CPU time restrictions.
1092 */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001093 if (quota <= 0 && quota != -1) {
1094 errno = EINVAL;
1095 return -1;
1096 }
1097 if (period <= 0) {
1098 errno = EINVAL;
1099 return -1;
1100 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001101
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001102 c->cpu_cgparams.quota = quota;
1103 c->cpu_cgparams.period = period;
1104 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +08001105}
1106
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001107int container_config_set_cpu_rt_params(struct container_config* c,
1108 int rt_runtime,
1109 int rt_period) {
1110 /*
1111 * rt_runtime could be set as 0 to prevent the cgroup from using
1112 * realtime CPU.
1113 */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001114 if (rt_runtime < 0 || rt_runtime >= rt_period) {
1115 errno = EINVAL;
1116 return -1;
1117 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001118
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001119 c->cpu_cgparams.rt_runtime = rt_runtime;
1120 c->cpu_cgparams.rt_period = rt_period;
1121 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +08001122}
1123
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001124int container_config_get_cpu_shares(struct container_config* c) {
1125 return c->cpu_cgparams.shares;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001126}
1127
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001128int container_config_get_cpu_quota(struct container_config* c) {
1129 return c->cpu_cgparams.quota;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001130}
1131
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001132int container_config_get_cpu_period(struct container_config* c) {
1133 return c->cpu_cgparams.period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001134}
1135
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001136int container_config_get_cpu_rt_runtime(struct container_config* c) {
1137 return c->cpu_cgparams.rt_runtime;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001138}
1139
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001140int container_config_get_cpu_rt_period(struct container_config* c) {
1141 return c->cpu_cgparams.rt_period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001142}
1143
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001144int container_config_set_cgroup_parent(struct container_config* c,
1145 const char* parent,
1146 uid_t cgroup_owner,
1147 gid_t cgroup_group) {
1148 c->cgroup_owner = cgroup_owner;
1149 c->cgroup_group = cgroup_group;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001150 c->cgroup_parent = base::FilePath(parent);
1151 return 0;
Dylan Reid9e724af2016-07-21 09:58:07 -07001152}
1153
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001154const char* container_config_get_cgroup_parent(struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001155 return c->cgroup_parent.value().c_str();
Dylan Reid9e724af2016-07-21 09:58:07 -07001156}
1157
Stephen Barber771653f2017-10-04 23:48:57 -07001158int container_config_namespaces(struct container_config* c,
1159 const char** namespaces,
1160 size_t num_ns) {
1161 if (num_ns < 1)
1162 return -EINVAL;
1163 c->namespaces.clear();
1164 for (size_t i = 0; i < num_ns; ++i)
1165 c->namespaces.emplace(namespaces[i]);
1166 return 0;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001167}
1168
Stephen Barber771653f2017-10-04 23:48:57 -07001169size_t container_config_get_num_namespaces(const struct container_config* c) {
1170 return c->namespaces.size();
1171}
1172
1173bool container_config_has_namespace(const struct container_config* c,
1174 const char* ns) {
1175 return c->namespaces.find(ns) != c->namespaces.end();
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001176}
1177
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001178void container_config_keep_fds_open(struct container_config* c) {
yusukesf125f332017-12-08 13:45:15 -08001179 c->keep_fds_open = true;
Dylan Reidc4335842016-11-11 10:24:52 -08001180}
1181
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001182void container_config_set_capmask(struct container_config* c,
1183 uint64_t capmask,
1184 int ambient) {
yusukesf125f332017-12-08 13:45:15 -08001185 c->use_capmask = true;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001186 c->capmask = capmask;
1187 c->use_capmask_ambient = ambient;
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001188}
1189
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001190void container_config_set_securebits_skip_mask(struct container_config* c,
1191 uint64_t securebits_skip_mask) {
1192 c->securebits_skip_mask = securebits_skip_mask;
Luis Hector Chavezcd44ba72017-06-30 13:01:38 -07001193}
1194
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001195void container_config_set_run_as_init(struct container_config* c,
1196 int run_as_init) {
1197 c->do_init = !run_as_init;
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001198}
1199
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001200int container_config_set_selinux_context(struct container_config* c,
1201 const char* context) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001202 if (!context) {
1203 errno = EINVAL;
1204 return -1;
1205 }
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001206 c->selinux_context = context;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001207 return 0;
Luis Hector Chavez15e8e672017-07-20 15:13:27 -07001208}
1209
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001210void container_config_set_pre_execve_hook(struct container_config* c,
1211 int (*hook)(void*),
1212 void* payload) {
1213 c->pre_start_hook = hook;
1214 c->pre_start_hook_payload = payload;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001215}
1216
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001217void container_config_add_hook(struct container_config* c,
1218 minijail_hook_event_t event,
1219 libcontainer::HookCallback callback) {
1220 auto it = c->hooks.insert(
1221 std::make_pair(event, std::vector<libcontainer::HookCallback>()));
1222 it.first->second.emplace_back(std::move(callback));
1223}
1224
Luis Hector Chaveze03926a2017-09-28 17:28:49 -07001225int container_config_add_hook(struct container_config* c,
1226 minijail_hook_event_t event,
1227 const char* filename,
1228 const char** argv,
1229 size_t num_args,
1230 int* pstdin_fd,
1231 int* pstdout_fd,
1232 int* pstderr_fd) {
1233 std::vector<std::string> args;
1234 args.reserve(num_args);
1235 for (size_t i = 0; i < num_args; ++i)
1236 args.emplace_back(argv[i]);
1237
1238 // First element of the array belongs to the parent and the second one belongs
1239 // to the child.
1240 base::ScopedFD stdin_fds[2], stdout_fds[2], stderr_fds[2];
1241 if (pstdin_fd) {
1242 if (!libcontainer::Pipe2(&stdin_fds[1], &stdin_fds[0], 0))
1243 return -1;
1244 }
1245 if (pstdout_fd) {
1246 if (!libcontainer::Pipe2(&stdout_fds[0], &stdout_fds[0], 0))
1247 return -1;
1248 }
1249 if (pstderr_fd) {
1250 if (!libcontainer::Pipe2(&stderr_fds[0], &stderr_fds[0], 0))
1251 return -1;
1252 }
1253
1254 // After this point the call has been successful, so we can now commit to
1255 // whatever pipes we have opened.
1256 if (pstdin_fd) {
1257 *pstdin_fd = stdin_fds[0].release();
1258 c->inherited_fds.emplace_back(stdin_fds[1].get());
1259 }
1260 if (pstdout_fd) {
1261 *pstdout_fd = stdout_fds[0].release();
1262 c->inherited_fds.emplace_back(stdout_fds[1].get());
1263 }
1264 if (pstderr_fd) {
1265 *pstderr_fd = stderr_fds[0].release();
1266 c->inherited_fds.emplace_back(stderr_fds[1].get());
1267 }
1268 container_config_add_hook(
1269 c, event,
1270 libcontainer::CreateExecveCallback(
1271 base::FilePath(filename), args, std::move(stdin_fds[1]),
1272 std::move(stdout_fds[1]), std::move(stderr_fds[1])));
1273 return 0;
1274}
1275
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001276int container_config_inherit_fds(struct container_config* c,
Luis Hector Chaveza5e87cb2018-05-21 07:21:22 -07001277 const int* inherited_fds,
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001278 size_t inherited_fd_count) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001279 if (!c->inherited_fds.empty()) {
1280 errno = EINVAL;
1281 return -1;
1282 }
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001283 for (size_t i = 0; i < inherited_fd_count; ++i)
1284 c->inherited_fds.emplace_back(inherited_fds[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001285 return 0;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001286}
1287
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001288struct container* container_new(const char* name, const char* rundir) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001289 struct container* c = new (std::nothrow) container();
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001290 if (!c)
1291 return nullptr;
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001292 c->rundir = base::FilePath(rundir);
1293 c->name = name;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001294 return c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001295}
1296
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001297void container_destroy(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001298 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001299}
1300
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001301int container_start(struct container* c,
1302 const struct container_config* config) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001303 if (!c) {
1304 errno = EINVAL;
1305 return -1;
1306 }
1307 if (!config) {
1308 errno = EINVAL;
1309 return -1;
1310 }
1311 if (config->program_argv.empty()) {
1312 errno = EINVAL;
1313 return -1;
1314 }
Dylan Reide040c6b2016-05-02 18:49:02 -07001315
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001316 // This will run in all the error cases.
1317 base::ScopedClosureRunner teardown(
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -07001318 base::Bind(&CancelContainerStart, base::Unretained(c)));
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001319
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001320 if (!config->config_root.empty())
1321 c->config_root = config->config_root;
1322 if (!config->premounted_runfs.empty()) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001323 c->runfs.clear();
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001324 c->runfsroot = config->premounted_runfs;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001325 } else {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001326 if (!MountRunfs(c, config))
1327 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001328 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001329
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001330 c->jail.reset(minijail_new());
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001331 if (!c->jail) {
1332 errno = ENOMEM;
1333 return -1;
1334 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001335
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001336 if (!DoContainerMounts(c, config))
1337 return -1;
Dylan Reid837c74a2016-01-22 17:25:21 -08001338
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001339 int cgroup_uid;
1340 if (!GetUsernsOutsideId(config->uid_map, config->cgroup_owner, &cgroup_uid))
1341 return -1;
1342 int cgroup_gid;
1343 if (!GetUsernsOutsideId(config->gid_map, config->cgroup_group, &cgroup_gid))
1344 return -1;
Stephen Barber1a398c72017-01-23 12:39:44 -08001345
Tom Hughes25f969a2020-08-27 15:57:27 -07001346 c->cgroup = libcontainer::Cgroup::Create(
1347 c->name, base::FilePath("/sys/fs/cgroup"), config->cgroup_parent,
1348 cgroup_uid, cgroup_gid);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001349 if (!c->cgroup)
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001350 return -1;
Dylan Reida9966422016-07-21 10:11:34 -07001351
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001352 // Must be root to modify device cgroup or mknod.
1353 std::map<minijail_hook_event_t, std::vector<libcontainer::HookCallback>>
1354 hook_callbacks;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001355 if (getuid() == 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001356 if (!config->devices.empty()) {
1357 // Create the devices in the mount namespace.
1358 auto it = hook_callbacks.insert(
1359 std::make_pair(MINIJAIL_HOOK_EVENT_PRE_CHROOT,
1360 std::vector<libcontainer::HookCallback>()));
1361 it.first->second.emplace_back(
1362 libcontainer::AdaptCallbackToRunInNamespaces(
1363 base::Bind(&CreateDeviceNodes, base::Unretained(c),
1364 base::Unretained(config)),
1365 {CLONE_NEWNS}));
1366 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001367 if (!DeviceSetup(c, config))
1368 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001369 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001370
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001371 /* Setup CPU cgroup params. */
1372 if (config->cpu_cgparams.shares) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001373 if (!c->cgroup->SetCpuShares(config->cpu_cgparams.shares))
1374 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001375 }
1376 if (config->cpu_cgparams.period) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001377 if (!c->cgroup->SetCpuQuota(config->cpu_cgparams.quota))
1378 return -1;
1379 if (!c->cgroup->SetCpuPeriod(config->cpu_cgparams.period))
1380 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001381 }
1382 if (config->cpu_cgparams.rt_period) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001383 if (!c->cgroup->SetCpuRtRuntime(config->cpu_cgparams.rt_runtime))
1384 return -1;
1385 if (!c->cgroup->SetCpuRtPeriod(config->cpu_cgparams.rt_period))
1386 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001387 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001388
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001389 /* Setup and start the container with libminijail. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001390 if (!config->pid_file_path.empty())
1391 c->pid_file_path = config->pid_file_path;
1392 else if (!c->runfs.empty())
1393 c->pid_file_path = c->runfs.Append("container.pid");
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001394
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001395 if (!c->pid_file_path.empty())
1396 minijail_write_pid_file(c->jail.get(), c->pid_file_path.value().c_str());
Chris Morin404a2692019-06-14 17:46:56 -07001397 minijail_forward_signals(c->jail.get());
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001398 minijail_reset_signal_mask(c->jail.get());
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -07001399 minijail_reset_signal_handlers(c->jail.get());
Dylan Reid837c74a2016-01-22 17:25:21 -08001400
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001401 /* Setup container namespaces. */
Stephen Barber771653f2017-10-04 23:48:57 -07001402 if (container_config_has_namespace(config, "ipc"))
1403 minijail_namespace_ipc(c->jail.get());
1404 if (container_config_has_namespace(config, "mount"))
1405 minijail_namespace_vfs(c->jail.get());
1406 if (container_config_has_namespace(config, "network"))
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001407 minijail_namespace_net(c->jail.get());
Stephen Barber771653f2017-10-04 23:48:57 -07001408 if (container_config_has_namespace(config, "pid"))
1409 minijail_namespace_pids(c->jail.get());
1410
1411 if (container_config_has_namespace(config, "user")) {
1412 minijail_namespace_user(c->jail.get());
1413 if (minijail_uidmap(c->jail.get(), config->uid_map.c_str()) != 0)
1414 return -1;
1415 if (minijail_gidmap(c->jail.get(), config->gid_map.c_str()) != 0)
1416 return -1;
1417 }
1418
1419 if (container_config_has_namespace(config, "cgroup"))
1420 minijail_namespace_cgroups(c->jail.get());
1421
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001422 if (getuid() != 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001423 minijail_namespace_user_disable_setgroups(c->jail.get());
Dylan Reid837c74a2016-01-22 17:25:21 -08001424
Risanfd41aee2018-08-15 14:03:38 +09001425 // Set the UID/GID inside the container if not 0.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001426 if (!GetUsernsOutsideId(config->uid_map, config->uid, nullptr))
1427 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001428 else if (config->uid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001429 minijail_change_uid(c->jail.get(), config->uid);
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001430 if (!GetUsernsOutsideId(config->gid_map, config->gid, nullptr))
1431 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001432 else if (config->gid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001433 minijail_change_gid(c->jail.get(), config->gid);
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001434
Risanfd41aee2018-08-15 14:03:38 +09001435 // Set the supplementary GIDs inside the container, if specified.
1436 if (!config->additional_gids.empty()) {
1437 for (const gid_t additional_gid : config->additional_gids) {
1438 if (!GetUsernsOutsideId(config->gid_map, additional_gid, nullptr))
1439 return -1;
1440 }
1441 minijail_set_supplementary_gids(c->jail.get(),
1442 config->additional_gids.size(),
1443 config->additional_gids.data());
1444 }
1445
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001446 if (minijail_enter_pivot_root(c->jail.get(), c->runfsroot.value().c_str()) !=
1447 0) {
1448 return -1;
1449 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001450
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001451 // Add the cgroups configured above.
1452 for (int32_t i = 0; i < libcontainer::Cgroup::Type::NUM_TYPES; i++) {
1453 if (c->cgroup->has_tasks_path(i)) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001454 if (minijail_add_to_cgroup(
1455 c->jail.get(), c->cgroup->tasks_path(i).value().c_str()) != 0) {
1456 return -1;
1457 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001458 }
1459 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001460
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001461 if (!config->alt_syscall_table.empty())
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001462 minijail_use_alt_syscall(c->jail.get(), config->alt_syscall_table.c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -08001463
Ereth McKnight-MacNeild0f1f742020-07-02 00:13:22 -07001464 if (config->core_sched) {
1465 if (minijail_add_hook(c->jail.get(), &SetCoreSched, nullptr,
1466 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS) != 0) {
1467 return -1;
1468 }
1469 }
1470
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001471 for (int i = 0; i < config->num_rlimits; i++) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001472 const Rlimit& lim = config->rlimits[i];
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001473 if (minijail_rlimit(c->jail.get(), lim.type, lim.cur, lim.max) != 0)
1474 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001475 }
Dylan Reid93fa4602017-06-06 13:39:31 -07001476
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001477 if (!config->selinux_context.empty()) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001478 if (minijail_add_hook(c->jail.get(), &Setexeccon,
1479 const_cast<char*>(config->selinux_context.c_str()),
1480 MINIJAIL_HOOK_EVENT_PRE_EXECVE) != 0) {
1481 return -1;
1482 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001483 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001484
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001485 if (config->pre_start_hook) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001486 if (minijail_add_hook(c->jail.get(), config->pre_start_hook,
1487 config->pre_start_hook_payload,
1488 MINIJAIL_HOOK_EVENT_PRE_EXECVE) != 0) {
1489 return -1;
1490 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001491 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001492
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001493 // Now that all pre-requisite hooks are installed, copy the ones in the
1494 // container_config object in the correct order.
1495 for (const auto& config_hook : config->hooks) {
1496 auto it = hook_callbacks.insert(std::make_pair(
1497 config_hook.first, std::vector<libcontainer::HookCallback>()));
1498 it.first->second.insert(it.first->second.end(), config_hook.second.begin(),
1499 config_hook.second.end());
1500 }
1501
1502 c->hook_states.clear();
1503 // Reserve enough memory to hold all the hooks, so that their addresses do not
1504 // get invalidated by reallocation.
1505 c->hook_states.reserve(MINIJAIL_HOOK_EVENT_MAX);
Tom Hughes25f969a2020-08-27 15:57:27 -07001506 for (minijail_hook_event_t event :
1507 {MINIJAIL_HOOK_EVENT_PRE_CHROOT, MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS,
1508 MINIJAIL_HOOK_EVENT_PRE_EXECVE}) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001509 const auto& it = hook_callbacks.find(event);
1510 if (it == hook_callbacks.end())
1511 continue;
1512 c->hook_states.emplace_back(
1513 std::make_pair(libcontainer::HookState(), it->second));
1514 if (!c->hook_states.back().first.InstallHook(c->jail.get(), event))
1515 return -1;
1516 }
1517
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001518 for (int fd : config->inherited_fds) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001519 if (minijail_preserve_fd(c->jail.get(), fd, fd) != 0)
1520 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001521 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001522
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001523 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001524 minijail_skip_remount_private(c->jail.get());
Dylan Reid3da683b2016-04-05 03:35:35 -07001525
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001526 if (!config->keep_fds_open)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001527 minijail_close_open_fds(c->jail.get());
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001528
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001529 if (config->use_capmask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001530 minijail_use_caps(c->jail.get(), config->capmask);
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001531 if (config->use_capmask_ambient)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001532 minijail_set_ambient_caps(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001533 if (config->securebits_skip_mask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001534 minijail_skip_setting_securebits(c->jail.get(),
1535 config->securebits_skip_mask);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001536 }
1537 }
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001538
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001539 if (!config->do_init)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001540 minijail_run_as_init(c->jail.get());
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001541
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001542 std::vector<char*> argv_cstr;
1543 argv_cstr.reserve(config->program_argv.size() + 1);
1544 for (const auto& arg : config->program_argv)
1545 argv_cstr.emplace_back(const_cast<char*>(arg.c_str()));
1546 argv_cstr.emplace_back(nullptr);
1547
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001548 if (minijail_run_pid_pipes_no_preload(c->jail.get(), argv_cstr[0],
1549 argv_cstr.data(), &c->init_pid, nullptr,
1550 nullptr, nullptr) != 0) {
1551 return -1;
1552 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001553
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001554 // |hook_states| is already sorted in the correct order.
1555 for (auto& hook_state : c->hook_states) {
1556 if (!hook_state.first.WaitForHookAndRun(hook_state.second, c->init_pid))
1557 return -1;
1558 }
1559
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001560 // The container has started successfully, no need to tear it down anymore.
1561 ignore_result(teardown.Release());
1562 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001563}
1564
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001565const char* container_root(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001566 return c->runfs.value().c_str();
Dylan Reid837c74a2016-01-22 17:25:21 -08001567}
1568
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001569int container_pid(struct container* c) {
1570 return c->init_pid;
Dylan Reid837c74a2016-01-22 17:25:21 -08001571}
1572
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001573int container_wait(struct container* c) {
1574 int rc;
Dylan Reidcf745c52016-04-22 10:18:03 -07001575
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001576 do {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001577 rc = minijail_wait(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001578 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001579
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001580 // If the process had already been reaped, still perform teardown.
1581 if (rc == -ECHILD || rc >= 0) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001582 if (!ContainerTeardown(c))
1583 rc = -errno;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001584 }
1585 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001586}
1587
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001588int container_kill(struct container* c) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001589 if (kill(c->init_pid, SIGKILL) != 0 && errno != ESRCH) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -07001590 PLOG(ERROR) << "Failed to kill " << c->init_pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001591 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -07001592 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001593 return container_wait(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001594}
yusukesbbc37a72017-11-21 09:51:54 -08001595
yusukes32622542018-01-05 18:59:52 -08001596char* container_config_dump(struct container_config* c, int sort_vectors) {
yusukesbbc37a72017-11-21 09:51:54 -08001597 std::stringstream out;
yusukes32622542018-01-05 18:59:52 -08001598 DumpConfig(&out, c, sort_vectors);
yusukesbbc37a72017-11-21 09:51:54 -08001599 return strdup(out.str().c_str());
1600}