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! */
71 typedef struct MountEntry
{
72 const char *path_const
; /* Memory allocated on stack or static */
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 */
80 const char *options_const
;/* Mount options for tmpfs */
82 unsigned long flags
; /* Mount flags used by EMPTY_DIR and TMPFS. Do not include MS_RDONLY here, but please use read_only. */
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 },
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 },
114 /* ProtectKernelModules= option */
115 static const MountEntry protect_kernel_modules_table
[] = {
117 { "/lib/modules", INACCESSIBLE
, true },
119 { "/usr/lib/modules", INACCESSIBLE
, true },
123 * ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
124 * system should be protected by ProtectSystem=
126 static const MountEntry protect_home_read_only_table
[] = {
127 { "/home", READONLY
, true },
128 { "/run/user", READONLY
, true },
129 { "/root", READONLY
, true },
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
},
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 },
146 /* ProtectSystem=yes table */
147 static const MountEntry protect_system_yes_table
[] = {
148 { "/usr", READONLY
, false },
149 { "/boot", READONLY
, true },
150 { "/efi", READONLY
, true },
152 { "/lib", READONLY
, true },
153 { "/lib64", READONLY
, true },
154 { "/bin", READONLY
, true },
156 { "/sbin", READONLY
, true },
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 },
168 { "/lib", READONLY
, true },
169 { "/lib64", READONLY
, true },
170 { "/bin", READONLY
, true },
172 { "/sbin", READONLY
, true },
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).
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= */
195 static const char *mount_entry_path(const MountEntry
*p
) {
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. */
201 return p
->path_malloc
?: p
->path_const
;
204 static bool mount_entry_read_only(const MountEntry
*p
) {
207 return p
->read_only
|| IN_SET(p
->mode
, READONLY
, INACCESSIBLE
);
210 static const char *mount_entry_source(const MountEntry
*p
) {
213 return p
->source_malloc
?: p
->source_const
;
216 static const char *mount_entry_options(const MountEntry
*p
) {
219 return p
->options_malloc
?: p
->options_const
;
222 static void mount_entry_done(MountEntry
*p
) {
225 p
->path_malloc
= mfree(p
->path_malloc
);
226 p
->source_malloc
= mfree(p
->source_malloc
);
227 p
->options_malloc
= mfree(p
->options_malloc
);
230 static int append_access_mounts(MountEntry
**p
, char **strv
, MountMode mode
, bool forcibly_require_prefix
) {
235 /* Adds a list of user-supplied READWRITE/READONLY/INACCESSIBLE entries */
237 STRV_FOREACH(i
, strv
) {
238 bool ignore
= false, needs_prefix
= false;
241 /* Look for any prefixes */
242 if (startswith(e
, "-")) {
246 if (startswith(e
, "+")) {
251 if (!path_is_absolute(e
))
254 *((*p
)++) = (MountEntry
) {
258 .has_prefix
= !needs_prefix
&& !forcibly_require_prefix
,
265 static int append_empty_dir_mounts(MountEntry
**p
, char **strv
) {
270 /* Adds tmpfs mounts to provide readable but empty directories. This is primarily used to implement the
271 * "/private/" boundary directories for DynamicUser=1. */
273 STRV_FOREACH(i
, strv
) {
275 *((*p
)++) = (MountEntry
) {
281 .options_const
= "mode=755",
282 .flags
= MS_NOSUID
|MS_NOEXEC
|MS_NODEV
|MS_STRICTATIME
,
289 static int append_bind_mounts(MountEntry
**p
, const BindMount
*binds
, unsigned n
) {
294 for (i
= 0; i
< n
; i
++) {
295 const BindMount
*b
= binds
+ i
;
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
,
309 static int append_tmpfs_mounts(MountEntry
**p
, const TemporaryFileSystem
*tmpfs
, unsigned n
) {
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
;
321 if (!path_is_absolute(t
->path
))
324 if (!isempty(t
->options
)) {
325 str
= strjoin("mode=0755,", t
->options
);
329 r
= mount_option_mangle(str
, MS_NODEV
|MS_STRICTATIME
, &flags
, &o
);
333 ro
= !!(flags
& MS_RDONLY
);
338 *((*p
)++) = (MountEntry
) {
339 .path_const
= t
->path
,
352 static int append_static_mounts(MountEntry
**p
, const MountEntry
*mounts
, unsigned n
, bool ignore_protect
) {
358 /* Adds a list of static pre-defined entries */
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
,
370 static int append_protect_home(MountEntry
**p
, ProtectHome protect_home
, bool ignore_protect
) {
373 switch (protect_home
) {
375 case PROTECT_HOME_NO
:
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
);
381 case PROTECT_HOME_TMPFS
:
382 return append_static_mounts(p
, protect_home_tmpfs_table
, ELEMENTSOF(protect_home_tmpfs_table
), ignore_protect
);
384 case PROTECT_HOME_YES
:
385 return append_static_mounts(p
, protect_home_yes_table
, ELEMENTSOF(protect_home_yes_table
), ignore_protect
);
388 assert_not_reached("Unexpected ProtectHome= value");
392 static int append_protect_system(MountEntry
**p
, ProtectSystem protect_system
, bool ignore_protect
) {
395 switch (protect_system
) {
397 case PROTECT_SYSTEM_NO
:
400 case PROTECT_SYSTEM_STRICT
:
401 return append_static_mounts(p
, protect_system_strict_table
, ELEMENTSOF(protect_system_strict_table
), ignore_protect
);
403 case PROTECT_SYSTEM_YES
:
404 return append_static_mounts(p
, protect_system_yes_table
, ELEMENTSOF(protect_system_yes_table
), ignore_protect
);
406 case PROTECT_SYSTEM_FULL
:
407 return append_static_mounts(p
, protect_system_full_table
, ELEMENTSOF(protect_system_full_table
), ignore_protect
);
410 assert_not_reached("Unexpected ProtectSystem= value");
414 static int mount_path_compare(const void *a
, const void *b
) {
415 const MountEntry
*p
= a
, *q
= b
;
418 /* If the paths are not equal, then order prefixes first */
419 d
= path_compare(mount_entry_path(p
), mount_entry_path(q
));
423 /* If the paths are equal, check the mode */
424 if (p
->mode
< q
->mode
)
427 if (p
->mode
> q
->mode
)
433 static int prefix_where_needed(MountEntry
*m
, unsigned n
, const char *root_directory
) {
436 /* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
442 for (i
= 0; i
< n
; i
++) {
448 s
= prefix_root(root_directory
, mount_entry_path(m
+i
));
452 free_and_replace(m
[i
].path_malloc
, s
);
453 m
[i
].has_prefix
= true;
459 static void drop_duplicates(MountEntry
*m
, unsigned *n
) {
460 MountEntry
*f
, *t
, *previous
;
465 /* Drops duplicate entries. Expects that the array is properly ordered already. */
467 for (f
= m
, t
= m
, previous
= NULL
; f
< m
+ *n
; f
++) {
469 /* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
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 */
486 static void drop_inaccessible(MountEntry
*m
, unsigned *n
) {
488 const char *clear
= NULL
;
493 /* Drops all entries obstructed by another entry further up the tree. Expects that the array is properly
494 * ordered already. */
496 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
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
);
506 clear
= f
->mode
== INACCESSIBLE
? mount_entry_path(f
) : NULL
;
515 static void drop_nop(MountEntry
*m
, unsigned *n
) {
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. */
524 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
526 /* Only suppress such subtrees for READONLY and READWRITE entries */
527 if (IN_SET(f
->mode
, READONLY
, READWRITE
)) {
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
))) {
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
));
554 static void drop_outside_root(const char *root_directory
, MountEntry
*m
, unsigned *n
) {
564 /* Drops all mounts that are outside of the root directory. */
566 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
568 if (!path_startswith(mount_entry_path(f
), root_directory
)) {
569 log_debug("%s is outside of root directory.", mount_entry_path(f
));
581 static int clone_device_node(const char *d
, const char *temporary_mount
, bool *make_devnode
) {
586 if (stat(d
, &st
) < 0) {
592 if (!S_ISBLK(st
.st_mode
) &&
593 !S_ISCHR(st
.st_mode
))
599 dn
= strjoina(temporary_mount
, d
);
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();
609 return log_debug_errno(errno
, "mknod failed for %s: %m", d
);
611 *make_devnode
= false;
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();
620 if (r
< 0 && errno
!= EEXIST
)
621 return log_debug_errno(errno
, "mknod fallback failed for %s: %m", d
);
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
);
634 static int mount_private_dev(MountEntry
*m
) {
635 static const char devnodes
[] =
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
;
653 if (!mkdtemp(temporary_mount
))
656 dev
= strjoina(temporary_mount
, "/dev");
657 (void) mkdir(dev
, 0755);
658 if (mount("tmpfs", dev
, "tmpfs", DEV_MOUNT_OPTIONS
, "mode=755") < 0) {
663 devpts
= strjoina(temporary_mount
, "/dev/pts");
664 (void) mkdir(devpts
, 0755);
665 if (mount("/dev/pts", devpts
, NULL
, MS_BIND
, NULL
) < 0) {
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
674 * in nspawn and other containers it will be a symlink, in that case make it a symlink
676 r
= is_symlink("/dev/ptmx");
680 devptmx
= strjoina(temporary_mount
, "/dev/ptmx");
681 if (symlink("pts/ptmx", devptmx
) < 0) {
686 r
= clone_device_node("/dev/ptmx", temporary_mount
, &can_mknod
);
695 devshm
= strjoina(temporary_mount
, "/dev/shm");
696 (void) mkdir(devshm
, 0755);
697 r
= mount("/dev/shm", devshm
, NULL
, MS_BIND
, NULL
);
703 devmqueue
= strjoina(temporary_mount
, "/dev/mqueue");
704 (void) mkdir(devmqueue
, 0755);
705 (void) mount("/dev/mqueue", devmqueue
, NULL
, MS_BIND
, NULL
);
707 devhugepages
= strjoina(temporary_mount
, "/dev/hugepages");
708 (void) mkdir(devhugepages
, 0755);
709 (void) mount("/dev/hugepages", devhugepages
, NULL
, MS_BIND
, NULL
);
711 devlog
= strjoina(temporary_mount
, "/dev/log");
712 (void) symlink("/run/systemd/journal/dev-log", devlog
);
714 NULSTR_FOREACH(d
, devnodes
) {
715 r
= clone_device_node(d
, temporary_mount
, &can_mknod
);
720 dev_setup(temporary_mount
, UID_INVALID
, GID_INVALID
);
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.
726 (void) mkdir_p_label(mount_entry_path(m
), 0755);
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) {
736 rmdir(temporary_mount
);
748 umount(devhugepages
);
755 rmdir(temporary_mount
);
760 static int mount_bind_dev(const MountEntry
*m
) {
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. */
768 (void) mkdir_p_label(mount_entry_path(m
), 0755);
770 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 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 */
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
));
782 static int mount_sysfs(const MountEntry
*m
) {
787 (void) mkdir_p_label(mount_entry_path(m
), 0755);
789 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 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 */
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
));
802 static int mount_procfs(const MountEntry
*m
) {
807 (void) mkdir_p_label(mount_entry_path(m
), 0755);
809 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 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 */
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
));
822 static int mount_tmpfs(const MountEntry
*m
) {
825 /* First, get rid of everything that is below if there is anything. Then, overmount with our new tmpfs */
827 (void) mkdir_p_label(mount_entry_path(m
), 0755);
828 (void) umount_recursive(mount_entry_path(m
), 0);
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
));
836 static int mount_entry_chase(
837 const char *root_directory
,
840 bool chase_nonexistent
,
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". */
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
);
858 return log_debug_errno(r
, "Failed to follow symlinks on %s: %m", path
);
860 log_debug("Followed symlinks %s → %s.", path
, chased
);
868 static int apply_mount(
869 const char *root_directory
,
872 bool rbind
= true, make
= false;
878 r
= mount_entry_chase(root_directory
, m
, mount_entry_path(m
), !IN_SET(m
->mode
, INACCESSIBLE
, READONLY
, READWRITE
), &m
->path_malloc
);
882 log_debug("Applying namespace mount on %s", mount_entry_path(m
));
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);
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
));
897 what
= mode_to_inaccessible_node(target
.st_mode
);
899 log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed");
907 r
= path_is_mount_point(mount_entry_path(m
), root_directory
, 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. */
912 /* This isn't a mount point yet, let's make it one. */
913 what
= mount_entry_path(m
);
920 case BIND_MOUNT_RECURSIVE
:
921 /* Also chase the source mount */
923 r
= mount_entry_chase(root_directory
, m
, mount_entry_source(m
), false, &m
->source_malloc
);
927 what
= mount_entry_source(m
);
933 return mount_tmpfs(m
);
936 what
= mount_entry_source(m
);
941 return mount_private_dev(m
);
944 return mount_bind_dev(m
);
947 return mount_sysfs(m
);
950 return mount_procfs(m
);
953 assert_not_reached("Unknown mode");
958 if (mount(what
, mount_entry_path(m
), NULL
, MS_BIND
|(rbind
? MS_REC
: 0), NULL
) < 0) {
959 bool try_again
= false;
962 if (r
== -ENOENT
&& make
) {
965 /* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
967 if (stat(what
, &st
) >= 0) {
969 (void) mkdir_parents(mount_entry_path(m
), 0755);
971 if (S_ISDIR(st
.st_mode
))
972 try_again
= mkdir(mount_entry_path(m
), 0755) >= 0;
974 try_again
= touch(mount_entry_path(m
)) >= 0;
979 if (mount(what
, mount_entry_path(m
), NULL
, MS_BIND
|(rbind
? MS_REC
: 0), NULL
) < 0)
986 return log_debug_errno(r
, "Failed to mount %s to %s: %m", what
, mount_entry_path(m
));
989 log_debug("Successfully mounted %s to %s", what
, mount_entry_path(m
));
993 static int make_read_only(const MountEntry
*m
, char **blacklist
, FILE *proc_self_mountinfo
) {
997 assert(proc_self_mountinfo
);
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)
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)
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. */
1017 if (r
== -ENOENT
&& m
->ignore
)
1023 static bool namespace_info_mount_apivfs(const char *root_directory
, const NamespaceInfo
*ns_info
) {
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.
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
);
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
) {
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)));
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)));
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
) +
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);
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
) {
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;
1113 bool require_prefix
= false;
1118 if (mount_flags
== 0)
1119 mount_flags
= MS_SHARED
;
1122 dissect_image_flags
|= DISSECT_IMAGE_REQUIRE_ROOT
;
1124 if (protect_system
== PROTECT_SYSTEM_STRICT
&& strv_isempty(read_write_paths
))
1125 dissect_image_flags
|= DISSECT_IMAGE_READ_ONLY
;
1127 r
= loop_device_make_by_path(root_image
,
1128 dissect_image_flags
& DISSECT_IMAGE_READ_ONLY
? O_RDONLY
: O_RDWR
,
1133 r
= root_hash_load(root_image
, &root_hash
, &root_hash_size
);
1137 r
= dissect_image(loop_device
->fd
, root_hash
, root_hash_size
, dissect_image_flags
, &dissected_image
);
1141 r
= dissected_image_decrypt(dissected_image
, NULL
, root_hash
, root_hash_size
, dissect_image_flags
, &decrypted_image
);
1147 root
= root_directory
;
1148 else if (root_image
|| n_bind_mounts
> 0 || n_temporary_filesystems
> 0) {
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. */
1156 root
= "/run/systemd/unit-root";
1157 (void) mkdir_label(root
, 0700);
1158 require_prefix
= true;
1162 n_mounts
= namespace_calculate_mounts(
1170 n_temporary_filesystems
,
1171 tmp_dir
, var_tmp_dir
,
1172 protect_home
, protect_system
);
1174 /* Set mount slave mode */
1175 if (root
|| n_mounts
> 0)
1179 m
= mounts
= (MountEntry
*) alloca0(n_mounts
* sizeof(MountEntry
));
1180 r
= append_access_mounts(&m
, read_write_paths
, READWRITE
, require_prefix
);
1184 r
= append_access_mounts(&m
, read_only_paths
, READONLY
, require_prefix
);
1188 r
= append_access_mounts(&m
, inaccessible_paths
, INACCESSIBLE
, require_prefix
);
1192 r
= append_empty_dir_mounts(&m
, empty_directories
);
1196 r
= append_bind_mounts(&m
, bind_mounts
, n_bind_mounts
);
1200 r
= append_tmpfs_mounts(&m
, temporary_filesystems
, n_temporary_filesystems
);
1205 *(m
++) = (MountEntry
) {
1206 .path_const
= "/tmp",
1207 .mode
= PRIVATE_TMP
,
1208 .source_const
= tmp_dir
,
1213 *(m
++) = (MountEntry
) {
1214 .path_const
= "/var/tmp",
1215 .mode
= PRIVATE_TMP
,
1216 .source_const
= var_tmp_dir
,
1220 if (ns_info
->private_dev
) {
1221 *(m
++) = (MountEntry
) {
1222 .path_const
= "/dev",
1223 .mode
= PRIVATE_DEV
,
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
);
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
);
1239 if (ns_info
->protect_control_groups
) {
1240 *(m
++) = (MountEntry
) {
1241 .path_const
= "/sys/fs/cgroup",
1246 r
= append_protect_home(&m
, protect_home
, ns_info
->ignore_protect_paths
);
1250 r
= append_protect_system(&m
, protect_system
, false);
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
);
1260 assert(mounts
+ n_mounts
== m
);
1262 /* Prepend the root directory where that's necessary */
1263 r
= prefix_where_needed(mounts
, n_mounts
, root
);
1267 qsort(mounts
, n_mounts
, sizeof(MountEntry
), mount_path_compare
);
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
);
1275 if (unshare(CLONE_NEWNS
) < 0) {
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) {
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
);
1295 if (decrypted_image
) {
1296 r
= decrypted_image_relinquish(decrypted_image
);
1301 loop_device_relinquish(loop_device
);
1303 } else if (root_directory
) {
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
);
1310 if (mount(root
, root
, NULL
, MS_BIND
|MS_REC
, NULL
) < 0) {
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) {
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
);
1330 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
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
) {
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
);
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
;
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
);
1364 /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
1365 r
= mount_move_root(root
);
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) {
1381 for (m
= mounts
; m
< mounts
+ n_mounts
; m
++)
1382 mount_entry_done(m
);
1387 void bind_mount_free_many(BindMount
*b
, unsigned n
) {
1390 assert(b
|| n
== 0);
1392 for (i
= 0; i
< n
; i
++) {
1394 free(b
[i
].destination
);
1400 int bind_mount_add(BindMount
**b
, unsigned *n
, const BindMount
*item
) {
1401 _cleanup_free_
char *s
= NULL
, *d
= NULL
;
1408 s
= strdup(item
->source
);
1412 d
= strdup(item
->destination
);
1416 c
= reallocarray(*b
, *n
+ 1, sizeof(BindMount
));
1422 c
[(*n
) ++] = (BindMount
) {
1425 .read_only
= item
->read_only
,
1426 .recursive
= item
->recursive
,
1427 .ignore_enoent
= item
->ignore_enoent
,
1434 void temporary_filesystem_free_many(TemporaryFileSystem
*t
, unsigned n
) {
1437 assert(t
|| n
== 0);
1439 for (i
= 0; i
< n
; i
++) {
1447 int temporary_filesystem_add(
1448 TemporaryFileSystem
**t
,
1451 const char *options
) {
1453 _cleanup_free_
char *p
= NULL
, *o
= NULL
;
1454 TemporaryFileSystem
*c
;
1464 if (!isempty(options
)) {
1465 o
= strdup(options
);
1470 c
= reallocarray(*t
, *n
+ 1, sizeof(TemporaryFileSystem
));
1476 c
[(*n
) ++] = (TemporaryFileSystem
) {
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
];
1495 /* We include the boot id in the directory so that after a
1496 * reboot we can easily identify obsolete directories. */
1498 r
= sd_id128_get_boot(&boot_id
);
1502 x
= strjoin(prefix
, "/systemd-private-", sd_id128_to_string(boot_id
, bid
), "-", id
, "-XXXXXX");
1506 RUN_WITH_UMASK(0077)
1510 RUN_WITH_UMASK(0000) {
1513 y
= strjoina(x
, "/tmp");
1515 if (mkdir(y
, 0777 | S_ISVTX
) < 0)
1525 int setup_tmp_dirs(const char *id
, char **tmp_dir
, char **var_tmp_dir
) {
1531 assert(var_tmp_dir
);
1533 r
= setup_one_tmp_dir(id
, "/tmp", &a
);
1537 r
= setup_one_tmp_dir(id
, "/var/tmp", &b
);
1541 t
= strjoina(a
, "/tmp");
1555 int setup_netns(int netns_storage_socket
[2]) {
1556 _cleanup_close_
int netns
= -1;
1559 assert(netns_storage_socket
);
1560 assert(netns_storage_socket
[0] >= 0);
1561 assert(netns_storage_socket
[1] >= 0);
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
1569 * It's a bit crazy, but hey, works great! */
1571 if (lockf(netns_storage_socket
[0], F_LOCK
, 0) < 0)
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 */
1578 if (unshare(CLONE_NEWNET
) < 0) {
1585 netns
= open("/proc/self/ns/net", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1593 } else if (netns
< 0) {
1598 /* Yay, found something, so let's join the namespace */
1599 if (setns(netns
, CLONE_NEWNET
) < 0) {
1607 q
= send_one_fd(netns_storage_socket
[1], netns
, MSG_DONTWAIT
);
1614 (void) lockf(netns_storage_socket
[0], F_ULOCK
, 0);
1618 bool ns_type_supported(NamespaceType type
) {
1619 const char *t
, *ns_proc
;
1621 t
= namespace_type_to_string(type
);
1622 if (!t
) /* Don't know how to translate this? Then it's not supported */
1625 ns_proc
= strjoina("/proc/self/ns/", t
);
1626 return access(ns_proc
, F_OK
) == 0;
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",
1636 DEFINE_STRING_TABLE_LOOKUP(protect_home
, ProtectHome
);
1638 ProtectHome
parse_protect_home_or_bool(const char *s
) {
1641 r
= parse_boolean(s
);
1643 return PROTECT_HOME_YES
;
1645 return PROTECT_HOME_NO
;
1647 return protect_home_from_string(s
);
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",
1657 DEFINE_STRING_TABLE_LOOKUP(protect_system
, ProtectSystem
);
1659 ProtectSystem
parse_protect_system_or_bool(const char *s
) {
1662 r
= parse_boolean(s
);
1664 return PROTECT_SYSTEM_YES
;
1666 return PROTECT_SYSTEM_NO
;
1668 return protect_system_from_string(s
);
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",
1681 DEFINE_STRING_TABLE_LOOKUP(namespace_type
, NamespaceType
);