1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
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.
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.
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/>.
25 #include <sys/mount.h>
30 #include "alloc-util.h"
31 #include "base-filesystem.h"
32 #include "dev-setup.h"
36 #include "loop-util.h"
37 #include "loopback-setup.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"
49 #include "umask-util.h"
50 #include "user-util.h"
53 #define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
55 typedef enum MountMode
{
56 /* This is ordered by priority! */
70 typedef struct MountEntry
{
71 const char *path_const
; /* Memory allocated on stack or static */
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_const' if we had to allocate memory */
77 const char *source_const
; /* The source path, for bind mounts */
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 },
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 },
109 /* ProtectKernelModules= option */
110 static const MountEntry protect_kernel_modules_table
[] = {
112 { "/lib/modules", INACCESSIBLE
, true },
114 { "/usr/lib/modules", INACCESSIBLE
, true },
118 * ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
119 * system should be protected by ProtectSystem=
121 static const MountEntry protect_home_read_only_table
[] = {
122 { "/home", READONLY
, true },
123 { "/run/user", READONLY
, true },
124 { "/root", READONLY
, true },
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 },
134 /* ProtectSystem=yes table */
135 static const MountEntry protect_system_yes_table
[] = {
136 { "/usr", READONLY
, false },
137 { "/boot", READONLY
, true },
138 { "/efi", READONLY
, true },
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 },
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).
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= */
167 static const char *mount_entry_path(const MountEntry
*p
) {
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. */
173 return p
->path_malloc
?: p
->path_const
;
176 static bool mount_entry_read_only(const MountEntry
*p
) {
179 return p
->read_only
|| IN_SET(p
->mode
, READONLY
, INACCESSIBLE
);
182 static const char *mount_entry_source(const MountEntry
*p
) {
185 return p
->source_malloc
?: p
->source_const
;
188 static void mount_entry_done(MountEntry
*p
) {
191 p
->path_malloc
= mfree(p
->path_malloc
);
192 p
->source_malloc
= mfree(p
->source_malloc
);
195 static int append_access_mounts(MountEntry
**p
, char **strv
, MountMode mode
, bool forcibly_require_prefix
) {
200 /* Adds a list of user-supplied READWRITE/READONLY/INACCESSIBLE entries */
202 STRV_FOREACH(i
, strv
) {
203 bool ignore
= false, needs_prefix
= false;
206 /* Look for any prefixes */
207 if (startswith(e
, "-")) {
211 if (startswith(e
, "+")) {
216 if (!path_is_absolute(e
))
219 *((*p
)++) = (MountEntry
) {
223 .has_prefix
= !needs_prefix
&& !forcibly_require_prefix
,
230 static int append_empty_dir_mounts(MountEntry
**p
, char **strv
) {
235 /* Adds tmpfs mounts to provide readable but empty directories. This is primarily used to implement the
236 * "/private/" boundary directories for DynamicUser=1. */
238 STRV_FOREACH(i
, strv
) {
240 *((*p
)++) = (MountEntry
) {
252 static int append_bind_mounts(MountEntry
**p
, const BindMount
*binds
, unsigned n
) {
257 for (i
= 0; i
< n
; i
++) {
258 const BindMount
*b
= binds
+ i
;
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
,
271 static int append_static_mounts(MountEntry
**p
, const MountEntry
*mounts
, unsigned n
, bool ignore_protect
) {
277 /* Adds a list of static pre-defined entries */
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
,
289 static int append_protect_home(MountEntry
**p
, ProtectHome protect_home
, bool ignore_protect
) {
292 switch (protect_home
) {
294 case PROTECT_HOME_NO
:
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
);
300 case PROTECT_HOME_YES
:
301 return append_static_mounts(p
, protect_home_yes_table
, ELEMENTSOF(protect_home_yes_table
), ignore_protect
);
304 assert_not_reached("Unexpected ProtectHome= value");
308 static int append_protect_system(MountEntry
**p
, ProtectSystem protect_system
, bool ignore_protect
) {
311 switch (protect_system
) {
313 case PROTECT_SYSTEM_NO
:
316 case PROTECT_SYSTEM_STRICT
:
317 return append_static_mounts(p
, protect_system_strict_table
, ELEMENTSOF(protect_system_strict_table
), ignore_protect
);
319 case PROTECT_SYSTEM_YES
:
320 return append_static_mounts(p
, protect_system_yes_table
, ELEMENTSOF(protect_system_yes_table
), ignore_protect
);
322 case PROTECT_SYSTEM_FULL
:
323 return append_static_mounts(p
, protect_system_full_table
, ELEMENTSOF(protect_system_full_table
), ignore_protect
);
326 assert_not_reached("Unexpected ProtectSystem= value");
330 static int mount_path_compare(const void *a
, const void *b
) {
331 const MountEntry
*p
= a
, *q
= b
;
334 /* If the paths are not equal, then order prefixes first */
335 d
= path_compare(mount_entry_path(p
), mount_entry_path(q
));
339 /* If the paths are equal, check the mode */
340 if (p
->mode
< q
->mode
)
343 if (p
->mode
> q
->mode
)
349 static int prefix_where_needed(MountEntry
*m
, unsigned n
, const char *root_directory
) {
352 /* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
358 for (i
= 0; i
< n
; i
++) {
364 s
= prefix_root(root_directory
, mount_entry_path(m
+i
));
368 free(m
[i
].path_malloc
);
369 m
[i
].path_malloc
= s
;
371 m
[i
].has_prefix
= true;
377 static void drop_duplicates(MountEntry
*m
, unsigned *n
) {
378 MountEntry
*f
, *t
, *previous
;
383 /* Drops duplicate entries. Expects that the array is properly ordered already. */
385 for (f
= m
, t
= m
, previous
= NULL
; f
< m
+ *n
; f
++) {
387 /* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
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 */
404 static void drop_inaccessible(MountEntry
*m
, unsigned *n
) {
406 const char *clear
= NULL
;
411 /* Drops all entries obstructed by another entry further up the tree. Expects that the array is properly
412 * ordered already. */
414 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
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
);
424 clear
= f
->mode
== INACCESSIBLE
? mount_entry_path(f
) : NULL
;
433 static void drop_nop(MountEntry
*m
, unsigned *n
) {
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. */
442 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
444 /* Only suppress such subtrees for READONLY and READWRITE entries */
445 if (IN_SET(f
->mode
, READONLY
, READWRITE
)) {
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
))) {
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
));
472 static void drop_outside_root(const char *root_directory
, MountEntry
*m
, unsigned *n
) {
482 /* Drops all mounts that are outside of the root directory. */
484 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
486 if (!path_startswith(mount_entry_path(f
), root_directory
)) {
487 log_debug("%s is outside of root directory.", mount_entry_path(f
));
499 static int clone_device_node(const char *d
, const char *temporary_mount
) {
504 if (stat(d
, &st
) < 0) {
510 if (!S_ISBLK(st
.st_mode
) &&
511 !S_ISCHR(st
.st_mode
))
517 dn
= strjoina(temporary_mount
, d
);
519 mac_selinux_create_file_prepare(d
, st
.st_mode
);
520 r
= mknod(dn
, st
.st_mode
, st
.st_rdev
);
521 mac_selinux_create_file_clear();
523 return log_debug_errno(errno
, "mknod failed for %s: %m", d
);
528 static int mount_private_dev(MountEntry
*m
) {
529 static const char devnodes
[] =
537 char temporary_mount
[] = "/tmp/namespace-dev-XXXXXX";
538 const char *d
, *dev
= NULL
, *devpts
= NULL
, *devshm
= NULL
, *devhugepages
= NULL
, *devmqueue
= NULL
, *devlog
= NULL
, *devptmx
= NULL
;
539 _cleanup_umask_ mode_t u
;
546 if (!mkdtemp(temporary_mount
))
549 dev
= strjoina(temporary_mount
, "/dev");
550 (void) mkdir(dev
, 0755);
551 if (mount("tmpfs", dev
, "tmpfs", DEV_MOUNT_OPTIONS
, "mode=755") < 0) {
556 devpts
= strjoina(temporary_mount
, "/dev/pts");
557 (void) mkdir(devpts
, 0755);
558 if (mount("/dev/pts", devpts
, NULL
, MS_BIND
, NULL
) < 0) {
563 /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx
564 * when /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible
565 * thus, in that case make a clone
567 * in nspawn and other containers it will be a symlink, in that case make it a symlink
569 r
= is_symlink("/dev/ptmx");
573 devptmx
= strjoina(temporary_mount
, "/dev/ptmx");
574 if (symlink("pts/ptmx", devptmx
) < 0) {
579 r
= clone_device_node("/dev/ptmx", temporary_mount
);
588 devshm
= strjoina(temporary_mount
, "/dev/shm");
589 (void) mkdir(devshm
, 0755);
590 r
= mount("/dev/shm", devshm
, NULL
, MS_BIND
, NULL
);
596 devmqueue
= strjoina(temporary_mount
, "/dev/mqueue");
597 (void) mkdir(devmqueue
, 0755);
598 (void) mount("/dev/mqueue", devmqueue
, NULL
, MS_BIND
, NULL
);
600 devhugepages
= strjoina(temporary_mount
, "/dev/hugepages");
601 (void) mkdir(devhugepages
, 0755);
602 (void) mount("/dev/hugepages", devhugepages
, NULL
, MS_BIND
, NULL
);
604 devlog
= strjoina(temporary_mount
, "/dev/log");
605 (void) symlink("/run/systemd/journal/dev-log", devlog
);
607 NULSTR_FOREACH(d
, devnodes
) {
608 r
= clone_device_node(d
, temporary_mount
);
613 dev_setup(temporary_mount
, UID_INVALID
, GID_INVALID
);
615 /* Create the /dev directory if missing. It is more likely to be
616 * missing when the service is started with RootDirectory. This is
617 * consistent with mount units creating the mount points when missing.
619 (void) mkdir_p_label(mount_entry_path(m
), 0755);
621 /* Unmount everything in old /dev */
622 umount_recursive(mount_entry_path(m
), 0);
623 if (mount(dev
, mount_entry_path(m
), NULL
, MS_MOVE
, NULL
) < 0) {
629 rmdir(temporary_mount
);
641 umount(devhugepages
);
648 rmdir(temporary_mount
);
653 static int mount_bind_dev(const MountEntry
*m
) {
658 /* Implements the little brother of mount_private_dev(): simply bind mounts the host's /dev into the service's
659 * /dev. This is only used when RootDirectory= is set. */
661 (void) mkdir_p_label(mount_entry_path(m
), 0755);
663 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 0);
665 return log_debug_errno(r
, "Unable to determine whether /dev is already mounted: %m");
666 if (r
> 0) /* make this a NOP if /dev is already a mount point */
669 if (mount("/dev", mount_entry_path(m
), NULL
, MS_BIND
|MS_REC
, NULL
) < 0)
670 return log_debug_errno(errno
, "Failed to bind mount %s: %m", mount_entry_path(m
));
675 static int mount_sysfs(const MountEntry
*m
) {
680 (void) mkdir_p_label(mount_entry_path(m
), 0755);
682 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 0);
684 return log_debug_errno(r
, "Unable to determine whether /sys is already mounted: %m");
685 if (r
> 0) /* make this a NOP if /sys is already a mount point */
688 /* Bind mount the host's version so that we get all child mounts of it, too. */
689 if (mount("/sys", mount_entry_path(m
), NULL
, MS_BIND
|MS_REC
, NULL
) < 0)
690 return log_debug_errno(errno
, "Failed to mount %s: %m", mount_entry_path(m
));
695 static int mount_procfs(const MountEntry
*m
) {
700 (void) mkdir_p_label(mount_entry_path(m
), 0755);
702 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 0);
704 return log_debug_errno(r
, "Unable to determine whether /proc is already mounted: %m");
705 if (r
> 0) /* make this a NOP if /proc is already a mount point */
708 /* Mount a new instance, so that we get the one that matches our user namespace, if we are running in one */
709 if (mount("proc", mount_entry_path(m
), "proc", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, NULL
) < 0)
710 return log_debug_errno(errno
, "Failed to mount %s: %m", mount_entry_path(m
));
715 static int mount_empty_dir(const MountEntry
*m
) {
718 /* First, get rid of everything that is below if there is anything. Then, overmount with our new empty dir */
720 (void) mkdir_p_label(mount_entry_path(m
), 0755);
721 (void) umount_recursive(mount_entry_path(m
), 0);
723 if (mount("tmpfs", mount_entry_path(m
), "tmpfs", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
|MS_STRICTATIME
, "mode=755") < 0)
724 return log_debug_errno(errno
, "Failed to mount %s: %m", mount_entry_path(m
));
729 static int mount_entry_chase(
730 const char *root_directory
,
741 /* Since mount() will always follow symlinks and we need to take the different root directory into account we
742 * chase the symlinks on our own first. This is called for the destination path, as well as the source path (if
743 * that applies). The result is stored in "location". */
747 BIND_MOUNT_RECURSIVE
,
754 flags
|= CHASE_NONEXISTENT
;
756 r
= chase_symlinks(path
, root_directory
, flags
, &chased
);
757 if (r
== -ENOENT
&& m
->ignore
) {
758 log_debug_errno(r
, "Path %s does not exist, ignoring.", path
);
762 return log_debug_errno(r
, "Failed to follow symlinks on %s: %m", path
);
764 log_debug("Followed symlinks %s → %s.", path
, chased
);
772 static int apply_mount(
773 const char *root_directory
,
776 bool rbind
= true, make
= false;
782 r
= mount_entry_chase(root_directory
, m
, mount_entry_path(m
), &m
->path_malloc
);
786 log_debug("Applying namespace mount on %s", mount_entry_path(m
));
793 /* First, get rid of everything that is below if there
794 * is anything... Then, overmount it with an
795 * inaccessible path. */
796 (void) umount_recursive(mount_entry_path(m
), 0);
798 if (lstat(mount_entry_path(m
), &target
) < 0)
799 return log_debug_errno(errno
, "Failed to lstat() %s to determine what to mount over it: %m", mount_entry_path(m
));
801 what
= mode_to_inaccessible_node(target
.st_mode
);
803 log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed");
811 r
= path_is_mount_point(mount_entry_path(m
), root_directory
, 0);
813 return log_debug_errno(r
, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m
));
814 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. */
816 /* This isn't a mount point yet, let's make it one. */
817 what
= mount_entry_path(m
);
824 case BIND_MOUNT_RECURSIVE
:
825 /* Also chase the source mount */
827 r
= mount_entry_chase(root_directory
, m
, mount_entry_source(m
), &m
->source_malloc
);
831 what
= mount_entry_source(m
);
836 return mount_empty_dir(m
);
839 what
= mount_entry_source(m
);
844 return mount_private_dev(m
);
847 return mount_bind_dev(m
);
850 return mount_sysfs(m
);
853 return mount_procfs(m
);
856 assert_not_reached("Unknown mode");
861 if (mount(what
, mount_entry_path(m
), NULL
, MS_BIND
|(rbind
? MS_REC
: 0), NULL
) < 0) {
862 bool try_again
= false;
865 if (r
== -ENOENT
&& make
) {
868 /* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
870 if (stat(what
, &st
) >= 0) {
872 (void) mkdir_parents(mount_entry_path(m
), 0755);
874 if (S_ISDIR(st
.st_mode
))
875 try_again
= mkdir(mount_entry_path(m
), 0755) >= 0;
877 try_again
= touch(mount_entry_path(m
)) >= 0;
882 if (mount(what
, mount_entry_path(m
), NULL
, MS_BIND
|(rbind
? MS_REC
: 0), NULL
) < 0)
889 return log_debug_errno(r
, "Failed to mount %s to %s: %m", what
, mount_entry_path(m
));
892 log_debug("Successfully mounted %s to %s", what
, mount_entry_path(m
));
896 static int make_read_only(const MountEntry
*m
, char **blacklist
, FILE *proc_self_mountinfo
) {
900 assert(proc_self_mountinfo
);
902 if (mount_entry_read_only(m
))
903 r
= bind_remount_recursive_with_mountinfo(mount_entry_path(m
), true, blacklist
, proc_self_mountinfo
);
904 else if (m
->mode
== PRIVATE_DEV
) { /* Superblock can be readonly but the submounts can't */
905 if (mount(NULL
, mount_entry_path(m
), NULL
, MS_REMOUNT
|DEV_MOUNT_OPTIONS
|MS_RDONLY
, NULL
) < 0)
910 /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked read-only
911 * already stays this way. This improves compatibility with container managers, where we won't attempt to undo
912 * read-only mounts already applied. */
914 if (r
== -ENOENT
&& m
->ignore
)
920 static bool namespace_info_mount_apivfs(const char *root_directory
, const NamespaceInfo
*ns_info
) {
924 * ProtectControlGroups= and ProtectKernelTunables= imply MountAPIVFS=,
925 * since to protect the API VFS mounts, they need to be around in the
926 * first place... and RootDirectory= or RootImage= need to be set.
929 /* root_directory should point to a mount point */
930 return root_directory
&&
931 (ns_info
->mount_apivfs
||
932 ns_info
->protect_control_groups
||
933 ns_info
->protect_kernel_tunables
);
936 static unsigned namespace_calculate_mounts(
937 const char* root_directory
,
938 const NamespaceInfo
*ns_info
,
939 char** read_write_paths
,
940 char** read_only_paths
,
941 char** inaccessible_paths
,
942 char** empty_directories
,
943 const BindMount
*bind_mounts
,
944 unsigned n_bind_mounts
,
946 const char* var_tmp_dir
,
947 ProtectHome protect_home
,
948 ProtectSystem protect_system
) {
950 unsigned protect_home_cnt
;
951 unsigned protect_system_cnt
=
952 (protect_system
== PROTECT_SYSTEM_STRICT
?
953 ELEMENTSOF(protect_system_strict_table
) :
954 ((protect_system
== PROTECT_SYSTEM_FULL
) ?
955 ELEMENTSOF(protect_system_full_table
) :
956 ((protect_system
== PROTECT_SYSTEM_YES
) ?
957 ELEMENTSOF(protect_system_yes_table
) : 0)));
960 (protect_home
== PROTECT_HOME_YES
?
961 ELEMENTSOF(protect_home_yes_table
) :
962 ((protect_home
== PROTECT_HOME_READ_ONLY
) ?
963 ELEMENTSOF(protect_home_read_only_table
) : 0));
965 return !!tmp_dir
+ !!var_tmp_dir
+
966 strv_length(read_write_paths
) +
967 strv_length(read_only_paths
) +
968 strv_length(inaccessible_paths
) +
969 strv_length(empty_directories
) +
971 ns_info
->private_dev
+
972 (ns_info
->protect_kernel_tunables
? ELEMENTSOF(protect_kernel_tunables_table
) : 0) +
973 (ns_info
->protect_control_groups
? 1 : 0) +
974 (ns_info
->protect_kernel_modules
? ELEMENTSOF(protect_kernel_modules_table
) : 0) +
975 protect_home_cnt
+ protect_system_cnt
+
976 (namespace_info_mount_apivfs(root_directory
, ns_info
) ? ELEMENTSOF(apivfs_table
) : 0);
980 const char* root_directory
,
981 const char* root_image
,
982 const NamespaceInfo
*ns_info
,
983 char** read_write_paths
,
984 char** read_only_paths
,
985 char** inaccessible_paths
,
986 char** empty_directories
,
987 const BindMount
*bind_mounts
,
988 unsigned n_bind_mounts
,
990 const char* var_tmp_dir
,
991 ProtectHome protect_home
,
992 ProtectSystem protect_system
,
993 unsigned long mount_flags
,
994 DissectImageFlags dissect_image_flags
) {
996 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
997 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*decrypted_image
= NULL
;
998 _cleanup_(dissected_image_unrefp
) DissectedImage
*dissected_image
= NULL
;
999 _cleanup_free_
void *root_hash
= NULL
;
1000 MountEntry
*m
, *mounts
= NULL
;
1001 size_t root_hash_size
= 0;
1002 bool make_slave
= false;
1005 bool require_prefix
= false;
1010 if (mount_flags
== 0)
1011 mount_flags
= MS_SHARED
;
1014 dissect_image_flags
|= DISSECT_IMAGE_REQUIRE_ROOT
;
1016 if (protect_system
== PROTECT_SYSTEM_STRICT
&& strv_isempty(read_write_paths
))
1017 dissect_image_flags
|= DISSECT_IMAGE_READ_ONLY
;
1019 r
= loop_device_make_by_path(root_image
,
1020 dissect_image_flags
& DISSECT_IMAGE_READ_ONLY
? O_RDONLY
: O_RDWR
,
1025 r
= root_hash_load(root_image
, &root_hash
, &root_hash_size
);
1029 r
= dissect_image(loop_device
->fd
, root_hash
, root_hash_size
, dissect_image_flags
, &dissected_image
);
1033 r
= dissected_image_decrypt(dissected_image
, NULL
, root_hash
, root_hash_size
, dissect_image_flags
, &decrypted_image
);
1039 root
= root_directory
;
1040 else if (root_image
|| n_bind_mounts
> 0) {
1042 /* If we are booting from an image, create a mount point for the image, if it's still missing. We use
1043 * the same mount point for all images, which is safe, since they all live in their own namespaces
1044 * after all, and hence won't see each other. We also use such a root directory whenever there are bind
1045 * mounts configured, so that their source mounts are never obstructed by mounts we already applied
1046 * while we are applying them. */
1048 root
= "/run/systemd/unit-root";
1049 (void) mkdir_label(root
, 0700);
1050 require_prefix
= true;
1054 n_mounts
= namespace_calculate_mounts(
1061 bind_mounts
, n_bind_mounts
,
1062 tmp_dir
, var_tmp_dir
,
1063 protect_home
, protect_system
);
1065 /* Set mount slave mode */
1066 if (root
|| n_mounts
> 0)
1070 m
= mounts
= (MountEntry
*) alloca0(n_mounts
* sizeof(MountEntry
));
1071 r
= append_access_mounts(&m
, read_write_paths
, READWRITE
, require_prefix
);
1075 r
= append_access_mounts(&m
, read_only_paths
, READONLY
, require_prefix
);
1079 r
= append_access_mounts(&m
, inaccessible_paths
, INACCESSIBLE
, require_prefix
);
1083 r
= append_empty_dir_mounts(&m
, empty_directories
);
1087 r
= append_bind_mounts(&m
, bind_mounts
, n_bind_mounts
);
1092 *(m
++) = (MountEntry
) {
1093 .path_const
= "/tmp",
1094 .mode
= PRIVATE_TMP
,
1095 .source_const
= tmp_dir
,
1100 *(m
++) = (MountEntry
) {
1101 .path_const
= "/var/tmp",
1102 .mode
= PRIVATE_TMP
,
1103 .source_const
= var_tmp_dir
,
1107 if (ns_info
->private_dev
) {
1108 *(m
++) = (MountEntry
) {
1109 .path_const
= "/dev",
1110 .mode
= PRIVATE_DEV
,
1114 if (ns_info
->protect_kernel_tunables
) {
1115 r
= append_static_mounts(&m
, protect_kernel_tunables_table
, ELEMENTSOF(protect_kernel_tunables_table
), ns_info
->ignore_protect_paths
);
1120 if (ns_info
->protect_kernel_modules
) {
1121 r
= append_static_mounts(&m
, protect_kernel_modules_table
, ELEMENTSOF(protect_kernel_modules_table
), ns_info
->ignore_protect_paths
);
1126 if (ns_info
->protect_control_groups
) {
1127 *(m
++) = (MountEntry
) {
1128 .path_const
= "/sys/fs/cgroup",
1133 r
= append_protect_home(&m
, protect_home
, ns_info
->ignore_protect_paths
);
1137 r
= append_protect_system(&m
, protect_system
, false);
1141 if (namespace_info_mount_apivfs(root
, ns_info
)) {
1142 r
= append_static_mounts(&m
, apivfs_table
, ELEMENTSOF(apivfs_table
), ns_info
->ignore_protect_paths
);
1147 assert(mounts
+ n_mounts
== m
);
1149 /* Prepend the root directory where that's necessary */
1150 r
= prefix_where_needed(mounts
, n_mounts
, root
);
1154 qsort(mounts
, n_mounts
, sizeof(MountEntry
), mount_path_compare
);
1156 drop_duplicates(mounts
, &n_mounts
);
1157 drop_outside_root(root
, mounts
, &n_mounts
);
1158 drop_inaccessible(mounts
, &n_mounts
);
1159 drop_nop(mounts
, &n_mounts
);
1162 if (unshare(CLONE_NEWNS
) < 0) {
1168 /* Remount / as SLAVE so that nothing now mounted in the namespace
1169 shows up in the parent */
1170 if (mount(NULL
, "/", NULL
, MS_SLAVE
|MS_REC
, NULL
) < 0) {
1177 /* A root image is specified, mount it to the right place */
1178 r
= dissected_image_mount(dissected_image
, root
, UID_INVALID
, dissect_image_flags
);
1182 if (decrypted_image
) {
1183 r
= decrypted_image_relinquish(decrypted_image
);
1188 loop_device_relinquish(loop_device
);
1190 } else if (root_directory
) {
1192 /* A root directory is specified. Turn its directory into bind mount, if it isn't one yet. */
1193 r
= path_is_mount_point(root
, NULL
, AT_SYMLINK_FOLLOW
);
1197 if (mount(root
, root
, NULL
, MS_BIND
|MS_REC
, NULL
) < 0) {
1205 /* Let's mount the main root directory to the root directory to use */
1206 if (mount("/", root
, NULL
, MS_BIND
|MS_REC
, NULL
) < 0) {
1212 /* Try to set up the new root directory before mounting anything else there. */
1213 if (root_image
|| root_directory
)
1214 (void) base_filesystem_create(root
, UID_INVALID
, GID_INVALID
);
1217 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
1221 /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
1222 * For example, this is the case with the option: 'InaccessiblePaths=/proc' */
1223 proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re");
1224 if (!proc_self_mountinfo
) {
1229 /* First round, add in all special mounts we need */
1230 for (m
= mounts
; m
< mounts
+ n_mounts
; ++m
) {
1231 r
= apply_mount(root
, m
);
1236 /* Create a blacklist we can pass to bind_mount_recursive() */
1237 blacklist
= newa(char*, n_mounts
+1);
1238 for (j
= 0; j
< n_mounts
; j
++)
1239 blacklist
[j
] = (char*) mount_entry_path(mounts
+j
);
1240 blacklist
[j
] = NULL
;
1242 /* Second round, flip the ro bits if necessary. */
1243 for (m
= mounts
; m
< mounts
+ n_mounts
; ++m
) {
1244 r
= make_read_only(m
, blacklist
, proc_self_mountinfo
);
1251 /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
1252 r
= mount_move_root(root
);
1257 /* Remount / as the desired mode. Note that this will not
1258 * reestablish propagation from our side to the host, since
1259 * what's disconnected is disconnected. */
1260 if (mount(NULL
, "/", NULL
, mount_flags
| MS_REC
, NULL
) < 0) {
1268 for (m
= mounts
; m
< mounts
+ n_mounts
; m
++)
1269 mount_entry_done(m
);
1274 void bind_mount_free_many(BindMount
*b
, unsigned n
) {
1277 assert(b
|| n
== 0);
1279 for (i
= 0; i
< n
; i
++) {
1281 free(b
[i
].destination
);
1287 int bind_mount_add(BindMount
**b
, unsigned *n
, const BindMount
*item
) {
1288 _cleanup_free_
char *s
= NULL
, *d
= NULL
;
1295 s
= strdup(item
->source
);
1299 d
= strdup(item
->destination
);
1303 c
= realloc_multiply(*b
, sizeof(BindMount
), *n
+ 1);
1309 c
[(*n
) ++] = (BindMount
) {
1312 .read_only
= item
->read_only
,
1313 .recursive
= item
->recursive
,
1314 .ignore_enoent
= item
->ignore_enoent
,
1321 static int setup_one_tmp_dir(const char *id
, const char *prefix
, char **path
) {
1322 _cleanup_free_
char *x
= NULL
;
1323 char bid
[SD_ID128_STRING_MAX
];
1331 /* We include the boot id in the directory so that after a
1332 * reboot we can easily identify obsolete directories. */
1334 r
= sd_id128_get_boot(&boot_id
);
1338 x
= strjoin(prefix
, "/systemd-private-", sd_id128_to_string(boot_id
, bid
), "-", id
, "-XXXXXX");
1342 RUN_WITH_UMASK(0077)
1346 RUN_WITH_UMASK(0000) {
1349 y
= strjoina(x
, "/tmp");
1351 if (mkdir(y
, 0777 | S_ISVTX
) < 0)
1361 int setup_tmp_dirs(const char *id
, char **tmp_dir
, char **var_tmp_dir
) {
1367 assert(var_tmp_dir
);
1369 r
= setup_one_tmp_dir(id
, "/tmp", &a
);
1373 r
= setup_one_tmp_dir(id
, "/var/tmp", &b
);
1377 t
= strjoina(a
, "/tmp");
1391 int setup_netns(int netns_storage_socket
[2]) {
1392 _cleanup_close_
int netns
= -1;
1395 assert(netns_storage_socket
);
1396 assert(netns_storage_socket
[0] >= 0);
1397 assert(netns_storage_socket
[1] >= 0);
1399 /* We use the passed socketpair as a storage buffer for our
1400 * namespace reference fd. Whatever process runs this first
1401 * shall create a new namespace, all others should just join
1402 * it. To serialize that we use a file lock on the socket
1405 * It's a bit crazy, but hey, works great! */
1407 if (lockf(netns_storage_socket
[0], F_LOCK
, 0) < 0)
1410 netns
= receive_one_fd(netns_storage_socket
[0], MSG_DONTWAIT
);
1411 if (netns
== -EAGAIN
) {
1412 /* Nothing stored yet, so let's create a new namespace */
1414 if (unshare(CLONE_NEWNET
) < 0) {
1421 netns
= open("/proc/self/ns/net", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1429 } else if (netns
< 0) {
1434 /* Yay, found something, so let's join the namespace */
1435 if (setns(netns
, CLONE_NEWNET
) < 0) {
1443 q
= send_one_fd(netns_storage_socket
[1], netns
, MSG_DONTWAIT
);
1450 (void) lockf(netns_storage_socket
[0], F_ULOCK
, 0);
1454 bool ns_type_supported(NamespaceType type
) {
1455 const char *t
, *ns_proc
;
1457 t
= namespace_type_to_string(type
);
1458 if (!t
) /* Don't know how to translate this? Then it's not supported */
1461 ns_proc
= strjoina("/proc/self/ns/", t
);
1462 return access(ns_proc
, F_OK
) == 0;
1465 static const char *const protect_home_table
[_PROTECT_HOME_MAX
] = {
1466 [PROTECT_HOME_NO
] = "no",
1467 [PROTECT_HOME_YES
] = "yes",
1468 [PROTECT_HOME_READ_ONLY
] = "read-only",
1471 DEFINE_STRING_TABLE_LOOKUP(protect_home
, ProtectHome
);
1473 ProtectHome
parse_protect_home_or_bool(const char *s
) {
1476 r
= parse_boolean(s
);
1478 return PROTECT_HOME_YES
;
1480 return PROTECT_HOME_NO
;
1482 return protect_home_from_string(s
);
1485 static const char *const protect_system_table
[_PROTECT_SYSTEM_MAX
] = {
1486 [PROTECT_SYSTEM_NO
] = "no",
1487 [PROTECT_SYSTEM_YES
] = "yes",
1488 [PROTECT_SYSTEM_FULL
] = "full",
1489 [PROTECT_SYSTEM_STRICT
] = "strict",
1492 DEFINE_STRING_TABLE_LOOKUP(protect_system
, ProtectSystem
);
1494 ProtectSystem
parse_protect_system_or_bool(const char *s
) {
1497 r
= parse_boolean(s
);
1499 return PROTECT_SYSTEM_YES
;
1501 return PROTECT_SYSTEM_NO
;
1503 return protect_system_from_string(s
);
1506 static const char* const namespace_type_table
[] = {
1507 [NAMESPACE_MOUNT
] = "mnt",
1508 [NAMESPACE_CGROUP
] = "cgroup",
1509 [NAMESPACE_UTS
] = "uts",
1510 [NAMESPACE_IPC
] = "ipc",
1511 [NAMESPACE_USER
] = "user",
1512 [NAMESPACE_PID
] = "pid",
1513 [NAMESPACE_NET
] = "net",
1516 DEFINE_STRING_TABLE_LOOKUP(namespace_type
, NamespaceType
);