MountAPIVFS: always mount a tmpfs on /run

We need a writable /run for most operations, but in case a read-only
RootImage (or similar) is used, by default there's no additional
tmpfs mount on /run. Change this behaviour and document it.
This commit is contained in:
Luca Boccassi 2020-12-18 16:16:46 +00:00
parent f7c18d3de8
commit 94293d65cd
3 changed files with 35 additions and 5 deletions

10
NEWS
View file

@ -1,5 +1,15 @@
systemd System and Service Manager
CHANGES WITH 248:
* The MountAPIVFS= service file setting now additionally mounts a tmpfs
on /run/ if it is not already a mount point. A writable /run/ has always
been a requirement for a functioning system, but this was not
guaranteed when using a read-only image.
Users can always specify BindPaths= or InaccessiblePaths= as overrides,
and they will take precedence. If the host's root mount point is used,
there is no change in behaviour.
CHANGES WITH 247:
* KERNEL API INCOMPATIBILITY: Linux 4.14 introduced two new uevents

View file

@ -275,11 +275,12 @@
<term><varname>MountAPIVFS=</varname></term>
<listitem><para>Takes a boolean argument. If on, a private mount namespace for the unit's processes is created
and the API file systems <filename>/proc/</filename>, <filename>/sys/</filename>, and <filename>/dev/</filename>
are mounted inside of it, unless they are already mounted. Note that this option has no effect unless used in
conjunction with <varname>RootDirectory=</varname>/<varname>RootImage=</varname> as these three mounts are
and the API file systems <filename>/proc/</filename>, <filename>/sys/</filename>, <filename>/dev/</filename> and
<filename>/run/</filename> (as an empty <literal>tmpfs</literal>) are mounted inside of it, unless they are
already mounted. Note that this option has no effect unless used in conjunction with
<varname>RootDirectory=</varname>/<varname>RootImage=</varname> as these four mounts are
generally mounted in the host anyway, and unless the root directory is changed, the private mount namespace
will be a 1:1 copy of the host's, and include these three mounts. Note that the <filename>/dev/</filename> file
will be a 1:1 copy of the host's, and include these four mounts. Note that the <filename>/dev/</filename> file
system of the host is bind mounted if this option is used without <varname>PrivateDevices=</varname>. To run
the service with a private, minimal version of <filename>/dev/</filename>, combine this option with
<varname>PrivateDevices=</varname>.</para>

View file

@ -51,6 +51,7 @@ typedef enum MountMode {
EMPTY_DIR,
SYSFS,
PROCFS,
RUN,
READONLY,
READWRITE,
TMPFS,
@ -76,12 +77,13 @@ typedef struct MountEntry {
LIST_HEAD(MountOptions, image_options);
} MountEntry;
/* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted
/* If MountAPIVFS= is used, let's mount /sys, /proc, /dev and /run into the it, but only as a fallback if the user hasn't mounted
* something there already. These mounts are hence overridden by any other explicitly configured mounts. */
static const MountEntry apivfs_table[] = {
{ "/proc", PROCFS, false },
{ "/dev", BIND_DEV, false },
{ "/sys", SYSFS, false },
{ "/run", RUN, false, .options_const = "mode=755" TMPFS_LIMITS_RUN, .flags = MS_NOSUID|MS_NODEV|MS_STRICTATIME },
};
/* ProtectKernelTunables= option and the related filesystem APIs */
@ -945,6 +947,20 @@ static int mount_tmpfs(const MountEntry *m) {
return 1;
}
static int mount_run(const MountEntry *m) {
int r;
assert(m);
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0 && r != -ENOENT)
return log_debug_errno(r, "Unable to determine whether /run is already mounted: %m");
if (r > 0) /* make this a NOP if /run is already a mount point */
return 0;
return mount_tmpfs(m);
}
static int mount_images(const MountEntry *m) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
@ -1170,6 +1186,9 @@ static int apply_mount(
case PROCFS:
return mount_procfs(m, ns_info);
case RUN:
return mount_run(m);
case MOUNT_IMAGES:
return mount_images(m);