]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/namespace.c
core: fall back to bind-mounts for PrivateDevices= execution environments
[thirdparty/systemd.git] / src / core / namespace.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <sched.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/mount.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <linux/fs.h>
29
30 #include "alloc-util.h"
31 #include "base-filesystem.h"
32 #include "dev-setup.h"
33 #include "fd-util.h"
34 #include "fs-util.h"
35 #include "label.h"
36 #include "loop-util.h"
37 #include "loopback-setup.h"
38 #include "missing.h"
39 #include "mkdir.h"
40 #include "mount-util.h"
41 #include "namespace.h"
42 #include "path-util.h"
43 #include "selinux-util.h"
44 #include "socket-util.h"
45 #include "stat-util.h"
46 #include "string-table.h"
47 #include "string-util.h"
48 #include "strv.h"
49 #include "umask-util.h"
50 #include "user-util.h"
51 #include "util.h"
52
53 #define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
54
55 typedef enum MountMode {
56 /* This is ordered by priority! */
57 INACCESSIBLE,
58 BIND_MOUNT,
59 BIND_MOUNT_RECURSIVE,
60 PRIVATE_TMP,
61 PRIVATE_DEV,
62 BIND_DEV,
63 EMPTY_DIR,
64 SYSFS,
65 PROCFS,
66 READONLY,
67 READWRITE,
68 TMPFS,
69 } MountMode;
70
71 typedef struct MountEntry {
72 const char *path_const; /* Memory allocated on stack or static */
73 MountMode mode:5;
74 bool ignore:1; /* Ignore if path does not exist? */
75 bool has_prefix:1; /* Already is prefixed by the root dir? */
76 bool read_only:1; /* Shall this mount point be read-only? */
77 char *path_malloc; /* Use this instead of 'path_const' if we had to allocate memory */
78 const char *source_const; /* The source path, for bind mounts */
79 char *source_malloc;
80 const char *options_const;/* Mount options for tmpfs */
81 char *options_malloc;
82 unsigned long flags; /* Mount flags used by EMPTY_DIR and TMPFS. Do not include MS_RDONLY here, but please use read_only. */
83 } MountEntry;
84
85 /* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted
86 * something there already. These mounts are hence overriden by any other explicitly configured mounts. */
87 static const MountEntry apivfs_table[] = {
88 { "/proc", PROCFS, false },
89 { "/dev", BIND_DEV, false },
90 { "/sys", SYSFS, false },
91 };
92
93 /* ProtectKernelTunables= option and the related filesystem APIs */
94 static const MountEntry protect_kernel_tunables_table[] = {
95 { "/proc/sys", READONLY, false },
96 { "/proc/sysrq-trigger", READONLY, true },
97 { "/proc/latency_stats", READONLY, true },
98 { "/proc/mtrr", READONLY, true },
99 { "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
100 { "/proc/acpi", READONLY, true },
101 { "/proc/timer_stats", READONLY, true },
102 { "/proc/asound", READONLY, true },
103 { "/proc/bus", READONLY, true },
104 { "/proc/fs", READONLY, true },
105 { "/proc/irq", READONLY, true },
106 { "/sys", READONLY, false },
107 { "/sys/kernel/debug", READONLY, true },
108 { "/sys/kernel/tracing", READONLY, true },
109 { "/sys/fs/bpf", READONLY, true },
110 { "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
111 { "/sys/fs/selinux", READWRITE, true },
112 };
113
114 /* ProtectKernelModules= option */
115 static const MountEntry protect_kernel_modules_table[] = {
116 #if HAVE_SPLIT_USR
117 { "/lib/modules", INACCESSIBLE, true },
118 #endif
119 { "/usr/lib/modules", INACCESSIBLE, true },
120 };
121
122 /*
123 * ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
124 * system should be protected by ProtectSystem=
125 */
126 static const MountEntry protect_home_read_only_table[] = {
127 { "/home", READONLY, true },
128 { "/run/user", READONLY, true },
129 { "/root", READONLY, true },
130 };
131
132 /* ProtectHome=tmpfs table */
133 static const MountEntry protect_home_tmpfs_table[] = {
134 { "/home", TMPFS, true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
135 { "/run/user", TMPFS, true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
136 { "/root", TMPFS, true, .read_only = true, .options_const = "mode=0700", .flags = MS_NODEV|MS_STRICTATIME },
137 };
138
139 /* ProtectHome=yes table */
140 static const MountEntry protect_home_yes_table[] = {
141 { "/home", INACCESSIBLE, true },
142 { "/run/user", INACCESSIBLE, true },
143 { "/root", INACCESSIBLE, true },
144 };
145
146 /* ProtectSystem=yes table */
147 static const MountEntry protect_system_yes_table[] = {
148 { "/usr", READONLY, false },
149 { "/boot", READONLY, true },
150 { "/efi", READONLY, true },
151 #if HAVE_SPLIT_USR
152 { "/lib", READONLY, true },
153 { "/lib64", READONLY, true },
154 { "/bin", READONLY, true },
155 # if HAVE_SPLIT_BIN
156 { "/sbin", READONLY, true },
157 # endif
158 #endif
159 };
160
161 /* ProtectSystem=full includes ProtectSystem=yes */
162 static const MountEntry protect_system_full_table[] = {
163 { "/usr", READONLY, false },
164 { "/boot", READONLY, true },
165 { "/efi", READONLY, true },
166 { "/etc", READONLY, false },
167 #if HAVE_SPLIT_USR
168 { "/lib", READONLY, true },
169 { "/lib64", READONLY, true },
170 { "/bin", READONLY, true },
171 # if HAVE_SPLIT_BIN
172 { "/sbin", READONLY, true },
173 # endif
174 #endif
175 };
176
177 /*
178 * ProtectSystem=strict table. In this strict mode, we mount everything
179 * read-only, except for /proc, /dev, /sys which are the kernel API VFS,
180 * which are left writable, but PrivateDevices= + ProtectKernelTunables=
181 * protect those, and these options should be fully orthogonal.
182 * (And of course /home and friends are also left writable, as ProtectHome=
183 * shall manage those, orthogonally).
184 */
185 static const MountEntry protect_system_strict_table[] = {
186 { "/", READONLY, false },
187 { "/proc", READWRITE, false }, /* ProtectKernelTunables= */
188 { "/sys", READWRITE, false }, /* ProtectKernelTunables= */
189 { "/dev", READWRITE, false }, /* PrivateDevices= */
190 { "/home", READWRITE, true }, /* ProtectHome= */
191 { "/run/user", READWRITE, true }, /* ProtectHome= */
192 { "/root", READWRITE, true }, /* ProtectHome= */
193 };
194
195 static const char *mount_entry_path(const MountEntry *p) {
196 assert(p);
197
198 /* Returns the path of this bind mount. If the malloc()-allocated ->path_buffer field is set we return that,
199 * otherwise the stack/static ->path field is returned. */
200
201 return p->path_malloc ?: p->path_const;
202 }
203
204 static bool mount_entry_read_only(const MountEntry *p) {
205 assert(p);
206
207 return p->read_only || IN_SET(p->mode, READONLY, INACCESSIBLE);
208 }
209
210 static const char *mount_entry_source(const MountEntry *p) {
211 assert(p);
212
213 return p->source_malloc ?: p->source_const;
214 }
215
216 static const char *mount_entry_options(const MountEntry *p) {
217 assert(p);
218
219 return p->options_malloc ?: p->options_const;
220 }
221
222 static void mount_entry_done(MountEntry *p) {
223 assert(p);
224
225 p->path_malloc = mfree(p->path_malloc);
226 p->source_malloc = mfree(p->source_malloc);
227 p->options_malloc = mfree(p->options_malloc);
228 }
229
230 static int append_access_mounts(MountEntry **p, char **strv, MountMode mode, bool forcibly_require_prefix) {
231 char **i;
232
233 assert(p);
234
235 /* Adds a list of user-supplied READWRITE/READONLY/INACCESSIBLE entries */
236
237 STRV_FOREACH(i, strv) {
238 bool ignore = false, needs_prefix = false;
239 const char *e = *i;
240
241 /* Look for any prefixes */
242 if (startswith(e, "-")) {
243 e++;
244 ignore = true;
245 }
246 if (startswith(e, "+")) {
247 e++;
248 needs_prefix = true;
249 }
250
251 if (!path_is_absolute(e))
252 return -EINVAL;
253
254 *((*p)++) = (MountEntry) {
255 .path_const = e,
256 .mode = mode,
257 .ignore = ignore,
258 .has_prefix = !needs_prefix && !forcibly_require_prefix,
259 };
260 }
261
262 return 0;
263 }
264
265 static int append_empty_dir_mounts(MountEntry **p, char **strv) {
266 char **i;
267
268 assert(p);
269
270 /* Adds tmpfs mounts to provide readable but empty directories. This is primarily used to implement the
271 * "/private/" boundary directories for DynamicUser=1. */
272
273 STRV_FOREACH(i, strv) {
274
275 *((*p)++) = (MountEntry) {
276 .path_const = *i,
277 .mode = EMPTY_DIR,
278 .ignore = false,
279 .has_prefix = false,
280 .read_only = true,
281 .options_const = "mode=755",
282 .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
283 };
284 }
285
286 return 0;
287 }
288
289 static int append_bind_mounts(MountEntry **p, const BindMount *binds, unsigned n) {
290 unsigned i;
291
292 assert(p);
293
294 for (i = 0; i < n; i++) {
295 const BindMount *b = binds + i;
296
297 *((*p)++) = (MountEntry) {
298 .path_const = b->destination,
299 .mode = b->recursive ? BIND_MOUNT_RECURSIVE : BIND_MOUNT,
300 .read_only = b->read_only,
301 .source_const = b->source,
302 .ignore = b->ignore_enoent,
303 };
304 }
305
306 return 0;
307 }
308
309 static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, unsigned n) {
310 unsigned i;
311 int r;
312
313 assert(p);
314
315 for (i = 0; i < n; i++) {
316 const TemporaryFileSystem *t = tmpfs + i;
317 _cleanup_free_ char *o = NULL, *str = NULL;
318 unsigned long flags = MS_NODEV|MS_STRICTATIME;
319 bool ro = false;
320
321 if (!path_is_absolute(t->path))
322 return -EINVAL;
323
324 if (!isempty(t->options)) {
325 str = strjoin("mode=0755,", t->options);
326 if (!str)
327 return -ENOMEM;
328
329 r = mount_option_mangle(str, MS_NODEV|MS_STRICTATIME, &flags, &o);
330 if (r < 0)
331 return r;
332
333 ro = !!(flags & MS_RDONLY);
334 if (ro)
335 flags ^= MS_RDONLY;
336 }
337
338 *((*p)++) = (MountEntry) {
339 .path_const = t->path,
340 .mode = TMPFS,
341 .read_only = ro,
342 .options_malloc = o,
343 .flags = flags,
344 };
345
346 o = NULL;
347 }
348
349 return 0;
350 }
351
352 static int append_static_mounts(MountEntry **p, const MountEntry *mounts, unsigned n, bool ignore_protect) {
353 unsigned i;
354
355 assert(p);
356 assert(mounts);
357
358 /* Adds a list of static pre-defined entries */
359
360 for (i = 0; i < n; i++)
361 *((*p)++) = (MountEntry) {
362 .path_const = mount_entry_path(mounts+i),
363 .mode = mounts[i].mode,
364 .ignore = mounts[i].ignore || ignore_protect,
365 };
366
367 return 0;
368 }
369
370 static int append_protect_home(MountEntry **p, ProtectHome protect_home, bool ignore_protect) {
371 assert(p);
372
373 switch (protect_home) {
374
375 case PROTECT_HOME_NO:
376 return 0;
377
378 case PROTECT_HOME_READ_ONLY:
379 return append_static_mounts(p, protect_home_read_only_table, ELEMENTSOF(protect_home_read_only_table), ignore_protect);
380
381 case PROTECT_HOME_TMPFS:
382 return append_static_mounts(p, protect_home_tmpfs_table, ELEMENTSOF(protect_home_tmpfs_table), ignore_protect);
383
384 case PROTECT_HOME_YES:
385 return append_static_mounts(p, protect_home_yes_table, ELEMENTSOF(protect_home_yes_table), ignore_protect);
386
387 default:
388 assert_not_reached("Unexpected ProtectHome= value");
389 }
390 }
391
392 static int append_protect_system(MountEntry **p, ProtectSystem protect_system, bool ignore_protect) {
393 assert(p);
394
395 switch (protect_system) {
396
397 case PROTECT_SYSTEM_NO:
398 return 0;
399
400 case PROTECT_SYSTEM_STRICT:
401 return append_static_mounts(p, protect_system_strict_table, ELEMENTSOF(protect_system_strict_table), ignore_protect);
402
403 case PROTECT_SYSTEM_YES:
404 return append_static_mounts(p, protect_system_yes_table, ELEMENTSOF(protect_system_yes_table), ignore_protect);
405
406 case PROTECT_SYSTEM_FULL:
407 return append_static_mounts(p, protect_system_full_table, ELEMENTSOF(protect_system_full_table), ignore_protect);
408
409 default:
410 assert_not_reached("Unexpected ProtectSystem= value");
411 }
412 }
413
414 static int mount_path_compare(const void *a, const void *b) {
415 const MountEntry *p = a, *q = b;
416 int d;
417
418 /* If the paths are not equal, then order prefixes first */
419 d = path_compare(mount_entry_path(p), mount_entry_path(q));
420 if (d != 0)
421 return d;
422
423 /* If the paths are equal, check the mode */
424 if (p->mode < q->mode)
425 return -1;
426
427 if (p->mode > q->mode)
428 return 1;
429
430 return 0;
431 }
432
433 static int prefix_where_needed(MountEntry *m, unsigned n, const char *root_directory) {
434 unsigned i;
435
436 /* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
437 * that. */
438
439 if (!root_directory)
440 return 0;
441
442 for (i = 0; i < n; i++) {
443 char *s;
444
445 if (m[i].has_prefix)
446 continue;
447
448 s = prefix_root(root_directory, mount_entry_path(m+i));
449 if (!s)
450 return -ENOMEM;
451
452 free_and_replace(m[i].path_malloc, s);
453 m[i].has_prefix = true;
454 }
455
456 return 0;
457 }
458
459 static void drop_duplicates(MountEntry *m, unsigned *n) {
460 MountEntry *f, *t, *previous;
461
462 assert(m);
463 assert(n);
464
465 /* Drops duplicate entries. Expects that the array is properly ordered already. */
466
467 for (f = m, t = m, previous = NULL; f < m + *n; f++) {
468
469 /* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
470 * above. */
471 if (previous && path_equal(mount_entry_path(f), mount_entry_path(previous))) {
472 log_debug("%s is duplicate.", mount_entry_path(f));
473 previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */
474 mount_entry_done(f);
475 continue;
476 }
477
478 *t = *f;
479 previous = t;
480 t++;
481 }
482
483 *n = t - m;
484 }
485
486 static void drop_inaccessible(MountEntry *m, unsigned *n) {
487 MountEntry *f, *t;
488 const char *clear = NULL;
489
490 assert(m);
491 assert(n);
492
493 /* Drops all entries obstructed by another entry further up the tree. Expects that the array is properly
494 * ordered already. */
495
496 for (f = m, t = m; f < m + *n; f++) {
497
498 /* If we found a path set for INACCESSIBLE earlier, and this entry has it as prefix we should drop
499 * it, as inaccessible paths really should drop the entire subtree. */
500 if (clear && path_startswith(mount_entry_path(f), clear)) {
501 log_debug("%s is masked by %s.", mount_entry_path(f), clear);
502 mount_entry_done(f);
503 continue;
504 }
505
506 clear = f->mode == INACCESSIBLE ? mount_entry_path(f) : NULL;
507
508 *t = *f;
509 t++;
510 }
511
512 *n = t - m;
513 }
514
515 static void drop_nop(MountEntry *m, unsigned *n) {
516 MountEntry *f, *t;
517
518 assert(m);
519 assert(n);
520
521 /* Drops all entries which have an immediate parent that has the same type, as they are redundant. Assumes the
522 * list is ordered by prefixes. */
523
524 for (f = m, t = m; f < m + *n; f++) {
525
526 /* Only suppress such subtrees for READONLY and READWRITE entries */
527 if (IN_SET(f->mode, READONLY, READWRITE)) {
528 MountEntry *p;
529 bool found = false;
530
531 /* Now let's find the first parent of the entry we are looking at. */
532 for (p = t-1; p >= m; p--) {
533 if (path_startswith(mount_entry_path(f), mount_entry_path(p))) {
534 found = true;
535 break;
536 }
537 }
538
539 /* We found it, let's see if it's the same mode, if so, we can drop this entry */
540 if (found && p->mode == f->mode) {
541 log_debug("%s is redundant by %s", mount_entry_path(f), mount_entry_path(p));
542 mount_entry_done(f);
543 continue;
544 }
545 }
546
547 *t = *f;
548 t++;
549 }
550
551 *n = t - m;
552 }
553
554 static void drop_outside_root(const char *root_directory, MountEntry *m, unsigned *n) {
555 MountEntry *f, *t;
556
557 assert(m);
558 assert(n);
559
560 /* Nothing to do */
561 if (!root_directory)
562 return;
563
564 /* Drops all mounts that are outside of the root directory. */
565
566 for (f = m, t = m; f < m + *n; f++) {
567
568 if (!path_startswith(mount_entry_path(f), root_directory)) {
569 log_debug("%s is outside of root directory.", mount_entry_path(f));
570 mount_entry_done(f);
571 continue;
572 }
573
574 *t = *f;
575 t++;
576 }
577
578 *n = t - m;
579 }
580
581 static int clone_device_node(const char *d, const char *temporary_mount, bool *make_devnode) {
582 const char *dn;
583 struct stat st;
584 int r;
585
586 if (stat(d, &st) < 0) {
587 if (errno == ENOENT)
588 return 0;
589 return -errno;
590 }
591
592 if (!S_ISBLK(st.st_mode) &&
593 !S_ISCHR(st.st_mode))
594 return -EINVAL;
595
596 if (st.st_rdev == 0)
597 return 0;
598
599 dn = strjoina(temporary_mount, d);
600
601 if (*make_devnode) {
602 mac_selinux_create_file_prepare(d, st.st_mode);
603 r = mknod(dn, st.st_mode, st.st_rdev);
604 mac_selinux_create_file_clear();
605
606 if (r == 0)
607 return 1;
608 if (errno != EPERM)
609 return log_debug_errno(errno, "mknod failed for %s: %m", d);
610
611 *make_devnode = false;
612 }
613
614 /* We're about to fallback to bind-mounting the device
615 * node. So create a dummy bind-mount target. */
616 mac_selinux_create_file_prepare(d, 0);
617 r = mknod(dn, S_IFREG, 0);
618 mac_selinux_create_file_clear();
619
620 if (r < 0 && errno != EEXIST)
621 return log_debug_errno(errno, "mknod fallback failed for %s: %m", d);
622
623 /* Fallback to bind-mounting:
624 * The assumption here is that all used device nodes carry standard
625 * properties. Specifically, the devices nodes we bind-mount should
626 * either be owned by root:root or root:tty (e.g. /dev/tty, /dev/ptmx)
627 * and should not carry ACLs. */
628 if (mount(d, dn, NULL, MS_BIND, NULL) < 0)
629 return log_debug_errno(errno, "mount failed for %s: %m", d);
630
631 return 1;
632 }
633
634 static int mount_private_dev(MountEntry *m) {
635 static const char devnodes[] =
636 "/dev/null\0"
637 "/dev/zero\0"
638 "/dev/full\0"
639 "/dev/random\0"
640 "/dev/urandom\0"
641 "/dev/tty\0";
642
643 char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
644 const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
645 bool can_mknod = true;
646 _cleanup_umask_ mode_t u;
647 int r;
648
649 assert(m);
650
651 u = umask(0000);
652
653 if (!mkdtemp(temporary_mount))
654 return -errno;
655
656 dev = strjoina(temporary_mount, "/dev");
657 (void) mkdir(dev, 0755);
658 if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
659 r = -errno;
660 goto fail;
661 }
662
663 devpts = strjoina(temporary_mount, "/dev/pts");
664 (void) mkdir(devpts, 0755);
665 if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
666 r = -errno;
667 goto fail;
668 }
669
670 /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx
671 * when /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible
672 * thus, in that case make a clone
673 *
674 * in nspawn and other containers it will be a symlink, in that case make it a symlink
675 */
676 r = is_symlink("/dev/ptmx");
677 if (r < 0)
678 goto fail;
679 if (r > 0) {
680 devptmx = strjoina(temporary_mount, "/dev/ptmx");
681 if (symlink("pts/ptmx", devptmx) < 0) {
682 r = -errno;
683 goto fail;
684 }
685 } else {
686 r = clone_device_node("/dev/ptmx", temporary_mount, &can_mknod);
687 if (r < 0)
688 goto fail;
689 if (r == 0) {
690 r = -ENXIO;
691 goto fail;
692 }
693 }
694
695 devshm = strjoina(temporary_mount, "/dev/shm");
696 (void) mkdir(devshm, 0755);
697 r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
698 if (r < 0) {
699 r = -errno;
700 goto fail;
701 }
702
703 devmqueue = strjoina(temporary_mount, "/dev/mqueue");
704 (void) mkdir(devmqueue, 0755);
705 (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
706
707 devhugepages = strjoina(temporary_mount, "/dev/hugepages");
708 (void) mkdir(devhugepages, 0755);
709 (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
710
711 devlog = strjoina(temporary_mount, "/dev/log");
712 (void) symlink("/run/systemd/journal/dev-log", devlog);
713
714 NULSTR_FOREACH(d, devnodes) {
715 r = clone_device_node(d, temporary_mount, &can_mknod);
716 if (r < 0)
717 goto fail;
718 }
719
720 dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
721
722 /* Create the /dev directory if missing. It is more likely to be
723 * missing when the service is started with RootDirectory. This is
724 * consistent with mount units creating the mount points when missing.
725 */
726 (void) mkdir_p_label(mount_entry_path(m), 0755);
727
728 /* Unmount everything in old /dev */
729 umount_recursive(mount_entry_path(m), 0);
730 if (mount(dev, mount_entry_path(m), NULL, MS_MOVE, NULL) < 0) {
731 r = -errno;
732 goto fail;
733 }
734
735 rmdir(dev);
736 rmdir(temporary_mount);
737
738 return 0;
739
740 fail:
741 if (devpts)
742 umount(devpts);
743
744 if (devshm)
745 umount(devshm);
746
747 if (devhugepages)
748 umount(devhugepages);
749
750 if (devmqueue)
751 umount(devmqueue);
752
753 umount(dev);
754 rmdir(dev);
755 rmdir(temporary_mount);
756
757 return r;
758 }
759
760 static int mount_bind_dev(const MountEntry *m) {
761 int r;
762
763 assert(m);
764
765 /* Implements the little brother of mount_private_dev(): simply bind mounts the host's /dev into the service's
766 * /dev. This is only used when RootDirectory= is set. */
767
768 (void) mkdir_p_label(mount_entry_path(m), 0755);
769
770 r = path_is_mount_point(mount_entry_path(m), NULL, 0);
771 if (r < 0)
772 return log_debug_errno(r, "Unable to determine whether /dev is already mounted: %m");
773 if (r > 0) /* make this a NOP if /dev is already a mount point */
774 return 0;
775
776 if (mount("/dev", mount_entry_path(m), NULL, MS_BIND|MS_REC, NULL) < 0)
777 return log_debug_errno(errno, "Failed to bind mount %s: %m", mount_entry_path(m));
778
779 return 1;
780 }
781
782 static int mount_sysfs(const MountEntry *m) {
783 int r;
784
785 assert(m);
786
787 (void) mkdir_p_label(mount_entry_path(m), 0755);
788
789 r = path_is_mount_point(mount_entry_path(m), NULL, 0);
790 if (r < 0)
791 return log_debug_errno(r, "Unable to determine whether /sys is already mounted: %m");
792 if (r > 0) /* make this a NOP if /sys is already a mount point */
793 return 0;
794
795 /* Bind mount the host's version so that we get all child mounts of it, too. */
796 if (mount("/sys", mount_entry_path(m), NULL, MS_BIND|MS_REC, NULL) < 0)
797 return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
798
799 return 1;
800 }
801
802 static int mount_procfs(const MountEntry *m) {
803 int r;
804
805 assert(m);
806
807 (void) mkdir_p_label(mount_entry_path(m), 0755);
808
809 r = path_is_mount_point(mount_entry_path(m), NULL, 0);
810 if (r < 0)
811 return log_debug_errno(r, "Unable to determine whether /proc is already mounted: %m");
812 if (r > 0) /* make this a NOP if /proc is already a mount point */
813 return 0;
814
815 /* Mount a new instance, so that we get the one that matches our user namespace, if we are running in one */
816 if (mount("proc", mount_entry_path(m), "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0)
817 return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
818
819 return 1;
820 }
821
822 static int mount_tmpfs(const MountEntry *m) {
823 assert(m);
824
825 /* First, get rid of everything that is below if there is anything. Then, overmount with our new tmpfs */
826
827 (void) mkdir_p_label(mount_entry_path(m), 0755);
828 (void) umount_recursive(mount_entry_path(m), 0);
829
830 if (mount("tmpfs", mount_entry_path(m), "tmpfs", m->flags, mount_entry_options(m)) < 0)
831 return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
832
833 return 1;
834 }
835
836 static int mount_entry_chase(
837 const char *root_directory,
838 const MountEntry *m,
839 const char *path,
840 bool chase_nonexistent,
841 char **location) {
842
843 char *chased;
844 int r;
845
846 assert(m);
847
848 /* Since mount() will always follow symlinks and we need to take the different root directory into account we
849 * chase the symlinks on our own first. This is called for the destination path, as well as the source path (if
850 * that applies). The result is stored in "location". */
851
852 r = chase_symlinks(path, root_directory, chase_nonexistent ? CHASE_NONEXISTENT : 0, &chased);
853 if (r == -ENOENT && m->ignore) {
854 log_debug_errno(r, "Path %s does not exist, ignoring.", path);
855 return 0;
856 }
857 if (r < 0)
858 return log_debug_errno(r, "Failed to follow symlinks on %s: %m", path);
859
860 log_debug("Followed symlinks %s → %s.", path, chased);
861
862 free(*location);
863 *location = chased;
864
865 return 1;
866 }
867
868 static int apply_mount(
869 const char *root_directory,
870 MountEntry *m) {
871
872 bool rbind = true, make = false;
873 const char *what;
874 int r;
875
876 assert(m);
877
878 r = mount_entry_chase(root_directory, m, mount_entry_path(m), !IN_SET(m->mode, INACCESSIBLE, READONLY, READWRITE), &m->path_malloc);
879 if (r <= 0)
880 return r;
881
882 log_debug("Applying namespace mount on %s", mount_entry_path(m));
883
884 switch (m->mode) {
885
886 case INACCESSIBLE: {
887 struct stat target;
888
889 /* First, get rid of everything that is below if there
890 * is anything... Then, overmount it with an
891 * inaccessible path. */
892 (void) umount_recursive(mount_entry_path(m), 0);
893
894 if (lstat(mount_entry_path(m), &target) < 0)
895 return log_debug_errno(errno, "Failed to lstat() %s to determine what to mount over it: %m", mount_entry_path(m));
896
897 what = mode_to_inaccessible_node(target.st_mode);
898 if (!what) {
899 log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed");
900 return -ELOOP;
901 }
902 break;
903 }
904
905 case READONLY:
906 case READWRITE:
907 r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
908 if (r < 0)
909 return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m));
910 if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY bit for the mount point if needed. */
911 return 0;
912 /* This isn't a mount point yet, let's make it one. */
913 what = mount_entry_path(m);
914 break;
915
916 case BIND_MOUNT:
917 rbind = false;
918
919 _fallthrough_;
920 case BIND_MOUNT_RECURSIVE:
921 /* Also chase the source mount */
922
923 r = mount_entry_chase(root_directory, m, mount_entry_source(m), false, &m->source_malloc);
924 if (r <= 0)
925 return r;
926
927 what = mount_entry_source(m);
928 make = true;
929 break;
930
931 case EMPTY_DIR:
932 case TMPFS:
933 return mount_tmpfs(m);
934
935 case PRIVATE_TMP:
936 what = mount_entry_source(m);
937 make = true;
938 break;
939
940 case PRIVATE_DEV:
941 return mount_private_dev(m);
942
943 case BIND_DEV:
944 return mount_bind_dev(m);
945
946 case SYSFS:
947 return mount_sysfs(m);
948
949 case PROCFS:
950 return mount_procfs(m);
951
952 default:
953 assert_not_reached("Unknown mode");
954 }
955
956 assert(what);
957
958 if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0) {
959 bool try_again = false;
960 r = -errno;
961
962 if (r == -ENOENT && make) {
963 struct stat st;
964
965 /* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
966
967 if (stat(what, &st) >= 0) {
968
969 (void) mkdir_parents(mount_entry_path(m), 0755);
970
971 if (S_ISDIR(st.st_mode))
972 try_again = mkdir(mount_entry_path(m), 0755) >= 0;
973 else
974 try_again = touch(mount_entry_path(m)) >= 0;
975 }
976 }
977
978 if (try_again) {
979 if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0)
980 r = -errno;
981 else
982 r = 0;
983 }
984
985 if (r < 0)
986 return log_debug_errno(r, "Failed to mount %s to %s: %m", what, mount_entry_path(m));
987 }
988
989 log_debug("Successfully mounted %s to %s", what, mount_entry_path(m));
990 return 0;
991 }
992
993 static int make_read_only(const MountEntry *m, char **blacklist, FILE *proc_self_mountinfo) {
994 int r = 0;
995
996 assert(m);
997 assert(proc_self_mountinfo);
998
999 if (mount_entry_read_only(m)) {
1000 if (IN_SET(m->mode, EMPTY_DIR, TMPFS)) {
1001 /* Make superblock readonly */
1002 if (mount(NULL, mount_entry_path(m), NULL, MS_REMOUNT | MS_RDONLY | m->flags, mount_entry_options(m)) < 0)
1003 r = -errno;
1004 } else
1005 r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), true, blacklist, proc_self_mountinfo);
1006 } else if (m->mode == PRIVATE_DEV) {
1007 /* Superblock can be readonly but the submounts can't */
1008 if (mount(NULL, mount_entry_path(m), NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
1009 r = -errno;
1010 } else
1011 return 0;
1012
1013 /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked read-only
1014 * already stays this way. This improves compatibility with container managers, where we won't attempt to undo
1015 * read-only mounts already applied. */
1016
1017 if (r == -ENOENT && m->ignore)
1018 r = 0;
1019
1020 return r;
1021 }
1022
1023 static bool namespace_info_mount_apivfs(const char *root_directory, const NamespaceInfo *ns_info) {
1024 assert(ns_info);
1025
1026 /*
1027 * ProtectControlGroups= and ProtectKernelTunables= imply MountAPIVFS=,
1028 * since to protect the API VFS mounts, they need to be around in the
1029 * first place... and RootDirectory= or RootImage= need to be set.
1030 */
1031
1032 /* root_directory should point to a mount point */
1033 return root_directory &&
1034 (ns_info->mount_apivfs ||
1035 ns_info->protect_control_groups ||
1036 ns_info->protect_kernel_tunables);
1037 }
1038
1039 static unsigned namespace_calculate_mounts(
1040 const char* root_directory,
1041 const NamespaceInfo *ns_info,
1042 char** read_write_paths,
1043 char** read_only_paths,
1044 char** inaccessible_paths,
1045 char** empty_directories,
1046 unsigned n_bind_mounts,
1047 unsigned n_temporary_filesystems,
1048 const char* tmp_dir,
1049 const char* var_tmp_dir,
1050 ProtectHome protect_home,
1051 ProtectSystem protect_system) {
1052
1053 unsigned protect_home_cnt;
1054 unsigned protect_system_cnt =
1055 (protect_system == PROTECT_SYSTEM_STRICT ?
1056 ELEMENTSOF(protect_system_strict_table) :
1057 ((protect_system == PROTECT_SYSTEM_FULL) ?
1058 ELEMENTSOF(protect_system_full_table) :
1059 ((protect_system == PROTECT_SYSTEM_YES) ?
1060 ELEMENTSOF(protect_system_yes_table) : 0)));
1061
1062 protect_home_cnt =
1063 (protect_home == PROTECT_HOME_YES ?
1064 ELEMENTSOF(protect_home_yes_table) :
1065 ((protect_home == PROTECT_HOME_READ_ONLY) ?
1066 ELEMENTSOF(protect_home_read_only_table) :
1067 ((protect_home == PROTECT_HOME_TMPFS) ?
1068 ELEMENTSOF(protect_home_tmpfs_table) : 0)));
1069
1070 return !!tmp_dir + !!var_tmp_dir +
1071 strv_length(read_write_paths) +
1072 strv_length(read_only_paths) +
1073 strv_length(inaccessible_paths) +
1074 strv_length(empty_directories) +
1075 n_bind_mounts +
1076 n_temporary_filesystems +
1077 ns_info->private_dev +
1078 (ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
1079 (ns_info->protect_control_groups ? 1 : 0) +
1080 (ns_info->protect_kernel_modules ? ELEMENTSOF(protect_kernel_modules_table) : 0) +
1081 protect_home_cnt + protect_system_cnt +
1082 (namespace_info_mount_apivfs(root_directory, ns_info) ? ELEMENTSOF(apivfs_table) : 0);
1083 }
1084
1085 int setup_namespace(
1086 const char* root_directory,
1087 const char* root_image,
1088 const NamespaceInfo *ns_info,
1089 char** read_write_paths,
1090 char** read_only_paths,
1091 char** inaccessible_paths,
1092 char** empty_directories,
1093 const BindMount *bind_mounts,
1094 unsigned n_bind_mounts,
1095 const TemporaryFileSystem *temporary_filesystems,
1096 unsigned n_temporary_filesystems,
1097 const char* tmp_dir,
1098 const char* var_tmp_dir,
1099 ProtectHome protect_home,
1100 ProtectSystem protect_system,
1101 unsigned long mount_flags,
1102 DissectImageFlags dissect_image_flags) {
1103
1104 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
1105 _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
1106 _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
1107 _cleanup_free_ void *root_hash = NULL;
1108 MountEntry *m, *mounts = NULL;
1109 size_t root_hash_size = 0;
1110 bool make_slave = false;
1111 const char *root;
1112 unsigned n_mounts;
1113 bool require_prefix = false;
1114 int r = 0;
1115
1116 assert(ns_info);
1117
1118 if (mount_flags == 0)
1119 mount_flags = MS_SHARED;
1120
1121 if (root_image) {
1122 dissect_image_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
1123
1124 if (protect_system == PROTECT_SYSTEM_STRICT && strv_isempty(read_write_paths))
1125 dissect_image_flags |= DISSECT_IMAGE_READ_ONLY;
1126
1127 r = loop_device_make_by_path(root_image,
1128 dissect_image_flags & DISSECT_IMAGE_READ_ONLY ? O_RDONLY : O_RDWR,
1129 &loop_device);
1130 if (r < 0)
1131 return r;
1132
1133 r = root_hash_load(root_image, &root_hash, &root_hash_size);
1134 if (r < 0)
1135 return r;
1136
1137 r = dissect_image(loop_device->fd, root_hash, root_hash_size, dissect_image_flags, &dissected_image);
1138 if (r < 0)
1139 return r;
1140
1141 r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, dissect_image_flags, &decrypted_image);
1142 if (r < 0)
1143 return r;
1144 }
1145
1146 if (root_directory)
1147 root = root_directory;
1148 else if (root_image || n_bind_mounts > 0 || n_temporary_filesystems > 0) {
1149
1150 /* If we are booting from an image, create a mount point for the image, if it's still missing. We use
1151 * the same mount point for all images, which is safe, since they all live in their own namespaces
1152 * after all, and hence won't see each other. We also use such a root directory whenever there are bind
1153 * mounts configured, so that their source mounts are never obstructed by mounts we already applied
1154 * while we are applying them. */
1155
1156 root = "/run/systemd/unit-root";
1157 (void) mkdir_label(root, 0700);
1158 require_prefix = true;
1159 } else
1160 root = NULL;
1161
1162 n_mounts = namespace_calculate_mounts(
1163 root,
1164 ns_info,
1165 read_write_paths,
1166 read_only_paths,
1167 inaccessible_paths,
1168 empty_directories,
1169 n_bind_mounts,
1170 n_temporary_filesystems,
1171 tmp_dir, var_tmp_dir,
1172 protect_home, protect_system);
1173
1174 /* Set mount slave mode */
1175 if (root || n_mounts > 0)
1176 make_slave = true;
1177
1178 if (n_mounts > 0) {
1179 m = mounts = (MountEntry *) alloca0(n_mounts * sizeof(MountEntry));
1180 r = append_access_mounts(&m, read_write_paths, READWRITE, require_prefix);
1181 if (r < 0)
1182 goto finish;
1183
1184 r = append_access_mounts(&m, read_only_paths, READONLY, require_prefix);
1185 if (r < 0)
1186 goto finish;
1187
1188 r = append_access_mounts(&m, inaccessible_paths, INACCESSIBLE, require_prefix);
1189 if (r < 0)
1190 goto finish;
1191
1192 r = append_empty_dir_mounts(&m, empty_directories);
1193 if (r < 0)
1194 goto finish;
1195
1196 r = append_bind_mounts(&m, bind_mounts, n_bind_mounts);
1197 if (r < 0)
1198 goto finish;
1199
1200 r = append_tmpfs_mounts(&m, temporary_filesystems, n_temporary_filesystems);
1201 if (r < 0)
1202 goto finish;
1203
1204 if (tmp_dir) {
1205 *(m++) = (MountEntry) {
1206 .path_const = "/tmp",
1207 .mode = PRIVATE_TMP,
1208 .source_const = tmp_dir,
1209 };
1210 }
1211
1212 if (var_tmp_dir) {
1213 *(m++) = (MountEntry) {
1214 .path_const = "/var/tmp",
1215 .mode = PRIVATE_TMP,
1216 .source_const = var_tmp_dir,
1217 };
1218 }
1219
1220 if (ns_info->private_dev) {
1221 *(m++) = (MountEntry) {
1222 .path_const = "/dev",
1223 .mode = PRIVATE_DEV,
1224 };
1225 }
1226
1227 if (ns_info->protect_kernel_tunables) {
1228 r = append_static_mounts(&m, protect_kernel_tunables_table, ELEMENTSOF(protect_kernel_tunables_table), ns_info->ignore_protect_paths);
1229 if (r < 0)
1230 goto finish;
1231 }
1232
1233 if (ns_info->protect_kernel_modules) {
1234 r = append_static_mounts(&m, protect_kernel_modules_table, ELEMENTSOF(protect_kernel_modules_table), ns_info->ignore_protect_paths);
1235 if (r < 0)
1236 goto finish;
1237 }
1238
1239 if (ns_info->protect_control_groups) {
1240 *(m++) = (MountEntry) {
1241 .path_const = "/sys/fs/cgroup",
1242 .mode = READONLY,
1243 };
1244 }
1245
1246 r = append_protect_home(&m, protect_home, ns_info->ignore_protect_paths);
1247 if (r < 0)
1248 goto finish;
1249
1250 r = append_protect_system(&m, protect_system, false);
1251 if (r < 0)
1252 goto finish;
1253
1254 if (namespace_info_mount_apivfs(root, ns_info)) {
1255 r = append_static_mounts(&m, apivfs_table, ELEMENTSOF(apivfs_table), ns_info->ignore_protect_paths);
1256 if (r < 0)
1257 goto finish;
1258 }
1259
1260 assert(mounts + n_mounts == m);
1261
1262 /* Prepend the root directory where that's necessary */
1263 r = prefix_where_needed(mounts, n_mounts, root);
1264 if (r < 0)
1265 goto finish;
1266
1267 qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
1268
1269 drop_duplicates(mounts, &n_mounts);
1270 drop_outside_root(root, mounts, &n_mounts);
1271 drop_inaccessible(mounts, &n_mounts);
1272 drop_nop(mounts, &n_mounts);
1273 }
1274
1275 if (unshare(CLONE_NEWNS) < 0) {
1276 r = -errno;
1277 goto finish;
1278 }
1279
1280 if (make_slave) {
1281 /* Remount / as SLAVE so that nothing now mounted in the namespace
1282 shows up in the parent */
1283 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
1284 r = -errno;
1285 goto finish;
1286 }
1287 }
1288
1289 if (root_image) {
1290 /* A root image is specified, mount it to the right place */
1291 r = dissected_image_mount(dissected_image, root, UID_INVALID, dissect_image_flags);
1292 if (r < 0)
1293 goto finish;
1294
1295 if (decrypted_image) {
1296 r = decrypted_image_relinquish(decrypted_image);
1297 if (r < 0)
1298 goto finish;
1299 }
1300
1301 loop_device_relinquish(loop_device);
1302
1303 } else if (root_directory) {
1304
1305 /* A root directory is specified. Turn its directory into bind mount, if it isn't one yet. */
1306 r = path_is_mount_point(root, NULL, AT_SYMLINK_FOLLOW);
1307 if (r < 0)
1308 goto finish;
1309 if (r == 0) {
1310 if (mount(root, root, NULL, MS_BIND|MS_REC, NULL) < 0) {
1311 r = -errno;
1312 goto finish;
1313 }
1314 }
1315
1316 } else if (root) {
1317
1318 /* Let's mount the main root directory to the root directory to use */
1319 if (mount("/", root, NULL, MS_BIND|MS_REC, NULL) < 0) {
1320 r = -errno;
1321 goto finish;
1322 }
1323 }
1324
1325 /* Try to set up the new root directory before mounting anything else there. */
1326 if (root_image || root_directory)
1327 (void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
1328
1329 if (n_mounts > 0) {
1330 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
1331 char **blacklist;
1332 unsigned j;
1333
1334 /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
1335 * For example, this is the case with the option: 'InaccessiblePaths=/proc' */
1336 proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
1337 if (!proc_self_mountinfo) {
1338 r = -errno;
1339 goto finish;
1340 }
1341
1342 /* First round, add in all special mounts we need */
1343 for (m = mounts; m < mounts + n_mounts; ++m) {
1344 r = apply_mount(root, m);
1345 if (r < 0)
1346 goto finish;
1347 }
1348
1349 /* Create a blacklist we can pass to bind_mount_recursive() */
1350 blacklist = newa(char*, n_mounts+1);
1351 for (j = 0; j < n_mounts; j++)
1352 blacklist[j] = (char*) mount_entry_path(mounts+j);
1353 blacklist[j] = NULL;
1354
1355 /* Second round, flip the ro bits if necessary. */
1356 for (m = mounts; m < mounts + n_mounts; ++m) {
1357 r = make_read_only(m, blacklist, proc_self_mountinfo);
1358 if (r < 0)
1359 goto finish;
1360 }
1361 }
1362
1363 if (root) {
1364 /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
1365 r = mount_move_root(root);
1366 if (r < 0)
1367 goto finish;
1368 }
1369
1370 /* Remount / as the desired mode. Note that this will not
1371 * reestablish propagation from our side to the host, since
1372 * what's disconnected is disconnected. */
1373 if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
1374 r = -errno;
1375 goto finish;
1376 }
1377
1378 r = 0;
1379
1380 finish:
1381 for (m = mounts; m < mounts + n_mounts; m++)
1382 mount_entry_done(m);
1383
1384 return r;
1385 }
1386
1387 void bind_mount_free_many(BindMount *b, unsigned n) {
1388 unsigned i;
1389
1390 assert(b || n == 0);
1391
1392 for (i = 0; i < n; i++) {
1393 free(b[i].source);
1394 free(b[i].destination);
1395 }
1396
1397 free(b);
1398 }
1399
1400 int bind_mount_add(BindMount **b, unsigned *n, const BindMount *item) {
1401 _cleanup_free_ char *s = NULL, *d = NULL;
1402 BindMount *c;
1403
1404 assert(b);
1405 assert(n);
1406 assert(item);
1407
1408 s = strdup(item->source);
1409 if (!s)
1410 return -ENOMEM;
1411
1412 d = strdup(item->destination);
1413 if (!d)
1414 return -ENOMEM;
1415
1416 c = reallocarray(*b, *n + 1, sizeof(BindMount));
1417 if (!c)
1418 return -ENOMEM;
1419
1420 *b = c;
1421
1422 c[(*n) ++] = (BindMount) {
1423 .source = s,
1424 .destination = d,
1425 .read_only = item->read_only,
1426 .recursive = item->recursive,
1427 .ignore_enoent = item->ignore_enoent,
1428 };
1429
1430 s = d = NULL;
1431 return 0;
1432 }
1433
1434 void temporary_filesystem_free_many(TemporaryFileSystem *t, unsigned n) {
1435 unsigned i;
1436
1437 assert(t || n == 0);
1438
1439 for (i = 0; i < n; i++) {
1440 free(t[i].path);
1441 free(t[i].options);
1442 }
1443
1444 free(t);
1445 }
1446
1447 int temporary_filesystem_add(
1448 TemporaryFileSystem **t,
1449 unsigned *n,
1450 const char *path,
1451 const char *options) {
1452
1453 _cleanup_free_ char *p = NULL, *o = NULL;
1454 TemporaryFileSystem *c;
1455
1456 assert(t);
1457 assert(n);
1458 assert(path);
1459
1460 p = strdup(path);
1461 if (!p)
1462 return -ENOMEM;
1463
1464 if (!isempty(options)) {
1465 o = strdup(options);
1466 if (!o)
1467 return -ENOMEM;
1468 }
1469
1470 c = reallocarray(*t, *n + 1, sizeof(TemporaryFileSystem));
1471 if (!c)
1472 return -ENOMEM;
1473
1474 *t = c;
1475
1476 c[(*n) ++] = (TemporaryFileSystem) {
1477 .path = p,
1478 .options = o,
1479 };
1480
1481 p = o = NULL;
1482 return 0;
1483 }
1484
1485 static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
1486 _cleanup_free_ char *x = NULL;
1487 char bid[SD_ID128_STRING_MAX];
1488 sd_id128_t boot_id;
1489 int r;
1490
1491 assert(id);
1492 assert(prefix);
1493 assert(path);
1494
1495 /* We include the boot id in the directory so that after a
1496 * reboot we can easily identify obsolete directories. */
1497
1498 r = sd_id128_get_boot(&boot_id);
1499 if (r < 0)
1500 return r;
1501
1502 x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX");
1503 if (!x)
1504 return -ENOMEM;
1505
1506 RUN_WITH_UMASK(0077)
1507 if (!mkdtemp(x))
1508 return -errno;
1509
1510 RUN_WITH_UMASK(0000) {
1511 char *y;
1512
1513 y = strjoina(x, "/tmp");
1514
1515 if (mkdir(y, 0777 | S_ISVTX) < 0)
1516 return -errno;
1517 }
1518
1519 *path = x;
1520 x = NULL;
1521
1522 return 0;
1523 }
1524
1525 int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
1526 char *a, *b;
1527 int r;
1528
1529 assert(id);
1530 assert(tmp_dir);
1531 assert(var_tmp_dir);
1532
1533 r = setup_one_tmp_dir(id, "/tmp", &a);
1534 if (r < 0)
1535 return r;
1536
1537 r = setup_one_tmp_dir(id, "/var/tmp", &b);
1538 if (r < 0) {
1539 char *t;
1540
1541 t = strjoina(a, "/tmp");
1542 rmdir(t);
1543 rmdir(a);
1544
1545 free(a);
1546 return r;
1547 }
1548
1549 *tmp_dir = a;
1550 *var_tmp_dir = b;
1551
1552 return 0;
1553 }
1554
1555 int setup_netns(int netns_storage_socket[2]) {
1556 _cleanup_close_ int netns = -1;
1557 int r, q;
1558
1559 assert(netns_storage_socket);
1560 assert(netns_storage_socket[0] >= 0);
1561 assert(netns_storage_socket[1] >= 0);
1562
1563 /* We use the passed socketpair as a storage buffer for our
1564 * namespace reference fd. Whatever process runs this first
1565 * shall create a new namespace, all others should just join
1566 * it. To serialize that we use a file lock on the socket
1567 * pair.
1568 *
1569 * It's a bit crazy, but hey, works great! */
1570
1571 if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
1572 return -errno;
1573
1574 netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
1575 if (netns == -EAGAIN) {
1576 /* Nothing stored yet, so let's create a new namespace */
1577
1578 if (unshare(CLONE_NEWNET) < 0) {
1579 r = -errno;
1580 goto fail;
1581 }
1582
1583 loopback_setup();
1584
1585 netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1586 if (netns < 0) {
1587 r = -errno;
1588 goto fail;
1589 }
1590
1591 r = 1;
1592
1593 } else if (netns < 0) {
1594 r = netns;
1595 goto fail;
1596
1597 } else {
1598 /* Yay, found something, so let's join the namespace */
1599 if (setns(netns, CLONE_NEWNET) < 0) {
1600 r = -errno;
1601 goto fail;
1602 }
1603
1604 r = 0;
1605 }
1606
1607 q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
1608 if (q < 0) {
1609 r = q;
1610 goto fail;
1611 }
1612
1613 fail:
1614 (void) lockf(netns_storage_socket[0], F_ULOCK, 0);
1615 return r;
1616 }
1617
1618 bool ns_type_supported(NamespaceType type) {
1619 const char *t, *ns_proc;
1620
1621 t = namespace_type_to_string(type);
1622 if (!t) /* Don't know how to translate this? Then it's not supported */
1623 return false;
1624
1625 ns_proc = strjoina("/proc/self/ns/", t);
1626 return access(ns_proc, F_OK) == 0;
1627 }
1628
1629 static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
1630 [PROTECT_HOME_NO] = "no",
1631 [PROTECT_HOME_YES] = "yes",
1632 [PROTECT_HOME_READ_ONLY] = "read-only",
1633 [PROTECT_HOME_TMPFS] = "tmpfs",
1634 };
1635
1636 DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
1637
1638 ProtectHome parse_protect_home_or_bool(const char *s) {
1639 int r;
1640
1641 r = parse_boolean(s);
1642 if (r > 0)
1643 return PROTECT_HOME_YES;
1644 if (r == 0)
1645 return PROTECT_HOME_NO;
1646
1647 return protect_home_from_string(s);
1648 }
1649
1650 static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
1651 [PROTECT_SYSTEM_NO] = "no",
1652 [PROTECT_SYSTEM_YES] = "yes",
1653 [PROTECT_SYSTEM_FULL] = "full",
1654 [PROTECT_SYSTEM_STRICT] = "strict",
1655 };
1656
1657 DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);
1658
1659 ProtectSystem parse_protect_system_or_bool(const char *s) {
1660 int r;
1661
1662 r = parse_boolean(s);
1663 if (r > 0)
1664 return PROTECT_SYSTEM_YES;
1665 if (r == 0)
1666 return PROTECT_SYSTEM_NO;
1667
1668 return protect_system_from_string(s);
1669 }
1670
1671 static const char* const namespace_type_table[] = {
1672 [NAMESPACE_MOUNT] = "mnt",
1673 [NAMESPACE_CGROUP] = "cgroup",
1674 [NAMESPACE_UTS] = "uts",
1675 [NAMESPACE_IPC] = "ipc",
1676 [NAMESPACE_USER] = "user",
1677 [NAMESPACE_PID] = "pid",
1678 [NAMESPACE_NET] = "net",
1679 };
1680
1681 DEFINE_STRING_TABLE_LOOKUP(namespace_type, NamespaceType);