blob: e5de9888078b21ec890f01a193c00134020552e6 [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>
12#include <sys/stat.h>
Yunlian Jiang6b423022018-10-16 14:47:47 -070013#include <sys/sysmacros.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080014#include <sys/types.h>
Dylan Reid2bd9ea92016-04-07 20:57:47 -070015#include <sys/wait.h>
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070016#include <syscall.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080017#include <unistd.h>
18
yusukes32622542018-01-05 18:59:52 -080019#include <algorithm>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070020#include <map>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070021#include <memory>
yusukesbbc37a72017-11-21 09:51:54 -080022#include <ostream>
Stephen Barber771653f2017-10-04 23:48:57 -070023#include <set>
yusukesbbc37a72017-11-21 09:51:54 -080024#include <sstream>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070025#include <string>
yusukes32622542018-01-05 18:59:52 -080026#include <tuple>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070027#include <utility>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070028#include <vector>
29
30#include <base/bind.h>
31#include <base/bind_helpers.h>
32#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
Luis Hector Chavez5381d002017-09-16 12:54:24 -070050namespace {
51
Luis Hector Chavez81efb332017-09-18 14:01:29 -070052using libcontainer::DeviceMapperDetach;
53using libcontainer::DeviceMapperSetup;
54using libcontainer::GetUsernsOutsideId;
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -070055using libcontainer::Loopdev;
Luis Hector Chavez81efb332017-09-18 14:01:29 -070056using libcontainer::LoopdevDetach;
57using libcontainer::LoopdevSetup;
58using libcontainer::MakeDir;
59using libcontainer::MountExternal;
60using libcontainer::TouchFile;
Mike Frysinger412dbd22017-01-06 01:50:34 -050061
Luis Hector Chavez81efb332017-09-18 14:01:29 -070062constexpr size_t kMaxRlimits = 32; // Linux defines 15 at the time of writing.
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070063
Luis Hector Chavez5381d002017-09-16 12:54:24 -070064struct Mount {
65 std::string name;
66 base::FilePath source;
67 base::FilePath destination;
68 std::string type;
69 std::string data;
70 std::string verity;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070071 int flags;
72 int uid;
73 int gid;
74 int mode;
Luis Hector Chavez5381d002017-09-16 12:54:24 -070075
76 // True if mount should happen in new vfs ns.
77 bool mount_in_ns;
78
79 // True if target should be created if it doesn't exist.
80 bool create;
81
82 // True if target should be mounted via loopback.
83 bool loopback;
Dylan Reid837c74a2016-01-22 17:25:21 -080084};
85
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070086struct Device {
87 // 'c' or 'b' for char or block
88 char type;
89 base::FilePath path;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070090 int fs_permissions;
91 int major;
92 int minor;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070093
Stephen Barber7bae6642017-11-30 10:47:12 -080094 // Copy the major from existing node, ignores |major|.
95 bool copy_major;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070096 // Copy the minor from existing node, ignores |minor|.
97 bool copy_minor;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070098 int uid;
99 int gid;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700100};
101
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700102struct CgroupDevice {
103 bool allow;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700104 char type;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700105
106 // -1 for either major or minor means all.
107 int major;
108 int minor;
109
110 bool read;
111 bool write;
112 bool modify;
Dylan Reid837c74a2016-01-22 17:25:21 -0800113};
114
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700115struct CpuCgroup {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700116 int shares;
117 int quota;
118 int period;
119 int rt_runtime;
120 int rt_period;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800121};
122
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700123struct Rlimit {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700124 int type;
Luis Hector Chavezda352462018-01-30 09:10:00 -0800125 rlim_t cur;
126 rlim_t max;
Dylan Reid93fa4602017-06-06 13:39:31 -0700127};
128
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700129} // namespace
130
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700131// Structure that configures how the container is run.
Dylan Reid837c74a2016-01-22 17:25:21 -0800132struct container_config {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700133 // Path to the root of the container itself.
134 base::FilePath config_root;
135
136 // Path to the root of the container's filesystem.
137 base::FilePath rootfs;
138
139 // Flags that will be passed to mount() for the rootfs.
yusukesb7b9a042017-12-08 13:14:25 -0800140 unsigned long rootfs_mount_flags = 0x0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700141
142 // Path to where the container will be run.
143 base::FilePath premounted_runfs;
144
145 // Path to the file where the pid should be written.
146 base::FilePath pid_file_path;
147
148 // The program to run and args, e.g. "/sbin/init".
149 std::vector<std::string> program_argv;
150
151 // The uid the container will run as.
yusukesb7b9a042017-12-08 13:14:25 -0800152 uid_t uid = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700153
154 // Mapping of UIDs in the container, e.g. "0 100000 1024"
155 std::string uid_map;
156
157 // The gid the container will run as.
yusukesb7b9a042017-12-08 13:14:25 -0800158 gid_t gid = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700159
160 // Mapping of GIDs in the container, e.g. "0 100000 1024"
161 std::string gid_map;
162
Risanfd41aee2018-08-15 14:03:38 +0900163 // The supplementary gids that attached to the container.
164 std::vector<gid_t> additional_gids;
165
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700166 // Syscall table to use or nullptr if none.
167 std::string alt_syscall_table;
168
169 // Filesystems to mount in the new namespace.
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700170 std::vector<Mount> mounts;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700171
Stephen Barber771653f2017-10-04 23:48:57 -0700172 // Namespaces that should be used for the container.
173 std::set<std::string> namespaces;
174
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700175 // Device nodes to create.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700176 std::vector<Device> devices;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700177
178 // Device node cgroup permissions.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700179 std::vector<CgroupDevice> cgroup_devices;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700180
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700181 // CPU cgroup params.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700182 CpuCgroup cpu_cgparams;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700183
184 // Parent dir for cgroup creation
185 base::FilePath cgroup_parent;
186
187 // uid to own the created cgroups
yusukesb7b9a042017-12-08 13:14:25 -0800188 uid_t cgroup_owner = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700189
190 // gid to own the created cgroups
yusukesb7b9a042017-12-08 13:14:25 -0800191 gid_t cgroup_group = 0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700192
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700193 // Allow the child process to keep open FDs (for stdin/out/err).
yusukesf125f332017-12-08 13:45:15 -0800194 bool keep_fds_open = false;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700195
196 // Array of rlimits for the contained process.
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700197 Rlimit rlimits[kMaxRlimits];
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700198
199 // The number of elements in `rlimits`.
yusukesb7b9a042017-12-08 13:14:25 -0800200 int num_rlimits = 0;
yusukesf125f332017-12-08 13:45:15 -0800201 bool use_capmask = false;
202 bool use_capmask_ambient = false;
yusukesb7b9a042017-12-08 13:14:25 -0800203 uint64_t capmask = 0x0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700204
205 // The mask of securebits to skip when restricting caps.
yusukesb7b9a042017-12-08 13:14:25 -0800206 uint64_t securebits_skip_mask = 0x0;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700207
208 // Whether the container needs an extra process to be run as init.
yusukesf125f332017-12-08 13:45:15 -0800209 bool do_init = false;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700210
211 // The SELinux context name the container will run under.
212 std::string selinux_context;
213
214 // A function pointer to be called prior to calling execve(2).
yusukesb7b9a042017-12-08 13:14:25 -0800215 minijail_hook_t pre_start_hook = nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700216
217 // Parameter that will be passed to pre_start_hook().
yusukesb7b9a042017-12-08 13:14:25 -0800218 void* pre_start_hook_payload = nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700219
Luis Hector Chaveze03926a2017-09-28 17:28:49 -0700220 // A list of file descriptors to inherit.
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700221 std::vector<int> inherited_fds;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700222
223 // A list of hooks that will be called upon minijail reaching various states
224 // of execution.
225 std::map<minijail_hook_event_t, std::vector<libcontainer::HookCallback>>
226 hooks;
Dylan Reid837c74a2016-01-22 17:25:21 -0800227};
228
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700229// Container manipulation
230struct container {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700231 std::unique_ptr<libcontainer::Cgroup> cgroup;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700232 ScopedMinijail jail;
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700233 pid_t init_pid = -1;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700234 base::FilePath config_root;
235 base::FilePath runfs;
236 base::FilePath rundir;
237 base::FilePath runfsroot;
238 base::FilePath pid_file_path;
239
240 // Mounts made outside of the minijail.
241 std::vector<base::FilePath> ext_mounts;
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700242 std::vector<Loopdev> loopdevs;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700243 std::vector<std::string> device_mappers;
244 std::string name;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700245
246 std::vector<std::pair<libcontainer::HookState,
247 std::vector<libcontainer::HookCallback>>>
248 hook_states;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700249};
250
251namespace {
252
yusukes4d955472018-01-17 16:41:32 -0800253std::string GetMountFlagsAsString(int flags) {
254#define CHECK_MOUNT_FLAG(flag) \
255 do { \
256 if (flags & flag) \
257 result.push_back(#flag); \
258 } while (false)
259
260 std::vector<std::string> result;
261 CHECK_MOUNT_FLAG(MS_RDONLY);
262 CHECK_MOUNT_FLAG(MS_NOSUID);
263 CHECK_MOUNT_FLAG(MS_NODEV);
264 CHECK_MOUNT_FLAG(MS_NOEXEC);
265 CHECK_MOUNT_FLAG(MS_SYNCHRONOUS);
266 CHECK_MOUNT_FLAG(MS_REMOUNT);
267 CHECK_MOUNT_FLAG(MS_MANDLOCK);
268 CHECK_MOUNT_FLAG(MS_DIRSYNC);
269 CHECK_MOUNT_FLAG(MS_NOATIME);
270 CHECK_MOUNT_FLAG(MS_NODIRATIME);
271 CHECK_MOUNT_FLAG(MS_BIND);
272 CHECK_MOUNT_FLAG(MS_MOVE);
273 CHECK_MOUNT_FLAG(MS_REC);
274 CHECK_MOUNT_FLAG(MS_SILENT);
275 CHECK_MOUNT_FLAG(MS_POSIXACL);
276 CHECK_MOUNT_FLAG(MS_UNBINDABLE);
277 CHECK_MOUNT_FLAG(MS_PRIVATE);
278 CHECK_MOUNT_FLAG(MS_SLAVE);
279 CHECK_MOUNT_FLAG(MS_SHARED);
280 return result.empty() ? "no flags" : base::JoinString(result, " | ");
281
282#undef CHECK_MOUNT_FLAG
283}
284
yusukesbbc37a72017-11-21 09:51:54 -0800285std::ostream& operator<<(std::ostream& stream, const Mount& mount) {
286 stream << "mount:" << std::endl
287 << " name: " << QUOTE(mount.name) << std::endl
288 << " source: " << QUOTE(mount.source.value()) << std::endl
289 << " destination: " << QUOTE(mount.destination.value()) << std::endl
290 << " type: " << QUOTE(mount.type) << std::endl
291 << " data: " << QUOTE(mount.data) << std::endl
292 << " verity: " << QUOTE(mount.verity) << std::endl
yusukes4d955472018-01-17 16:41:32 -0800293 << " flags: 0x" << std::hex << mount.flags << std::dec << " ("
294 << GetMountFlagsAsString(mount.flags) << ")" << std::endl
yusukesbbc37a72017-11-21 09:51:54 -0800295 << " uid: " << mount.uid << std::endl
296 << " gid: " << mount.gid << std::endl
297 << " mode: 0" << std::oct << mount.mode << std::dec << std::endl
298 << " mount_in_ns: " << mount.mount_in_ns << std::endl
299 << " create: " << mount.create << std::endl
300 << " loopback: " << mount.loopback << std::endl;
301
302 return stream;
303}
304
305std::ostream& operator<<(std::ostream& stream, const Device& device) {
306 stream << "device:" << std::endl
307 << " type: " << device.type << std::endl
308 << " path: " << QUOTE(device.path.value()) << std::endl
309 << " fs_permissions: 0" << std::oct << device.fs_permissions
310 << std::dec << std::endl
311 << " major: " << device.major << std::endl
312 << " minor: " << device.minor << std::endl
313 << " copy_minor: " << device.copy_minor << std::endl
314 << " uid: " << device.uid << std::endl
315 << " gid: " << device.gid << std::endl;
316
317 return stream;
318}
319
320std::ostream& operator<<(std::ostream& stream,
321 const CgroupDevice& cgroup_device) {
322 stream << "cgroup_device:" << std::endl
323 << " allow: " << cgroup_device.allow << std::endl
324 << " type: " << cgroup_device.type << std::endl
325 << " major: " << cgroup_device.major << std::endl
326 << " minor: " << cgroup_device.minor << std::endl
327 << " read: " << cgroup_device.read << std::endl
328 << " write: " << cgroup_device.write << std::endl
329 << " modify: " << cgroup_device.modify << std::endl;
330
331 return stream;
332}
333
334std::ostream& operator<<(std::ostream& stream, const CpuCgroup& cpu_cgroup) {
335 stream << "cpu_cgroup:" << std::endl
336 << " shares: " << cpu_cgroup.shares << std::endl
337 << " quota: " << cpu_cgroup.quota << std::endl
338 << " period: " << cpu_cgroup.period << std::endl
339 << " rt_runtime: " << cpu_cgroup.rt_runtime << std::endl
340 << " rt_period: " << cpu_cgroup.rt_period << std::endl;
341
342 return stream;
343}
344
345std::ostream& operator<<(std::ostream& stream, const Rlimit& rlimit) {
346 stream << "rlimit:" << std::endl
347 << " type: " << rlimit.type << std::endl
348 << " cur: " << rlimit.cur << std::endl
349 << " max: " << rlimit.max << std::endl;
350
351 return stream;
352}
353
yusukes32622542018-01-05 18:59:52 -0800354void DumpConfig(std::ostream* stream,
355 const container_config* c,
356 bool sort_vectors) {
357 *stream << "config_root: " << QUOTE(c->config_root.value()) << std::endl
358 << "rootfs: " << QUOTE(c->rootfs.value()) << std::endl
359 << "rootfs_mount_flags: 0x" << std::hex << c->rootfs_mount_flags
yusukes4d955472018-01-17 16:41:32 -0800360 << std::dec << " (" << GetMountFlagsAsString(c->rootfs_mount_flags)
361 << ")" << std::endl
yusukes32622542018-01-05 18:59:52 -0800362 << "premounted_runfs: " << QUOTE(c->premounted_runfs.value())
363 << std::endl
364 << "pid_file_path: " << QUOTE(c->pid_file_path.value()) << std::endl
365 << "program_argv: size=" << c->program_argv.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800366
367 for (const std::string& argv : c->program_argv)
yusukes32622542018-01-05 18:59:52 -0800368 *stream << " " << QUOTE(argv) << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800369
yusukes32622542018-01-05 18:59:52 -0800370 *stream << "uid: " << c->uid << std::endl
371 << "uid_map: " << QUOTE(c->uid_map) << std::endl
372 << "gid: " << c->gid << std::endl
373 << "gid_map: " << QUOTE(c->gid_map) << std::endl
374 << "alt_syscall_table: " << QUOTE(c->alt_syscall_table) << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800375
yusukes32622542018-01-05 18:59:52 -0800376 auto mount_sorted = c->mounts;
377 if (sort_vectors) {
378 std::stable_sort(mount_sorted.begin(), mount_sorted.end(),
379 [](const Mount& lhs, const Mount& rhs) {
380 return std::make_tuple(lhs.destination.value(),
381 lhs.source.value(), lhs.flags) <
382 std::make_tuple(rhs.destination.value(),
383 rhs.source.value(), rhs.flags);
384 });
385 }
386 for (const auto& mount : mount_sorted)
387 *stream << mount;
yusukesbbc37a72017-11-21 09:51:54 -0800388
yusukes32622542018-01-05 18:59:52 -0800389 *stream << "namespaces: size=" << c->namespaces.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800390 for (const std::string& ns : c->namespaces)
yusukes32622542018-01-05 18:59:52 -0800391 *stream << " " << QUOTE(ns) << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800392
yusukes32622542018-01-05 18:59:52 -0800393 auto devices_sorted = c->devices;
394 if (sort_vectors) {
395 std::stable_sort(devices_sorted.begin(), devices_sorted.end(),
396 [](const Device& lhs, const Device& rhs) {
397 return lhs.path.value() < rhs.path.value();
398 });
399 }
400 for (const auto& device : devices_sorted)
401 *stream << device;
yusukesbbc37a72017-11-21 09:51:54 -0800402
yusukes32622542018-01-05 18:59:52 -0800403 auto cgroup_devices_sorted = c->cgroup_devices;
404 if (sort_vectors) {
405 std::stable_sort(cgroup_devices_sorted.begin(), cgroup_devices_sorted.end(),
406 [](const CgroupDevice& lhs, const CgroupDevice& rhs) {
407 return std::make_tuple(lhs.type, lhs.major, lhs.minor) <
408 std::make_tuple(rhs.type, rhs.major, rhs.minor);
409 });
410 }
411 for (const auto& cgroup_device : cgroup_devices_sorted)
412 *stream << cgroup_device;
yusukesbbc37a72017-11-21 09:51:54 -0800413
yusukese67af442017-12-23 00:52:15 -0800414 *stream << c->cpu_cgparams
yusukes32622542018-01-05 18:59:52 -0800415 << "cgroup_parent: " << QUOTE(c->cgroup_parent.value()) << std::endl
416 << "cgroup_owner: " << c->cgroup_owner << std::endl
417 << "cgroup_group: " << c->cgroup_group << std::endl
418 << "keep_fds_open: " << c->keep_fds_open << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800419
yusukes32622542018-01-05 18:59:52 -0800420 *stream << "num_rlimits: " << c->num_rlimits << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800421 for (size_t i = 0; i < c->num_rlimits; ++i)
yusukes32622542018-01-05 18:59:52 -0800422 *stream << c->rlimits[i];
yusukesbbc37a72017-11-21 09:51:54 -0800423
yusukes32622542018-01-05 18:59:52 -0800424 *stream << "use_capmask: " << c->use_capmask << std::endl
425 << "use_capmask_ambient: " << c->use_capmask_ambient << std::endl
426 << "capmask: 0x" << std::hex << c->capmask << std::dec << std::endl
427 << "securebits_skip_mask: 0x" << std::hex << c->securebits_skip_mask
428 << std::dec << std::endl
429 << "do_init: " << c->do_init << std::endl
430 << "selinux_context: " << QUOTE(c->selinux_context) << std::endl
431 << "pre_start_hook: " << reinterpret_cast<void*>(c->pre_start_hook)
432 << std::endl
433 << "pre_start_hook_payload: " << c->pre_start_hook_payload
434 << std::endl
435 << "inherited_fds: size=" << c->inherited_fds.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800436
437 for (int fd : c->inherited_fds)
yusukes32622542018-01-05 18:59:52 -0800438 *stream << " " << fd << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800439
yusukes32622542018-01-05 18:59:52 -0800440 *stream << "hooks: size=" << c->hooks.size() << std::endl;
yusukesbbc37a72017-11-21 09:51:54 -0800441}
442
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700443// Returns the path for |path_in_container| in the outer namespace.
444base::FilePath GetPathInOuterNamespace(
445 const base::FilePath& root, const base::FilePath& path_in_container) {
446 if (path_in_container.IsAbsolute())
447 return base::FilePath(root.value() + path_in_container.value());
448 return root.Append(path_in_container);
449}
450
451// Make sure the mount target exists in the new rootfs. Create if needed and
452// possible.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700453bool SetupMountDestination(const struct container_config* config,
454 const Mount& mount,
455 const base::FilePath& source,
456 const base::FilePath& dest) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700457 struct stat st_buf;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700458 if (stat(dest.value().c_str(), &st_buf) == 0) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700459 // destination exists.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700460 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700461 }
462
463 // Try to create the destination. Either make directory or touch a file
464 // depending on the source type.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700465 int uid_userns;
466 if (!GetUsernsOutsideId(config->uid_map, mount.uid, &uid_userns))
467 return false;
468 int gid_userns;
469 if (!GetUsernsOutsideId(config->gid_map, mount.gid, &gid_userns))
470 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700471
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700472 if (stat(source.value().c_str(), &st_buf) != 0 || S_ISDIR(st_buf.st_mode) ||
473 S_ISBLK(st_buf.st_mode)) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700474 return MakeDir(dest, uid_userns, gid_userns, mount.mode);
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700475 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700476
477 return TouchFile(dest, uid_userns, gid_userns, mount.mode);
478}
479
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700480// Unmounts anything we mounted in this mount namespace in the opposite order
481// that they were mounted.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700482bool UnmountExternalMounts(struct container* c) {
483 bool ret = true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700484
485 for (auto it = c->ext_mounts.rbegin(); it != c->ext_mounts.rend(); ++it) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700486 if (umount(it->value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700487 PLOG(ERROR) << "Failed to unmount " << it->value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700488 ret = false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700489 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700490 }
491 c->ext_mounts.clear();
492
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700493 for (auto it = c->loopdevs.rbegin(); it != c->loopdevs.rend(); ++it) {
494 if (!LoopdevDetach(&(*it)))
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700495 ret = false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700496 }
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700497 c->loopdevs.clear();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700498
499 for (auto it = c->device_mappers.rbegin(); it != c->device_mappers.rend();
500 ++it) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700501 if (!DeviceMapperDetach(*it))
502 ret = false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700503 }
504 c->device_mappers.clear();
505
506 return ret;
507}
508
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700509bool DoContainerMount(struct container* c,
510 const struct container_config* config,
511 const Mount& mount) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700512 base::FilePath dest =
513 GetPathInOuterNamespace(c->runfsroot, mount.destination);
514
515 // If it's a bind mount relative to rootfs, append source to
516 // rootfs path, otherwise source path is absolute.
517 base::FilePath source;
518 if ((mount.flags & MS_BIND) && !mount.source.IsAbsolute()) {
519 source = GetPathInOuterNamespace(c->runfsroot, mount.source);
520 } else if (mount.loopback && !mount.source.IsAbsolute() &&
521 !c->config_root.empty()) {
522 source = GetPathInOuterNamespace(c->config_root, mount.source);
523 } else {
524 source = mount.source;
525 }
526
527 // Only create the destinations for external mounts, minijail will take
528 // care of those mounted in the new namespace.
529 if (mount.create && !mount.mount_in_ns) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700530 if (!SetupMountDestination(config, mount, source, dest))
531 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700532 }
533 if (mount.loopback) {
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700534 Loopdev loopdev;
535 if (!LoopdevSetup(source, &loopdev))
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700536 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700537
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700538 // Replace the mount source with the loopback device path.
539 source = loopdev.path;
540
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700541 // Save this to cleanup when shutting down.
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700542 c->loopdevs.emplace_back(std::move(loopdev));
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700543 }
544 if (!mount.verity.empty()) {
545 // Set this device up via dm-verity.
546 std::string dm_name;
547 base::FilePath dm_source = source;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700548 if (!DeviceMapperSetup(dm_source, mount.verity, &source, &dm_name))
549 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700550
551 // Save this to cleanup when shutting down.
552 c->device_mappers.push_back(dm_name);
553 }
554 if (mount.mount_in_ns) {
555 // We can mount this with minijail.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700556 if (minijail_mount_with_data(
557 c->jail.get(), source.value().c_str(),
558 mount.destination.value().c_str(), mount.type.c_str(), mount.flags,
559 mount.data.empty() ? nullptr : mount.data.c_str()) != 0) {
560 return false;
561 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700562 } else {
563 // Mount this externally and unmount it on exit.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700564 if (!MountExternal(source.value(), dest.value(), mount.type, mount.flags,
565 mount.data)) {
566 return false;
567 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700568 // Save this to unmount when shutting down.
569 c->ext_mounts.push_back(dest);
570 }
571
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700572 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700573}
574
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700575bool DoContainerMounts(struct container* c,
576 const struct container_config* config) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700577 UnmountExternalMounts(c);
578
579 // This will run in all the error cases.
580 base::ScopedClosureRunner teardown(base::Bind(
581 base::IgnoreResult(&UnmountExternalMounts), base::Unretained(c)));
582
583 for (const auto& mount : config->mounts) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700584 if (!DoContainerMount(c, config, mount))
585 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700586 }
587
588 // The mounts have been done successfully, no need to tear them down anymore.
589 ignore_result(teardown.Release());
590
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700591 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700592}
593
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700594bool ContainerCreateDevice(const struct container* c,
595 const struct container_config* config,
596 const Device& dev,
Stephen Barber7bae6642017-11-30 10:47:12 -0800597 int major,
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700598 int minor) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700599 mode_t mode = dev.fs_permissions;
600 switch (dev.type) {
601 case 'b':
602 mode |= S_IFBLK;
603 break;
604 case 'c':
605 mode |= S_IFCHR;
606 break;
607 default:
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700608 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700609 }
610
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700611 int uid_userns;
612 if (!GetUsernsOutsideId(config->uid_map, dev.uid, &uid_userns))
613 return false;
614 int gid_userns;
615 if (!GetUsernsOutsideId(config->gid_map, dev.gid, &gid_userns))
616 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700617
618 base::FilePath path = GetPathInOuterNamespace(c->runfsroot, dev.path);
Luis Hector Chavez92278e82017-10-16 11:30:27 -0700619 if (!libcontainer::CreateDirectoryOwnedBy(path.DirName(), 0755, uid_userns,
620 gid_userns)) {
Luis Hector Chavez5d51abb2017-10-11 17:05:57 -0700621 PLOG(ERROR) << "Failed to create parent directory for " << path.value();
622 return false;
623 }
Stephen Barber7bae6642017-11-30 10:47:12 -0800624 if (mknod(path.value().c_str(), mode, makedev(major, minor)) != 0 &&
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700625 errno != EEXIST) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700626 PLOG(ERROR) << "Failed to mknod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700627 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700628 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700629 if (chown(path.value().c_str(), uid_userns, gid_userns) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700630 PLOG(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700631 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700632 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700633 if (chmod(path.value().c_str(), dev.fs_permissions) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700634 PLOG(ERROR) << "Failed to chmod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700635 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700636 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700637
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700638 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700639}
640
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700641bool MountRunfs(struct container* c, const struct container_config* config) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700642 {
643 std::string runfs_template = base::StringPrintf(
644 "%s/%s_XXXXXX", c->rundir.value().c_str(), c->name.c_str());
645 // TODO(lhchavez): Replace this with base::CreateTemporaryDirInDir().
646 char* runfs_path = mkdtemp(const_cast<char*>(runfs_template.c_str()));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700647 if (!runfs_path) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700648 PLOG(ERROR) << "Failed to mkdtemp in " << c->rundir.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700649 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700650 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700651 c->runfs = base::FilePath(runfs_path);
652 }
653
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700654 int uid_userns;
655 if (!GetUsernsOutsideId(config->uid_map, config->uid, &uid_userns))
656 return false;
657 int gid_userns;
658 if (!GetUsernsOutsideId(config->gid_map, config->gid, &gid_userns))
659 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700660
661 // Make sure the container uid can access the rootfs.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700662 if (chmod(c->runfs.value().c_str(), 0700) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700663 PLOG(ERROR) << "Failed to chmod " << c->runfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700664 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700665 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700666 if (chown(c->runfs.value().c_str(), uid_userns, gid_userns) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700667 PLOG(ERROR) << "Failed to chown " << c->runfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700668 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700669 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700670
671 c->runfsroot = c->runfs.Append("root");
672
673 constexpr mode_t kRootDirMode = 0660;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700674 if (mkdir(c->runfsroot.value().c_str(), kRootDirMode) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700675 PLOG(ERROR) << "Failed to mkdir " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700676 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700677 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700678 if (chmod(c->runfsroot.value().c_str(), kRootDirMode) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700679 PLOG(ERROR) << "Failed to chmod " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700680 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700681 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700682
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700683 if (mount(config->rootfs.value().c_str(), c->runfsroot.value().c_str(), "",
684 MS_BIND | (config->rootfs_mount_flags & MS_REC), nullptr) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700685 PLOG(ERROR) << "Failed to bind-mount " << config->rootfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700686 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700687 }
688
689 // MS_BIND ignores any flags passed to it (except MS_REC). We need a
690 // second call to mount() to actually set them.
691 if (config->rootfs_mount_flags &&
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700692 mount(config->rootfs.value().c_str(), c->runfsroot.value().c_str(), "",
693 (config->rootfs_mount_flags & ~MS_REC), nullptr) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700694 PLOG(ERROR) << "Failed to remount " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700695 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700696 }
697
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700698 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700699}
700
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700701bool CreateDeviceNodes(struct container* c,
702 const struct container_config* config,
703 pid_t container_pid) {
704 for (const auto& dev : config->devices) {
Stephen Barber7bae6642017-11-30 10:47:12 -0800705 int major = dev.major;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700706 int minor = dev.minor;
707
Stephen Barber7bae6642017-11-30 10:47:12 -0800708 if (dev.copy_major || dev.copy_minor) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700709 struct stat st_buff;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700710 if (stat(dev.path.value().c_str(), &st_buff) != 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700711 continue;
Stephen Barber7bae6642017-11-30 10:47:12 -0800712
713 if (dev.copy_major)
714 major = major(st_buff.st_rdev);
715 if (dev.copy_minor)
716 minor = minor(st_buff.st_rdev);
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700717 }
Stephen Barber7bae6642017-11-30 10:47:12 -0800718 if (major < 0 || minor < 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700719 continue;
Stephen Barber7bae6642017-11-30 10:47:12 -0800720 if (!ContainerCreateDevice(c, config, dev, major, minor))
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700721 return false;
722 }
723
724 return true;
725}
726
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700727bool DeviceSetup(struct container* c, const struct container_config* config) {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700728 c->cgroup->DenyAllDevices();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700729
730 for (const auto& dev : config->cgroup_devices) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700731 if (!c->cgroup->AddDevice(dev.allow, dev.major, dev.minor, dev.read,
732 dev.write, dev.modify, dev.type)) {
733 return false;
734 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700735 }
736
Luis Hector Chavez5cf71ed2018-05-07 14:45:43 -0700737 for (const auto& loopdev : c->loopdevs) {
738 if (!c->cgroup->AddDevice(1, major(loopdev.info.lo_rdevice),
739 minor(loopdev.info.lo_rdevice), 1, 0, 0, 'b')) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700740 return false;
741 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700742 }
743
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700744 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700745}
746
747int Setexeccon(void* payload) {
748 char* init_domain = reinterpret_cast<char*>(payload);
749 pid_t tid = syscall(SYS_gettid);
750
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700751 if (tid < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700752 PLOG(ERROR) << "Failed to gettid";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700753 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700754 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700755
756 std::string exec_path =
757 base::StringPrintf("/proc/self/task/%d/attr/exec", tid);
758
759 base::ScopedFD fd(open(exec_path.c_str(), O_WRONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700760 if (!fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700761 PLOG(ERROR) << "Failed to open " << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700762 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700763 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700764
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700765 if (!base::WriteFileDescriptor(fd.get(), init_domain, strlen(init_domain))) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700766 PLOG(ERROR) << "Failed to write the SELinux label to " << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700767 return -errno;
768 }
769
770 return 0;
771}
772
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700773bool ContainerTeardown(struct container* c) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700774 UnmountExternalMounts(c);
775 if (!c->runfsroot.empty() && !c->runfs.empty()) {
776 /* |c->runfsroot| may have been mounted recursively. Thus use
777 * MNT_DETACH to "immediately disconnect the filesystem and all
778 * filesystems mounted below it from each other and from the
779 * mount table". Otherwise one would need to unmount every
780 * single dependent mount before unmounting |c->runfsroot|
781 * itself.
782 */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700783 if (umount2(c->runfsroot.value().c_str(), MNT_DETACH) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700784 PLOG(ERROR) << "Failed to detach " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700785 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700786 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700787 if (rmdir(c->runfsroot.value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700788 PLOG(ERROR) << "Failed to rmdir " << c->runfsroot.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700789 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700790 }
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700791 c->runfsroot = base::FilePath();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700792 }
793 if (!c->pid_file_path.empty()) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700794 if (unlink(c->pid_file_path.value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700795 PLOG(ERROR) << "Failed to unlink " << c->pid_file_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700796 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700797 }
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700798 c->pid_file_path = base::FilePath();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700799 }
800 if (!c->runfs.empty()) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700801 if (rmdir(c->runfs.value().c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700802 PLOG(ERROR) << "Failed to rmdir " << c->runfs.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700803 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700804 }
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700805 c->runfs = base::FilePath();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700806 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700807 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700808}
809
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -0700810void CancelContainerStart(struct container* c) {
811 if (c->init_pid != -1)
812 container_kill(c);
813 ContainerTeardown(c);
814}
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700815
816} // namespace
817
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700818struct container_config* container_config_create() {
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700819 return new (std::nothrow) struct container_config();
Dylan Reid837c74a2016-01-22 17:25:21 -0800820}
821
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700822void container_config_destroy(struct container_config* c) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700823 if (c == nullptr)
824 return;
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700825 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -0800826}
827
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700828int container_config_config_root(struct container_config* c,
829 const char* config_root) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700830 c->config_root = base::FilePath(config_root);
831 return 0;
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500832}
833
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700834const char* container_config_get_config_root(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700835 return c->config_root.value().c_str();
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500836}
837
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700838int container_config_rootfs(struct container_config* c, const char* rootfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700839 c->rootfs = base::FilePath(rootfs);
840 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800841}
842
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700843const char* container_config_get_rootfs(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700844 return c->rootfs.value().c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700845}
846
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700847void container_config_rootfs_mount_flags(struct container_config* c,
848 unsigned long rootfs_mount_flags) {
849 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
850 * simply check against zero later. MS_BIND is also added to avoid
851 * re-mounting the original filesystem, since the rootfs is always
852 * bind-mounted.
853 */
854 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700855}
856
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700857unsigned long container_config_get_rootfs_mount_flags(
858 const struct container_config* c) {
859 return c->rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700860}
861
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700862int container_config_premounted_runfs(struct container_config* c,
863 const char* runfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700864 c->premounted_runfs = base::FilePath(runfs);
865 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700866}
867
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700868const char* container_config_get_premounted_runfs(
869 const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700870 return c->premounted_runfs.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700871}
872
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700873int container_config_pid_file(struct container_config* c, const char* path) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700874 c->pid_file_path = base::FilePath(path);
875 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700876}
877
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700878const char* container_config_get_pid_file(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700879 return c->pid_file_path.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700880}
881
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700882int container_config_program_argv(struct container_config* c,
883 const char** argv,
884 size_t num_args) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700885 if (num_args < 1) {
886 errno = EINVAL;
887 return -1;
888 }
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700889 c->program_argv.clear();
890 c->program_argv.reserve(num_args);
891 for (size_t i = 0; i < num_args; ++i)
892 c->program_argv.emplace_back(argv[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700893 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800894}
895
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700896size_t container_config_get_num_program_args(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700897 return c->program_argv.size();
Dylan Reid11456722016-05-02 11:24:50 -0700898}
899
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700900const char* container_config_get_program_arg(const struct container_config* c,
901 size_t index) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700902 if (index >= c->program_argv.size())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700903 return nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700904 return c->program_argv[index].c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700905}
906
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700907void container_config_uid(struct container_config* c, uid_t uid) {
908 c->uid = uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700909}
910
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700911uid_t container_config_get_uid(const struct container_config* c) {
912 return c->uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700913}
914
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700915int container_config_uid_map(struct container_config* c, const char* uid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700916 c->uid_map = uid_map;
917 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800918}
919
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700920void container_config_gid(struct container_config* c, gid_t gid) {
921 c->gid = gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700922}
923
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700924gid_t container_config_get_gid(const struct container_config* c) {
925 return c->gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700926}
927
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700928int container_config_gid_map(struct container_config* c, const char* gid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700929 c->gid_map = gid_map;
930 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800931}
932
Risanfd41aee2018-08-15 14:03:38 +0900933void container_config_additional_gids(struct container_config* c,
934 const gid_t* gids,
935 size_t num_gids) {
936 c->additional_gids.assign(gids, gids + num_gids);
937}
938
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700939int container_config_alt_syscall_table(struct container_config* c,
940 const char* alt_syscall_table) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700941 c->alt_syscall_table = alt_syscall_table;
942 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800943}
944
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700945int container_config_add_rlimit(struct container_config* c,
946 int type,
Luis Hector Chavezda352462018-01-30 09:10:00 -0800947 rlim_t cur,
948 rlim_t max) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700949 if (c->num_rlimits >= kMaxRlimits) {
950 errno = ENOMEM;
951 return -1;
952 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700953 c->rlimits[c->num_rlimits].type = type;
954 c->rlimits[c->num_rlimits].cur = cur;
955 c->rlimits[c->num_rlimits].max = max;
956 c->num_rlimits++;
957 return 0;
Dylan Reid93fa4602017-06-06 13:39:31 -0700958}
959
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700960int container_config_add_mount(struct container_config* c,
961 const char* name,
962 const char* source,
963 const char* destination,
964 const char* type,
965 const char* data,
966 const char* verity,
967 int flags,
968 int uid,
969 int gid,
970 int mode,
971 int mount_in_ns,
972 int create,
973 int loopback) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700974 if (name == nullptr || source == nullptr || destination == nullptr ||
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700975 type == nullptr) {
976 errno = EINVAL;
977 return -1;
978 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800979
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700980 c->mounts.emplace_back(Mount{name,
981 base::FilePath(source),
982 base::FilePath(destination),
983 type,
984 data ? data : "",
985 verity ? verity : "",
986 flags,
987 uid,
988 gid,
989 mode,
990 mount_in_ns != 0,
991 create != 0,
992 loopback != 0});
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700993
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700994 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800995}
996
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700997int container_config_add_cgroup_device(struct container_config* c,
998 int allow,
999 char type,
1000 int major,
1001 int minor,
1002 int read,
1003 int write,
1004 int modify) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001005 c->cgroup_devices.emplace_back(CgroupDevice{
1006 allow != 0, type, major, minor, read != 0, write != 0, modify != 0});
Dylan Reid4843d6b2017-03-31 18:14:30 -07001007
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001008 return 0;
Dylan Reid4843d6b2017-03-31 18:14:30 -07001009}
1010
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001011int container_config_add_device(struct container_config* c,
1012 char type,
1013 const char* path,
1014 int fs_permissions,
1015 int major,
1016 int minor,
Stephen Barber7bae6642017-11-30 10:47:12 -08001017 int copy_major,
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001018 int copy_minor,
1019 int uid,
1020 int gid,
1021 int read_allowed,
1022 int write_allowed,
1023 int modify_allowed) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001024 if (path == nullptr) {
1025 errno = EINVAL;
1026 return -1;
1027 }
Stephen Barber7bae6642017-11-30 10:47:12 -08001028 /* If using a dynamic major/minor number, ensure that major/minor is -1. */
1029 if ((copy_major && (major != -1)) || (copy_minor && (minor != -1))) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001030 errno = EINVAL;
1031 return -1;
1032 }
Dylan Reid355d5e42016-04-29 16:53:31 -07001033
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001034 if (read_allowed || write_allowed || modify_allowed) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001035 if (container_config_add_cgroup_device(c, 1, type, major, minor,
1036 read_allowed, write_allowed,
1037 modify_allowed) != 0) {
1038 errno = ENOMEM;
1039 return -1;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001040 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001041 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001042
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001043 c->devices.emplace_back(Device{
Stephen Barber7bae6642017-11-30 10:47:12 -08001044 type, base::FilePath(path), fs_permissions, major, minor, copy_major != 0,
1045 copy_minor != 0, uid, gid,
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001046 });
1047
1048 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001049}
1050
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001051int container_config_set_cpu_shares(struct container_config* c, int shares) {
1052 /* CPU shares must be 2 or higher. */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001053 if (shares < 2) {
1054 errno = EINVAL;
1055 return -1;
1056 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001057
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001058 c->cpu_cgparams.shares = shares;
1059 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +08001060}
1061
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001062int container_config_set_cpu_cfs_params(struct container_config* c,
1063 int quota,
1064 int period) {
1065 /*
1066 * quota could be set higher than period to utilize more than one CPU.
1067 * quota could also be set as -1 to indicate the cgroup does not adhere
1068 * to any CPU time restrictions.
1069 */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001070 if (quota <= 0 && quota != -1) {
1071 errno = EINVAL;
1072 return -1;
1073 }
1074 if (period <= 0) {
1075 errno = EINVAL;
1076 return -1;
1077 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001078
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001079 c->cpu_cgparams.quota = quota;
1080 c->cpu_cgparams.period = period;
1081 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +08001082}
1083
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001084int container_config_set_cpu_rt_params(struct container_config* c,
1085 int rt_runtime,
1086 int rt_period) {
1087 /*
1088 * rt_runtime could be set as 0 to prevent the cgroup from using
1089 * realtime CPU.
1090 */
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001091 if (rt_runtime < 0 || rt_runtime >= rt_period) {
1092 errno = EINVAL;
1093 return -1;
1094 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001095
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001096 c->cpu_cgparams.rt_runtime = rt_runtime;
1097 c->cpu_cgparams.rt_period = rt_period;
1098 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +08001099}
1100
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001101int container_config_get_cpu_shares(struct container_config* c) {
1102 return c->cpu_cgparams.shares;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001103}
1104
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001105int container_config_get_cpu_quota(struct container_config* c) {
1106 return c->cpu_cgparams.quota;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001107}
1108
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001109int container_config_get_cpu_period(struct container_config* c) {
1110 return c->cpu_cgparams.period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001111}
1112
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001113int container_config_get_cpu_rt_runtime(struct container_config* c) {
1114 return c->cpu_cgparams.rt_runtime;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001115}
1116
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001117int container_config_get_cpu_rt_period(struct container_config* c) {
1118 return c->cpu_cgparams.rt_period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +08001119}
1120
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001121int container_config_set_cgroup_parent(struct container_config* c,
1122 const char* parent,
1123 uid_t cgroup_owner,
1124 gid_t cgroup_group) {
1125 c->cgroup_owner = cgroup_owner;
1126 c->cgroup_group = cgroup_group;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001127 c->cgroup_parent = base::FilePath(parent);
1128 return 0;
Dylan Reid9e724af2016-07-21 09:58:07 -07001129}
1130
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001131const char* container_config_get_cgroup_parent(struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001132 return c->cgroup_parent.value().c_str();
Dylan Reid9e724af2016-07-21 09:58:07 -07001133}
1134
Stephen Barber771653f2017-10-04 23:48:57 -07001135int container_config_namespaces(struct container_config* c,
1136 const char** namespaces,
1137 size_t num_ns) {
1138 if (num_ns < 1)
1139 return -EINVAL;
1140 c->namespaces.clear();
1141 for (size_t i = 0; i < num_ns; ++i)
1142 c->namespaces.emplace(namespaces[i]);
1143 return 0;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001144}
1145
Stephen Barber771653f2017-10-04 23:48:57 -07001146size_t container_config_get_num_namespaces(const struct container_config* c) {
1147 return c->namespaces.size();
1148}
1149
1150bool container_config_has_namespace(const struct container_config* c,
1151 const char* ns) {
1152 return c->namespaces.find(ns) != c->namespaces.end();
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001153}
1154
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001155void container_config_keep_fds_open(struct container_config* c) {
yusukesf125f332017-12-08 13:45:15 -08001156 c->keep_fds_open = true;
Dylan Reidc4335842016-11-11 10:24:52 -08001157}
1158
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001159void container_config_set_capmask(struct container_config* c,
1160 uint64_t capmask,
1161 int ambient) {
yusukesf125f332017-12-08 13:45:15 -08001162 c->use_capmask = true;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001163 c->capmask = capmask;
1164 c->use_capmask_ambient = ambient;
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001165}
1166
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001167void container_config_set_securebits_skip_mask(struct container_config* c,
1168 uint64_t securebits_skip_mask) {
1169 c->securebits_skip_mask = securebits_skip_mask;
Luis Hector Chavezcd44ba72017-06-30 13:01:38 -07001170}
1171
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001172void container_config_set_run_as_init(struct container_config* c,
1173 int run_as_init) {
1174 c->do_init = !run_as_init;
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001175}
1176
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001177int container_config_set_selinux_context(struct container_config* c,
1178 const char* context) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001179 if (!context) {
1180 errno = EINVAL;
1181 return -1;
1182 }
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001183 c->selinux_context = context;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001184 return 0;
Luis Hector Chavez15e8e672017-07-20 15:13:27 -07001185}
1186
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001187void container_config_set_pre_execve_hook(struct container_config* c,
1188 int (*hook)(void*),
1189 void* payload) {
1190 c->pre_start_hook = hook;
1191 c->pre_start_hook_payload = payload;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001192}
1193
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001194void container_config_add_hook(struct container_config* c,
1195 minijail_hook_event_t event,
1196 libcontainer::HookCallback callback) {
1197 auto it = c->hooks.insert(
1198 std::make_pair(event, std::vector<libcontainer::HookCallback>()));
1199 it.first->second.emplace_back(std::move(callback));
1200}
1201
Luis Hector Chaveze03926a2017-09-28 17:28:49 -07001202int container_config_add_hook(struct container_config* c,
1203 minijail_hook_event_t event,
1204 const char* filename,
1205 const char** argv,
1206 size_t num_args,
1207 int* pstdin_fd,
1208 int* pstdout_fd,
1209 int* pstderr_fd) {
1210 std::vector<std::string> args;
1211 args.reserve(num_args);
1212 for (size_t i = 0; i < num_args; ++i)
1213 args.emplace_back(argv[i]);
1214
1215 // First element of the array belongs to the parent and the second one belongs
1216 // to the child.
1217 base::ScopedFD stdin_fds[2], stdout_fds[2], stderr_fds[2];
1218 if (pstdin_fd) {
1219 if (!libcontainer::Pipe2(&stdin_fds[1], &stdin_fds[0], 0))
1220 return -1;
1221 }
1222 if (pstdout_fd) {
1223 if (!libcontainer::Pipe2(&stdout_fds[0], &stdout_fds[0], 0))
1224 return -1;
1225 }
1226 if (pstderr_fd) {
1227 if (!libcontainer::Pipe2(&stderr_fds[0], &stderr_fds[0], 0))
1228 return -1;
1229 }
1230
1231 // After this point the call has been successful, so we can now commit to
1232 // whatever pipes we have opened.
1233 if (pstdin_fd) {
1234 *pstdin_fd = stdin_fds[0].release();
1235 c->inherited_fds.emplace_back(stdin_fds[1].get());
1236 }
1237 if (pstdout_fd) {
1238 *pstdout_fd = stdout_fds[0].release();
1239 c->inherited_fds.emplace_back(stdout_fds[1].get());
1240 }
1241 if (pstderr_fd) {
1242 *pstderr_fd = stderr_fds[0].release();
1243 c->inherited_fds.emplace_back(stderr_fds[1].get());
1244 }
1245 container_config_add_hook(
1246 c, event,
1247 libcontainer::CreateExecveCallback(
1248 base::FilePath(filename), args, std::move(stdin_fds[1]),
1249 std::move(stdout_fds[1]), std::move(stderr_fds[1])));
1250 return 0;
1251}
1252
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001253int container_config_inherit_fds(struct container_config* c,
Luis Hector Chaveza5e87cb2018-05-21 07:21:22 -07001254 const int* inherited_fds,
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001255 size_t inherited_fd_count) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001256 if (!c->inherited_fds.empty()) {
1257 errno = EINVAL;
1258 return -1;
1259 }
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001260 for (size_t i = 0; i < inherited_fd_count; ++i)
1261 c->inherited_fds.emplace_back(inherited_fds[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001262 return 0;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001263}
1264
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001265struct container* container_new(const char* name, const char* rundir) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001266 struct container* c = new (std::nothrow) container();
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001267 if (!c)
1268 return nullptr;
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001269 c->rundir = base::FilePath(rundir);
1270 c->name = name;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001271 return c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001272}
1273
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001274void container_destroy(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001275 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001276}
1277
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001278int container_start(struct container* c,
1279 const struct container_config* config) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001280 if (!c) {
1281 errno = EINVAL;
1282 return -1;
1283 }
1284 if (!config) {
1285 errno = EINVAL;
1286 return -1;
1287 }
1288 if (config->program_argv.empty()) {
1289 errno = EINVAL;
1290 return -1;
1291 }
Dylan Reide040c6b2016-05-02 18:49:02 -07001292
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001293 // This will run in all the error cases.
1294 base::ScopedClosureRunner teardown(
Luis Hector Chavez15d0d1a2017-10-12 09:30:19 -07001295 base::Bind(&CancelContainerStart, base::Unretained(c)));
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001296
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001297 if (!config->config_root.empty())
1298 c->config_root = config->config_root;
1299 if (!config->premounted_runfs.empty()) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001300 c->runfs.clear();
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001301 c->runfsroot = config->premounted_runfs;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001302 } else {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001303 if (!MountRunfs(c, config))
1304 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001305 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001306
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001307 c->jail.reset(minijail_new());
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001308 if (!c->jail) {
1309 errno = ENOMEM;
1310 return -1;
1311 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001312
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001313 if (!DoContainerMounts(c, config))
1314 return -1;
Dylan Reid837c74a2016-01-22 17:25:21 -08001315
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001316 int cgroup_uid;
1317 if (!GetUsernsOutsideId(config->uid_map, config->cgroup_owner, &cgroup_uid))
1318 return -1;
1319 int cgroup_gid;
1320 if (!GetUsernsOutsideId(config->gid_map, config->cgroup_group, &cgroup_gid))
1321 return -1;
Stephen Barber1a398c72017-01-23 12:39:44 -08001322
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001323 c->cgroup = libcontainer::Cgroup::Create(c->name,
1324 base::FilePath("/sys/fs/cgroup"),
1325 config->cgroup_parent,
1326 cgroup_uid,
1327 cgroup_gid);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001328 if (!c->cgroup)
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001329 return -1;
Dylan Reida9966422016-07-21 10:11:34 -07001330
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001331 // Must be root to modify device cgroup or mknod.
1332 std::map<minijail_hook_event_t, std::vector<libcontainer::HookCallback>>
1333 hook_callbacks;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001334 if (getuid() == 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001335 if (!config->devices.empty()) {
1336 // Create the devices in the mount namespace.
1337 auto it = hook_callbacks.insert(
1338 std::make_pair(MINIJAIL_HOOK_EVENT_PRE_CHROOT,
1339 std::vector<libcontainer::HookCallback>()));
1340 it.first->second.emplace_back(
1341 libcontainer::AdaptCallbackToRunInNamespaces(
1342 base::Bind(&CreateDeviceNodes, base::Unretained(c),
1343 base::Unretained(config)),
1344 {CLONE_NEWNS}));
1345 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001346 if (!DeviceSetup(c, config))
1347 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001348 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001349
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001350 /* Setup CPU cgroup params. */
1351 if (config->cpu_cgparams.shares) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001352 if (!c->cgroup->SetCpuShares(config->cpu_cgparams.shares))
1353 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001354 }
1355 if (config->cpu_cgparams.period) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001356 if (!c->cgroup->SetCpuQuota(config->cpu_cgparams.quota))
1357 return -1;
1358 if (!c->cgroup->SetCpuPeriod(config->cpu_cgparams.period))
1359 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001360 }
1361 if (config->cpu_cgparams.rt_period) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001362 if (!c->cgroup->SetCpuRtRuntime(config->cpu_cgparams.rt_runtime))
1363 return -1;
1364 if (!c->cgroup->SetCpuRtPeriod(config->cpu_cgparams.rt_period))
1365 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001366 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001367
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001368 /* Setup and start the container with libminijail. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001369 if (!config->pid_file_path.empty())
1370 c->pid_file_path = config->pid_file_path;
1371 else if (!c->runfs.empty())
1372 c->pid_file_path = c->runfs.Append("container.pid");
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001373
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001374 if (!c->pid_file_path.empty())
1375 minijail_write_pid_file(c->jail.get(), c->pid_file_path.value().c_str());
1376 minijail_reset_signal_mask(c->jail.get());
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -07001377 minijail_reset_signal_handlers(c->jail.get());
Dylan Reid837c74a2016-01-22 17:25:21 -08001378
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001379 /* Setup container namespaces. */
Stephen Barber771653f2017-10-04 23:48:57 -07001380 if (container_config_has_namespace(config, "ipc"))
1381 minijail_namespace_ipc(c->jail.get());
1382 if (container_config_has_namespace(config, "mount"))
1383 minijail_namespace_vfs(c->jail.get());
1384 if (container_config_has_namespace(config, "network"))
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001385 minijail_namespace_net(c->jail.get());
Stephen Barber771653f2017-10-04 23:48:57 -07001386 if (container_config_has_namespace(config, "pid"))
1387 minijail_namespace_pids(c->jail.get());
1388
1389 if (container_config_has_namespace(config, "user")) {
1390 minijail_namespace_user(c->jail.get());
1391 if (minijail_uidmap(c->jail.get(), config->uid_map.c_str()) != 0)
1392 return -1;
1393 if (minijail_gidmap(c->jail.get(), config->gid_map.c_str()) != 0)
1394 return -1;
1395 }
1396
1397 if (container_config_has_namespace(config, "cgroup"))
1398 minijail_namespace_cgroups(c->jail.get());
1399
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001400 if (getuid() != 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001401 minijail_namespace_user_disable_setgroups(c->jail.get());
Dylan Reid837c74a2016-01-22 17:25:21 -08001402
Risanfd41aee2018-08-15 14:03:38 +09001403 // Set the UID/GID inside the container if not 0.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001404 if (!GetUsernsOutsideId(config->uid_map, config->uid, nullptr))
1405 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001406 else if (config->uid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001407 minijail_change_uid(c->jail.get(), config->uid);
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001408 if (!GetUsernsOutsideId(config->gid_map, config->gid, nullptr))
1409 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001410 else if (config->gid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001411 minijail_change_gid(c->jail.get(), config->gid);
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001412
Risanfd41aee2018-08-15 14:03:38 +09001413 // Set the supplementary GIDs inside the container, if specified.
1414 if (!config->additional_gids.empty()) {
1415 for (const gid_t additional_gid : config->additional_gids) {
1416 if (!GetUsernsOutsideId(config->gid_map, additional_gid, nullptr))
1417 return -1;
1418 }
1419 minijail_set_supplementary_gids(c->jail.get(),
1420 config->additional_gids.size(),
1421 config->additional_gids.data());
1422 }
1423
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001424 if (minijail_enter_pivot_root(c->jail.get(), c->runfsroot.value().c_str()) !=
1425 0) {
1426 return -1;
1427 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001428
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001429 // Add the cgroups configured above.
1430 for (int32_t i = 0; i < libcontainer::Cgroup::Type::NUM_TYPES; i++) {
1431 if (c->cgroup->has_tasks_path(i)) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001432 if (minijail_add_to_cgroup(
1433 c->jail.get(), c->cgroup->tasks_path(i).value().c_str()) != 0) {
1434 return -1;
1435 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001436 }
1437 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001438
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001439 if (!config->alt_syscall_table.empty())
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001440 minijail_use_alt_syscall(c->jail.get(), config->alt_syscall_table.c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -08001441
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001442 for (int i = 0; i < config->num_rlimits; i++) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001443 const Rlimit& lim = config->rlimits[i];
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001444 if (minijail_rlimit(c->jail.get(), lim.type, lim.cur, lim.max) != 0)
1445 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001446 }
Dylan Reid93fa4602017-06-06 13:39:31 -07001447
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001448 if (!config->selinux_context.empty()) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001449 if (minijail_add_hook(c->jail.get(), &Setexeccon,
1450 const_cast<char*>(config->selinux_context.c_str()),
1451 MINIJAIL_HOOK_EVENT_PRE_EXECVE) != 0) {
1452 return -1;
1453 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001454 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001455
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001456 if (config->pre_start_hook) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001457 if (minijail_add_hook(c->jail.get(), config->pre_start_hook,
1458 config->pre_start_hook_payload,
1459 MINIJAIL_HOOK_EVENT_PRE_EXECVE) != 0) {
1460 return -1;
1461 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001462 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001463
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001464 // Now that all pre-requisite hooks are installed, copy the ones in the
1465 // container_config object in the correct order.
1466 for (const auto& config_hook : config->hooks) {
1467 auto it = hook_callbacks.insert(std::make_pair(
1468 config_hook.first, std::vector<libcontainer::HookCallback>()));
1469 it.first->second.insert(it.first->second.end(), config_hook.second.begin(),
1470 config_hook.second.end());
1471 }
1472
1473 c->hook_states.clear();
1474 // Reserve enough memory to hold all the hooks, so that their addresses do not
1475 // get invalidated by reallocation.
1476 c->hook_states.reserve(MINIJAIL_HOOK_EVENT_MAX);
1477 for (minijail_hook_event_t event : {MINIJAIL_HOOK_EVENT_PRE_CHROOT,
1478 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS,
1479 MINIJAIL_HOOK_EVENT_PRE_EXECVE}) {
1480 const auto& it = hook_callbacks.find(event);
1481 if (it == hook_callbacks.end())
1482 continue;
1483 c->hook_states.emplace_back(
1484 std::make_pair(libcontainer::HookState(), it->second));
1485 if (!c->hook_states.back().first.InstallHook(c->jail.get(), event))
1486 return -1;
1487 }
1488
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001489 for (int fd : config->inherited_fds) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001490 if (minijail_preserve_fd(c->jail.get(), fd, fd) != 0)
1491 return -1;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001492 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001493
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001494 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001495 minijail_skip_remount_private(c->jail.get());
Dylan Reid3da683b2016-04-05 03:35:35 -07001496
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001497 if (!config->keep_fds_open)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001498 minijail_close_open_fds(c->jail.get());
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001499
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001500 if (config->use_capmask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001501 minijail_use_caps(c->jail.get(), config->capmask);
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001502 if (config->use_capmask_ambient)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001503 minijail_set_ambient_caps(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001504 if (config->securebits_skip_mask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001505 minijail_skip_setting_securebits(c->jail.get(),
1506 config->securebits_skip_mask);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001507 }
1508 }
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001509
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001510 if (!config->do_init)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001511 minijail_run_as_init(c->jail.get());
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001512
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001513 std::vector<char*> argv_cstr;
1514 argv_cstr.reserve(config->program_argv.size() + 1);
1515 for (const auto& arg : config->program_argv)
1516 argv_cstr.emplace_back(const_cast<char*>(arg.c_str()));
1517 argv_cstr.emplace_back(nullptr);
1518
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001519 if (minijail_run_pid_pipes_no_preload(c->jail.get(), argv_cstr[0],
1520 argv_cstr.data(), &c->init_pid, nullptr,
1521 nullptr, nullptr) != 0) {
1522 return -1;
1523 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001524
Luis Hector Chavez644d2042017-09-19 18:56:44 -07001525 // |hook_states| is already sorted in the correct order.
1526 for (auto& hook_state : c->hook_states) {
1527 if (!hook_state.first.WaitForHookAndRun(hook_state.second, c->init_pid))
1528 return -1;
1529 }
1530
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001531 // The container has started successfully, no need to tear it down anymore.
1532 ignore_result(teardown.Release());
1533 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001534}
1535
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001536const char* container_root(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001537 return c->runfs.value().c_str();
Dylan Reid837c74a2016-01-22 17:25:21 -08001538}
1539
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001540int container_pid(struct container* c) {
1541 return c->init_pid;
Dylan Reid837c74a2016-01-22 17:25:21 -08001542}
1543
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001544int container_wait(struct container* c) {
1545 int rc;
Dylan Reidcf745c52016-04-22 10:18:03 -07001546
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001547 do {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001548 rc = minijail_wait(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001549 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001550
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001551 // If the process had already been reaped, still perform teardown.
1552 if (rc == -ECHILD || rc >= 0) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001553 if (!ContainerTeardown(c))
1554 rc = -errno;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001555 }
1556 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001557}
1558
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001559int container_kill(struct container* c) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -07001560 if (kill(c->init_pid, SIGKILL) != 0 && errno != ESRCH) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -07001561 PLOG(ERROR) << "Failed to kill " << c->init_pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001562 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -07001563 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001564 return container_wait(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001565}
yusukesbbc37a72017-11-21 09:51:54 -08001566
yusukes32622542018-01-05 18:59:52 -08001567char* container_config_dump(struct container_config* c, int sort_vectors) {
yusukesbbc37a72017-11-21 09:51:54 -08001568 std::stringstream out;
yusukes32622542018-01-05 18:59:52 -08001569 DumpConfig(&out, c, sort_vectors);
yusukesbbc37a72017-11-21 09:51:54 -08001570 return strdup(out.str().c_str());
1571}