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