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
,
265 .ignore
= b
->ignore_enoent
,
272 static int append_static_mounts(MountEntry
**p
, const MountEntry
*mounts
, unsigned n
, bool ignore_protect
) {
278 /* Adds a list of static pre-defined entries */
280 for (i
= 0; i
< n
; i
++)
281 *((*p
)++) = (MountEntry
) {
282 .path_const
= mount_entry_path(mounts
+i
),
283 .mode
= mounts
[i
].mode
,
284 .ignore
= mounts
[i
].ignore
|| ignore_protect
,
290 static int append_protect_home(MountEntry
**p
, ProtectHome protect_home
, bool ignore_protect
) {
293 switch (protect_home
) {
295 case PROTECT_HOME_NO
:
298 case PROTECT_HOME_READ_ONLY
:
299 return append_static_mounts(p
, protect_home_read_only_table
, ELEMENTSOF(protect_home_read_only_table
), ignore_protect
);
301 case PROTECT_HOME_YES
:
302 return append_static_mounts(p
, protect_home_yes_table
, ELEMENTSOF(protect_home_yes_table
), ignore_protect
);
305 assert_not_reached("Unexpected ProtectHome= value");
309 static int append_protect_system(MountEntry
**p
, ProtectSystem protect_system
, bool ignore_protect
) {
312 switch (protect_system
) {
314 case PROTECT_SYSTEM_NO
:
317 case PROTECT_SYSTEM_STRICT
:
318 return append_static_mounts(p
, protect_system_strict_table
, ELEMENTSOF(protect_system_strict_table
), ignore_protect
);
320 case PROTECT_SYSTEM_YES
:
321 return append_static_mounts(p
, protect_system_yes_table
, ELEMENTSOF(protect_system_yes_table
), ignore_protect
);
323 case PROTECT_SYSTEM_FULL
:
324 return append_static_mounts(p
, protect_system_full_table
, ELEMENTSOF(protect_system_full_table
), ignore_protect
);
327 assert_not_reached("Unexpected ProtectSystem= value");
331 static int mount_path_compare(const void *a
, const void *b
) {
332 const MountEntry
*p
= a
, *q
= b
;
335 /* If the paths are not equal, then order prefixes first */
336 d
= path_compare(mount_entry_path(p
), mount_entry_path(q
));
340 /* If the paths are equal, check the mode */
341 if (p
->mode
< q
->mode
)
344 if (p
->mode
> q
->mode
)
350 static int prefix_where_needed(MountEntry
*m
, unsigned n
, const char *root_directory
) {
353 /* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
359 for (i
= 0; i
< n
; i
++) {
365 s
= prefix_root(root_directory
, mount_entry_path(m
+i
));
369 free_and_replace(m
[i
].path_malloc
, s
);
370 m
[i
].has_prefix
= true;
376 static void drop_duplicates(MountEntry
*m
, unsigned *n
) {
377 MountEntry
*f
, *t
, *previous
;
382 /* Drops duplicate entries. Expects that the array is properly ordered already. */
384 for (f
= m
, t
= m
, previous
= NULL
; f
< m
+ *n
; f
++) {
386 /* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
388 if (previous
&& path_equal(mount_entry_path(f
), mount_entry_path(previous
))) {
389 log_debug("%s is duplicate.", mount_entry_path(f
));
390 previous
->read_only
= previous
->read_only
|| mount_entry_read_only(f
); /* Propagate the read-only flag to the remaining entry */
403 static void drop_inaccessible(MountEntry
*m
, unsigned *n
) {
405 const char *clear
= NULL
;
410 /* Drops all entries obstructed by another entry further up the tree. Expects that the array is properly
411 * ordered already. */
413 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
415 /* If we found a path set for INACCESSIBLE earlier, and this entry has it as prefix we should drop
416 * it, as inaccessible paths really should drop the entire subtree. */
417 if (clear
&& path_startswith(mount_entry_path(f
), clear
)) {
418 log_debug("%s is masked by %s.", mount_entry_path(f
), clear
);
423 clear
= f
->mode
== INACCESSIBLE
? mount_entry_path(f
) : NULL
;
432 static void drop_nop(MountEntry
*m
, unsigned *n
) {
438 /* Drops all entries which have an immediate parent that has the same type, as they are redundant. Assumes the
439 * list is ordered by prefixes. */
441 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
443 /* Only suppress such subtrees for READONLY and READWRITE entries */
444 if (IN_SET(f
->mode
, READONLY
, READWRITE
)) {
448 /* Now let's find the first parent of the entry we are looking at. */
449 for (p
= t
-1; p
>= m
; p
--) {
450 if (path_startswith(mount_entry_path(f
), mount_entry_path(p
))) {
456 /* We found it, let's see if it's the same mode, if so, we can drop this entry */
457 if (found
&& p
->mode
== f
->mode
) {
458 log_debug("%s is redundant by %s", mount_entry_path(f
), mount_entry_path(p
));
471 static void drop_outside_root(const char *root_directory
, MountEntry
*m
, unsigned *n
) {
481 /* Drops all mounts that are outside of the root directory. */
483 for (f
= m
, t
= m
; f
< m
+ *n
; f
++) {
485 if (!path_startswith(mount_entry_path(f
), root_directory
)) {
486 log_debug("%s is outside of root directory.", mount_entry_path(f
));
498 static int clone_device_node(const char *d
, const char *temporary_mount
) {
503 if (stat(d
, &st
) < 0) {
509 if (!S_ISBLK(st
.st_mode
) &&
510 !S_ISCHR(st
.st_mode
))
516 dn
= strjoina(temporary_mount
, d
);
518 mac_selinux_create_file_prepare(d
, st
.st_mode
);
519 r
= mknod(dn
, st
.st_mode
, st
.st_rdev
);
520 mac_selinux_create_file_clear();
522 return log_debug_errno(errno
, "mknod failed for %s: %m", d
);
527 static int mount_private_dev(MountEntry
*m
) {
528 static const char devnodes
[] =
536 char temporary_mount
[] = "/tmp/namespace-dev-XXXXXX";
537 const char *d
, *dev
= NULL
, *devpts
= NULL
, *devshm
= NULL
, *devhugepages
= NULL
, *devmqueue
= NULL
, *devlog
= NULL
, *devptmx
= NULL
;
538 _cleanup_umask_ mode_t u
;
545 if (!mkdtemp(temporary_mount
))
548 dev
= strjoina(temporary_mount
, "/dev");
549 (void) mkdir(dev
, 0755);
550 if (mount("tmpfs", dev
, "tmpfs", DEV_MOUNT_OPTIONS
, "mode=755") < 0) {
555 devpts
= strjoina(temporary_mount
, "/dev/pts");
556 (void) mkdir(devpts
, 0755);
557 if (mount("/dev/pts", devpts
, NULL
, MS_BIND
, NULL
) < 0) {
562 /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx
563 * when /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible
564 * thus, in that case make a clone
566 * in nspawn and other containers it will be a symlink, in that case make it a symlink
568 r
= is_symlink("/dev/ptmx");
572 devptmx
= strjoina(temporary_mount
, "/dev/ptmx");
573 if (symlink("pts/ptmx", devptmx
) < 0) {
578 r
= clone_device_node("/dev/ptmx", temporary_mount
);
587 devshm
= strjoina(temporary_mount
, "/dev/shm");
588 (void) mkdir(devshm
, 0755);
589 r
= mount("/dev/shm", devshm
, NULL
, MS_BIND
, NULL
);
595 devmqueue
= strjoina(temporary_mount
, "/dev/mqueue");
596 (void) mkdir(devmqueue
, 0755);
597 (void) mount("/dev/mqueue", devmqueue
, NULL
, MS_BIND
, NULL
);
599 devhugepages
= strjoina(temporary_mount
, "/dev/hugepages");
600 (void) mkdir(devhugepages
, 0755);
601 (void) mount("/dev/hugepages", devhugepages
, NULL
, MS_BIND
, NULL
);
603 devlog
= strjoina(temporary_mount
, "/dev/log");
604 (void) symlink("/run/systemd/journal/dev-log", devlog
);
606 NULSTR_FOREACH(d
, devnodes
) {
607 r
= clone_device_node(d
, temporary_mount
);
612 dev_setup(temporary_mount
, UID_INVALID
, GID_INVALID
);
614 /* Create the /dev directory if missing. It is more likely to be
615 * missing when the service is started with RootDirectory. This is
616 * consistent with mount units creating the mount points when missing.
618 (void) mkdir_p_label(mount_entry_path(m
), 0755);
620 /* Unmount everything in old /dev */
621 umount_recursive(mount_entry_path(m
), 0);
622 if (mount(dev
, mount_entry_path(m
), NULL
, MS_MOVE
, NULL
) < 0) {
628 rmdir(temporary_mount
);
640 umount(devhugepages
);
647 rmdir(temporary_mount
);
652 static int mount_bind_dev(const MountEntry
*m
) {
657 /* Implements the little brother of mount_private_dev(): simply bind mounts the host's /dev into the service's
658 * /dev. This is only used when RootDirectory= is set. */
660 (void) mkdir_p_label(mount_entry_path(m
), 0755);
662 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 0);
664 return log_debug_errno(r
, "Unable to determine whether /dev is already mounted: %m");
665 if (r
> 0) /* make this a NOP if /dev is already a mount point */
668 if (mount("/dev", mount_entry_path(m
), NULL
, MS_BIND
|MS_REC
, NULL
) < 0)
669 return log_debug_errno(errno
, "Failed to bind mount %s: %m", mount_entry_path(m
));
674 static int mount_sysfs(const MountEntry
*m
) {
679 (void) mkdir_p_label(mount_entry_path(m
), 0755);
681 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 0);
683 return log_debug_errno(r
, "Unable to determine whether /sys is already mounted: %m");
684 if (r
> 0) /* make this a NOP if /sys is already a mount point */
687 /* Bind mount the host's version so that we get all child mounts of it, too. */
688 if (mount("/sys", mount_entry_path(m
), NULL
, MS_BIND
|MS_REC
, NULL
) < 0)
689 return log_debug_errno(errno
, "Failed to mount %s: %m", mount_entry_path(m
));
694 static int mount_procfs(const MountEntry
*m
) {
699 (void) mkdir_p_label(mount_entry_path(m
), 0755);
701 r
= path_is_mount_point(mount_entry_path(m
), NULL
, 0);
703 return log_debug_errno(r
, "Unable to determine whether /proc is already mounted: %m");
704 if (r
> 0) /* make this a NOP if /proc is already a mount point */
707 /* Mount a new instance, so that we get the one that matches our user namespace, if we are running in one */
708 if (mount("proc", mount_entry_path(m
), "proc", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, NULL
) < 0)
709 return log_debug_errno(errno
, "Failed to mount %s: %m", mount_entry_path(m
));
714 static int mount_empty_dir(const MountEntry
*m
) {
717 /* First, get rid of everything that is below if there is anything. Then, overmount with our new empty dir */
719 (void) mkdir_p_label(mount_entry_path(m
), 0755);
720 (void) umount_recursive(mount_entry_path(m
), 0);
722 if (mount("tmpfs", mount_entry_path(m
), "tmpfs", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
|MS_STRICTATIME
, "mode=755") < 0)
723 return log_debug_errno(errno
, "Failed to mount %s: %m", mount_entry_path(m
));
728 static int mount_entry_chase(
729 const char *root_directory
,
732 bool chase_nonexistent
,
740 /* Since mount() will always follow symlinks and we need to take the different root directory into account we
741 * chase the symlinks on our own first. This is called for the destination path, as well as the source path (if
742 * that applies). The result is stored in "location". */
744 r
= chase_symlinks(path
, root_directory
, chase_nonexistent
? CHASE_NONEXISTENT
: 0, &chased
);
745 if (r
== -ENOENT
&& m
->ignore
) {
746 log_debug_errno(r
, "Path %s does not exist, ignoring.", path
);
750 return log_debug_errno(r
, "Failed to follow symlinks on %s: %m", path
);
752 log_debug("Followed symlinks %s → %s.", path
, chased
);
760 static int apply_mount(
761 const char *root_directory
,
764 bool rbind
= true, make
= false;
770 r
= mount_entry_chase(root_directory
, m
, mount_entry_path(m
), !IN_SET(m
->mode
, INACCESSIBLE
, READONLY
, READWRITE
), &m
->path_malloc
);
774 log_debug("Applying namespace mount on %s", mount_entry_path(m
));
781 /* First, get rid of everything that is below if there
782 * is anything... Then, overmount it with an
783 * inaccessible path. */
784 (void) umount_recursive(mount_entry_path(m
), 0);
786 if (lstat(mount_entry_path(m
), &target
) < 0)
787 return log_debug_errno(errno
, "Failed to lstat() %s to determine what to mount over it: %m", mount_entry_path(m
));
789 what
= mode_to_inaccessible_node(target
.st_mode
);
791 log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed");
799 r
= path_is_mount_point(mount_entry_path(m
), root_directory
, 0);
801 return log_debug_errno(r
, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m
));
802 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. */
804 /* This isn't a mount point yet, let's make it one. */
805 what
= mount_entry_path(m
);
812 case BIND_MOUNT_RECURSIVE
:
813 /* Also chase the source mount */
815 r
= mount_entry_chase(root_directory
, m
, mount_entry_source(m
), false, &m
->source_malloc
);
819 what
= mount_entry_source(m
);
824 return mount_empty_dir(m
);
827 what
= mount_entry_source(m
);
832 return mount_private_dev(m
);
835 return mount_bind_dev(m
);
838 return mount_sysfs(m
);
841 return mount_procfs(m
);
844 assert_not_reached("Unknown mode");
849 if (mount(what
, mount_entry_path(m
), NULL
, MS_BIND
|(rbind
? MS_REC
: 0), NULL
) < 0) {
850 bool try_again
= false;
853 if (r
== -ENOENT
&& make
) {
856 /* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
858 if (stat(what
, &st
) >= 0) {
860 (void) mkdir_parents(mount_entry_path(m
), 0755);
862 if (S_ISDIR(st
.st_mode
))
863 try_again
= mkdir(mount_entry_path(m
), 0755) >= 0;
865 try_again
= touch(mount_entry_path(m
)) >= 0;
870 if (mount(what
, mount_entry_path(m
), NULL
, MS_BIND
|(rbind
? MS_REC
: 0), NULL
) < 0)
877 return log_debug_errno(r
, "Failed to mount %s to %s: %m", what
, mount_entry_path(m
));
880 log_debug("Successfully mounted %s to %s", what
, mount_entry_path(m
));
884 static int make_read_only(const MountEntry
*m
, char **blacklist
, FILE *proc_self_mountinfo
) {
888 assert(proc_self_mountinfo
);
890 if (mount_entry_read_only(m
))
891 r
= bind_remount_recursive_with_mountinfo(mount_entry_path(m
), true, blacklist
, proc_self_mountinfo
);
892 else if (m
->mode
== PRIVATE_DEV
) { /* Superblock can be readonly but the submounts can't */
893 if (mount(NULL
, mount_entry_path(m
), NULL
, MS_REMOUNT
|DEV_MOUNT_OPTIONS
|MS_RDONLY
, NULL
) < 0)
898 /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked read-only
899 * already stays this way. This improves compatibility with container managers, where we won't attempt to undo
900 * read-only mounts already applied. */
902 if (r
== -ENOENT
&& m
->ignore
)
908 static bool namespace_info_mount_apivfs(const char *root_directory
, const NamespaceInfo
*ns_info
) {
912 * ProtectControlGroups= and ProtectKernelTunables= imply MountAPIVFS=,
913 * since to protect the API VFS mounts, they need to be around in the
914 * first place... and RootDirectory= or RootImage= need to be set.
917 /* root_directory should point to a mount point */
918 return root_directory
&&
919 (ns_info
->mount_apivfs
||
920 ns_info
->protect_control_groups
||
921 ns_info
->protect_kernel_tunables
);
924 static unsigned namespace_calculate_mounts(
925 const char* root_directory
,
926 const NamespaceInfo
*ns_info
,
927 char** read_write_paths
,
928 char** read_only_paths
,
929 char** inaccessible_paths
,
930 char** empty_directories
,
931 unsigned n_bind_mounts
,
933 const char* var_tmp_dir
,
934 ProtectHome protect_home
,
935 ProtectSystem protect_system
) {
937 unsigned protect_home_cnt
;
938 unsigned protect_system_cnt
=
939 (protect_system
== PROTECT_SYSTEM_STRICT
?
940 ELEMENTSOF(protect_system_strict_table
) :
941 ((protect_system
== PROTECT_SYSTEM_FULL
) ?
942 ELEMENTSOF(protect_system_full_table
) :
943 ((protect_system
== PROTECT_SYSTEM_YES
) ?
944 ELEMENTSOF(protect_system_yes_table
) : 0)));
947 (protect_home
== PROTECT_HOME_YES
?
948 ELEMENTSOF(protect_home_yes_table
) :
949 ((protect_home
== PROTECT_HOME_READ_ONLY
) ?
950 ELEMENTSOF(protect_home_read_only_table
) : 0));
952 return !!tmp_dir
+ !!var_tmp_dir
+
953 strv_length(read_write_paths
) +
954 strv_length(read_only_paths
) +
955 strv_length(inaccessible_paths
) +
956 strv_length(empty_directories
) +
958 ns_info
->private_dev
+
959 (ns_info
->protect_kernel_tunables
? ELEMENTSOF(protect_kernel_tunables_table
) : 0) +
960 (ns_info
->protect_control_groups
? 1 : 0) +
961 (ns_info
->protect_kernel_modules
? ELEMENTSOF(protect_kernel_modules_table
) : 0) +
962 protect_home_cnt
+ protect_system_cnt
+
963 (namespace_info_mount_apivfs(root_directory
, ns_info
) ? ELEMENTSOF(apivfs_table
) : 0);
967 const char* root_directory
,
968 const char* root_image
,
969 const NamespaceInfo
*ns_info
,
970 char** read_write_paths
,
971 char** read_only_paths
,
972 char** inaccessible_paths
,
973 char** empty_directories
,
974 const BindMount
*bind_mounts
,
975 unsigned n_bind_mounts
,
977 const char* var_tmp_dir
,
978 ProtectHome protect_home
,
979 ProtectSystem protect_system
,
980 unsigned long mount_flags
,
981 DissectImageFlags dissect_image_flags
) {
983 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
984 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*decrypted_image
= NULL
;
985 _cleanup_(dissected_image_unrefp
) DissectedImage
*dissected_image
= NULL
;
986 _cleanup_free_
void *root_hash
= NULL
;
987 MountEntry
*m
, *mounts
= NULL
;
988 size_t root_hash_size
= 0;
989 bool make_slave
= false;
992 bool require_prefix
= false;
997 if (mount_flags
== 0)
998 mount_flags
= MS_SHARED
;
1001 dissect_image_flags
|= DISSECT_IMAGE_REQUIRE_ROOT
;
1003 if (protect_system
== PROTECT_SYSTEM_STRICT
&& strv_isempty(read_write_paths
))
1004 dissect_image_flags
|= DISSECT_IMAGE_READ_ONLY
;
1006 r
= loop_device_make_by_path(root_image
,
1007 dissect_image_flags
& DISSECT_IMAGE_READ_ONLY
? O_RDONLY
: O_RDWR
,
1012 r
= root_hash_load(root_image
, &root_hash
, &root_hash_size
);
1016 r
= dissect_image(loop_device
->fd
, root_hash
, root_hash_size
, dissect_image_flags
, &dissected_image
);
1020 r
= dissected_image_decrypt(dissected_image
, NULL
, root_hash
, root_hash_size
, dissect_image_flags
, &decrypted_image
);
1026 root
= root_directory
;
1027 else if (root_image
|| n_bind_mounts
> 0) {
1029 /* If we are booting from an image, create a mount point for the image, if it's still missing. We use
1030 * the same mount point for all images, which is safe, since they all live in their own namespaces
1031 * after all, and hence won't see each other. We also use such a root directory whenever there are bind
1032 * mounts configured, so that their source mounts are never obstructed by mounts we already applied
1033 * while we are applying them. */
1035 root
= "/run/systemd/unit-root";
1036 (void) mkdir_label(root
, 0700);
1037 require_prefix
= true;
1041 n_mounts
= namespace_calculate_mounts(
1049 tmp_dir
, var_tmp_dir
,
1050 protect_home
, protect_system
);
1052 /* Set mount slave mode */
1053 if (root
|| n_mounts
> 0)
1057 m
= mounts
= (MountEntry
*) alloca0(n_mounts
* sizeof(MountEntry
));
1058 r
= append_access_mounts(&m
, read_write_paths
, READWRITE
, require_prefix
);
1062 r
= append_access_mounts(&m
, read_only_paths
, READONLY
, require_prefix
);
1066 r
= append_access_mounts(&m
, inaccessible_paths
, INACCESSIBLE
, require_prefix
);
1070 r
= append_empty_dir_mounts(&m
, empty_directories
);
1074 r
= append_bind_mounts(&m
, bind_mounts
, n_bind_mounts
);
1079 *(m
++) = (MountEntry
) {
1080 .path_const
= "/tmp",
1081 .mode
= PRIVATE_TMP
,
1082 .source_const
= tmp_dir
,
1087 *(m
++) = (MountEntry
) {
1088 .path_const
= "/var/tmp",
1089 .mode
= PRIVATE_TMP
,
1090 .source_const
= var_tmp_dir
,
1094 if (ns_info
->private_dev
) {
1095 *(m
++) = (MountEntry
) {
1096 .path_const
= "/dev",
1097 .mode
= PRIVATE_DEV
,
1101 if (ns_info
->protect_kernel_tunables
) {
1102 r
= append_static_mounts(&m
, protect_kernel_tunables_table
, ELEMENTSOF(protect_kernel_tunables_table
), ns_info
->ignore_protect_paths
);
1107 if (ns_info
->protect_kernel_modules
) {
1108 r
= append_static_mounts(&m
, protect_kernel_modules_table
, ELEMENTSOF(protect_kernel_modules_table
), ns_info
->ignore_protect_paths
);
1113 if (ns_info
->protect_control_groups
) {
1114 *(m
++) = (MountEntry
) {
1115 .path_const
= "/sys/fs/cgroup",
1120 r
= append_protect_home(&m
, protect_home
, ns_info
->ignore_protect_paths
);
1124 r
= append_protect_system(&m
, protect_system
, false);
1128 if (namespace_info_mount_apivfs(root
, ns_info
)) {
1129 r
= append_static_mounts(&m
, apivfs_table
, ELEMENTSOF(apivfs_table
), ns_info
->ignore_protect_paths
);
1134 assert(mounts
+ n_mounts
== m
);
1136 /* Prepend the root directory where that's necessary */
1137 r
= prefix_where_needed(mounts
, n_mounts
, root
);
1141 qsort(mounts
, n_mounts
, sizeof(MountEntry
), mount_path_compare
);
1143 drop_duplicates(mounts
, &n_mounts
);
1144 drop_outside_root(root
, mounts
, &n_mounts
);
1145 drop_inaccessible(mounts
, &n_mounts
);
1146 drop_nop(mounts
, &n_mounts
);
1149 if (unshare(CLONE_NEWNS
) < 0) {
1155 /* Remount / as SLAVE so that nothing now mounted in the namespace
1156 shows up in the parent */
1157 if (mount(NULL
, "/", NULL
, MS_SLAVE
|MS_REC
, NULL
) < 0) {
1164 /* A root image is specified, mount it to the right place */
1165 r
= dissected_image_mount(dissected_image
, root
, UID_INVALID
, dissect_image_flags
);
1169 if (decrypted_image
) {
1170 r
= decrypted_image_relinquish(decrypted_image
);
1175 loop_device_relinquish(loop_device
);
1177 } else if (root_directory
) {
1179 /* A root directory is specified. Turn its directory into bind mount, if it isn't one yet. */
1180 r
= path_is_mount_point(root
, NULL
, AT_SYMLINK_FOLLOW
);
1184 if (mount(root
, root
, NULL
, MS_BIND
|MS_REC
, NULL
) < 0) {
1192 /* Let's mount the main root directory to the root directory to use */
1193 if (mount("/", root
, NULL
, MS_BIND
|MS_REC
, NULL
) < 0) {
1199 /* Try to set up the new root directory before mounting anything else there. */
1200 if (root_image
|| root_directory
)
1201 (void) base_filesystem_create(root
, UID_INVALID
, GID_INVALID
);
1204 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
1208 /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
1209 * For example, this is the case with the option: 'InaccessiblePaths=/proc' */
1210 proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re");
1211 if (!proc_self_mountinfo
) {
1216 /* First round, add in all special mounts we need */
1217 for (m
= mounts
; m
< mounts
+ n_mounts
; ++m
) {
1218 r
= apply_mount(root
, m
);
1223 /* Create a blacklist we can pass to bind_mount_recursive() */
1224 blacklist
= newa(char*, n_mounts
+1);
1225 for (j
= 0; j
< n_mounts
; j
++)
1226 blacklist
[j
] = (char*) mount_entry_path(mounts
+j
);
1227 blacklist
[j
] = NULL
;
1229 /* Second round, flip the ro bits if necessary. */
1230 for (m
= mounts
; m
< mounts
+ n_mounts
; ++m
) {
1231 r
= make_read_only(m
, blacklist
, proc_self_mountinfo
);
1238 /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
1239 r
= mount_move_root(root
);
1244 /* Remount / as the desired mode. Note that this will not
1245 * reestablish propagation from our side to the host, since
1246 * what's disconnected is disconnected. */
1247 if (mount(NULL
, "/", NULL
, mount_flags
| MS_REC
, NULL
) < 0) {
1255 for (m
= mounts
; m
< mounts
+ n_mounts
; m
++)
1256 mount_entry_done(m
);
1261 void bind_mount_free_many(BindMount
*b
, unsigned n
) {
1264 assert(b
|| n
== 0);
1266 for (i
= 0; i
< n
; i
++) {
1268 free(b
[i
].destination
);
1274 int bind_mount_add(BindMount
**b
, unsigned *n
, const BindMount
*item
) {
1275 _cleanup_free_
char *s
= NULL
, *d
= NULL
;
1282 s
= strdup(item
->source
);
1286 d
= strdup(item
->destination
);
1290 c
= realloc_multiply(*b
, sizeof(BindMount
), *n
+ 1);
1296 c
[(*n
) ++] = (BindMount
) {
1299 .read_only
= item
->read_only
,
1300 .recursive
= item
->recursive
,
1301 .ignore_enoent
= item
->ignore_enoent
,
1308 static int setup_one_tmp_dir(const char *id
, const char *prefix
, char **path
) {
1309 _cleanup_free_
char *x
= NULL
;
1310 char bid
[SD_ID128_STRING_MAX
];
1318 /* We include the boot id in the directory so that after a
1319 * reboot we can easily identify obsolete directories. */
1321 r
= sd_id128_get_boot(&boot_id
);
1325 x
= strjoin(prefix
, "/systemd-private-", sd_id128_to_string(boot_id
, bid
), "-", id
, "-XXXXXX");
1329 RUN_WITH_UMASK(0077)
1333 RUN_WITH_UMASK(0000) {
1336 y
= strjoina(x
, "/tmp");
1338 if (mkdir(y
, 0777 | S_ISVTX
) < 0)
1348 int setup_tmp_dirs(const char *id
, char **tmp_dir
, char **var_tmp_dir
) {
1354 assert(var_tmp_dir
);
1356 r
= setup_one_tmp_dir(id
, "/tmp", &a
);
1360 r
= setup_one_tmp_dir(id
, "/var/tmp", &b
);
1364 t
= strjoina(a
, "/tmp");
1378 int setup_netns(int netns_storage_socket
[2]) {
1379 _cleanup_close_
int netns
= -1;
1382 assert(netns_storage_socket
);
1383 assert(netns_storage_socket
[0] >= 0);
1384 assert(netns_storage_socket
[1] >= 0);
1386 /* We use the passed socketpair as a storage buffer for our
1387 * namespace reference fd. Whatever process runs this first
1388 * shall create a new namespace, all others should just join
1389 * it. To serialize that we use a file lock on the socket
1392 * It's a bit crazy, but hey, works great! */
1394 if (lockf(netns_storage_socket
[0], F_LOCK
, 0) < 0)
1397 netns
= receive_one_fd(netns_storage_socket
[0], MSG_DONTWAIT
);
1398 if (netns
== -EAGAIN
) {
1399 /* Nothing stored yet, so let's create a new namespace */
1401 if (unshare(CLONE_NEWNET
) < 0) {
1408 netns
= open("/proc/self/ns/net", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1416 } else if (netns
< 0) {
1421 /* Yay, found something, so let's join the namespace */
1422 if (setns(netns
, CLONE_NEWNET
) < 0) {
1430 q
= send_one_fd(netns_storage_socket
[1], netns
, MSG_DONTWAIT
);
1437 (void) lockf(netns_storage_socket
[0], F_ULOCK
, 0);
1441 bool ns_type_supported(NamespaceType type
) {
1442 const char *t
, *ns_proc
;
1444 t
= namespace_type_to_string(type
);
1445 if (!t
) /* Don't know how to translate this? Then it's not supported */
1448 ns_proc
= strjoina("/proc/self/ns/", t
);
1449 return access(ns_proc
, F_OK
) == 0;
1452 static const char *const protect_home_table
[_PROTECT_HOME_MAX
] = {
1453 [PROTECT_HOME_NO
] = "no",
1454 [PROTECT_HOME_YES
] = "yes",
1455 [PROTECT_HOME_READ_ONLY
] = "read-only",
1458 DEFINE_STRING_TABLE_LOOKUP(protect_home
, ProtectHome
);
1460 ProtectHome
parse_protect_home_or_bool(const char *s
) {
1463 r
= parse_boolean(s
);
1465 return PROTECT_HOME_YES
;
1467 return PROTECT_HOME_NO
;
1469 return protect_home_from_string(s
);
1472 static const char *const protect_system_table
[_PROTECT_SYSTEM_MAX
] = {
1473 [PROTECT_SYSTEM_NO
] = "no",
1474 [PROTECT_SYSTEM_YES
] = "yes",
1475 [PROTECT_SYSTEM_FULL
] = "full",
1476 [PROTECT_SYSTEM_STRICT
] = "strict",
1479 DEFINE_STRING_TABLE_LOOKUP(protect_system
, ProtectSystem
);
1481 ProtectSystem
parse_protect_system_or_bool(const char *s
) {
1484 r
= parse_boolean(s
);
1486 return PROTECT_SYSTEM_YES
;
1488 return PROTECT_SYSTEM_NO
;
1490 return protect_system_from_string(s
);
1493 static const char* const namespace_type_table
[] = {
1494 [NAMESPACE_MOUNT
] = "mnt",
1495 [NAMESPACE_CGROUP
] = "cgroup",
1496 [NAMESPACE_UTS
] = "uts",
1497 [NAMESPACE_IPC
] = "ipc",
1498 [NAMESPACE_USER
] = "user",
1499 [NAMESPACE_PID
] = "pid",
1500 [NAMESPACE_NET
] = "net",
1503 DEFINE_STRING_TABLE_LOOKUP(namespace_type
, NamespaceType
);