mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
mountfsd: add new systemd-mountfsd component
This commit is contained in:
@@ -676,3 +676,21 @@ Tools using the Varlink protocol (such as `varlinkctl`) or sd-bus (such as
|
||||
service. Takes a file system path: if specified the tool will listen on an
|
||||
`AF_UNIX` stream socket on the specified path in addition to whatever else it
|
||||
would listen on.
|
||||
|
||||
`systemd-mountfsd`:
|
||||
|
||||
* `$SYSTEMD_MOUNTFSD_TRUSTED_DIRECTORIES` – takes a boolean argument. If true
|
||||
disk images from the usual disk image directories (`/var/lib/machines/`,
|
||||
`/var/lib/confexts/`, …) will be considered "trusted", i.e. are validated
|
||||
with a more relaxed image policy (typically not requiring Verity signature
|
||||
checking) than those from other directories (where Verity signature checks
|
||||
are mandatory). If false all images are treated the same, regardless if
|
||||
placed in the usual disk image directories or elsewhere. If not set defaults
|
||||
to a compile time setting.
|
||||
|
||||
* `$SYSTEMD_MOUNTFSD_IMAGE_POLICY_TRUSTED`,
|
||||
`$SYSTEMD_MOUNTFSD_IMAGE_POLICY_UNTRUSTED` – the default image policy to
|
||||
apply to trusted and untrusted disk images. An image is considered trusted if
|
||||
placed in a trusted disk image directory (see above), or if suitable polkit
|
||||
authentication was acquired. See `systemd.image-policy(7)` for the valid
|
||||
syntax for image policy strings.
|
||||
|
||||
@@ -999,6 +999,7 @@ manpages = [
|
||||
['systemd-measure', '1', [], 'HAVE_TPM2 HAVE_BLKID HAVE_OPENSSL'],
|
||||
['systemd-modules-load.service', '8', ['systemd-modules-load'], 'HAVE_KMOD'],
|
||||
['systemd-mount', '1', ['systemd-umount'], ''],
|
||||
['systemd-mountfsd.service', '8', ['systemd-mountfsd'], 'ENABLE_MOUNTFSD'],
|
||||
['systemd-network-generator.service', '8', ['systemd-network-generator'], ''],
|
||||
['systemd-networkd-wait-online.service',
|
||||
'8',
|
||||
|
||||
70
man/systemd-mountfsd.service.xml
Normal file
70
man/systemd-mountfsd.service.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="systemd-mountfsd.service" conditional='ENABLE_MOUNTFSD'>
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-mountfsd.service</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-mountfsd.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-mountfsd.service</refname>
|
||||
<refname>systemd-mountfsd</refname>
|
||||
<refpurpose>Disk Image File System Mount Service</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-mountfsd.service</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-mountfsd</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-mountfsd</command> is a system service that dissects disk images, and returns mount
|
||||
file descriptors for the file systems contained therein to clients, via a Varlink IPC API.</para>
|
||||
|
||||
<para>The disk images provided must contain a raw file system image or must follow the <ulink
|
||||
url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification/">Discoverable
|
||||
Partitions Specification</ulink>. Before mounting any file systems authenticity of the disk image is
|
||||
established in one or a combination of the following ways:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem><para>If the disk image is located in a regular file in one of the directories
|
||||
<filename>/var/lib/machines/</filename>, <filename>/var/lib/portables/</filename>,
|
||||
<filename>/var/lib/extensions/</filename>, <filename>/var/lib/confexts/</filename> or their
|
||||
counterparts in the <filename>/etc/</filename>, <filename>/run/</filename>,
|
||||
<filename>/usr/lib/</filename> it is assumed to be trusted.</para></listitem>
|
||||
|
||||
<listitem><para>If the disk image contains a Verity enabled disk image, along with a signature
|
||||
partition with a key in the kernel keyring or in <filename>/etc/verity.d/</filename> (and related
|
||||
directories) the disk image is considered trusted.</para></listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>This service provides one <ulink url="https://varlink.org/">Varlink</ulink> service:
|
||||
<constant>io.systemd.MountFileSystem</constant> which accepts a file descriptor to a regular file or
|
||||
block device, and returns a number of file descriptors referring to an <function>fsmount()</function>
|
||||
file descriptor the client may then attach to a path of their choice.</para>
|
||||
|
||||
<para>The returned mounts are automatically allowlisted in the per-user-namespace allowlist maintained by
|
||||
<citerefentry><refentrytitle>systemd-nsresourced.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>The file systems are automatically fsck'ed before mounting.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-nsresourced.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
@@ -272,6 +272,7 @@ conf.set_quoted('SYSTEMD_TEST_DATA', testdata_dir)
|
||||
conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', bindir / 'systemd-tty-ask-password-agent')
|
||||
conf.set_quoted('SYSTEMD_UPDATE_HELPER_PATH', libexecdir / 'systemd-update-helper')
|
||||
conf.set_quoted('SYSTEMD_USERWORK_PATH', libexecdir / 'systemd-userwork')
|
||||
conf.set_quoted('SYSTEMD_MOUNTWORK_PATH', libexecdir / 'systemd-mountwork')
|
||||
conf.set_quoted('SYSTEMD_NSRESOURCEWORK_PATH', libexecdir / 'systemd-nsresourcework')
|
||||
conf.set_quoted('SYSTEMD_VERITYSETUP_PATH', libexecdir / 'systemd-veritysetup')
|
||||
conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', pkgsysconfdir / 'system')
|
||||
@@ -1598,6 +1599,8 @@ conf.set10('ENABLE_REMOTE', have)
|
||||
feature = get_option('vmspawn').disable_auto_if(conf.get('BUILD_MODE_DEVELOPER') == 0)
|
||||
conf.set10('ENABLE_VMSPAWN', feature.allowed())
|
||||
|
||||
conf.set10('DEFAULT_MOUNTFSD_TRUSTED_DIRECTORIES', get_option('default-mountfsd-trusted-directories'))
|
||||
|
||||
foreach term : ['analyze',
|
||||
'backlight',
|
||||
'binfmt',
|
||||
@@ -1618,6 +1621,7 @@ foreach term : ['analyze',
|
||||
'localed',
|
||||
'logind',
|
||||
'machined',
|
||||
'mountfsd',
|
||||
'networkd',
|
||||
'nscd',
|
||||
'nsresourced',
|
||||
@@ -2276,6 +2280,7 @@ subdir('src/locale')
|
||||
subdir('src/login')
|
||||
subdir('src/machine')
|
||||
subdir('src/machine-id-setup')
|
||||
subdir('src/mountfsd')
|
||||
subdir('src/modules-load')
|
||||
subdir('src/mount')
|
||||
subdir('src/network')
|
||||
|
||||
@@ -124,6 +124,8 @@ option('portabled', type : 'boolean',
|
||||
description : 'install the systemd-portabled stack')
|
||||
option('sysext', type : 'boolean',
|
||||
description : 'install the systemd-sysext stack')
|
||||
option('mountfsd', type : 'boolean',
|
||||
description : 'install the systemd-mountfsd stack')
|
||||
option('userdb', type : 'boolean',
|
||||
description : 'install the systemd-userdbd stack')
|
||||
option('homed', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
@@ -528,3 +530,6 @@ option('vmlinux-h', type : 'combo', choices : ['auto', 'provided', 'generated',
|
||||
description : 'which vmlinux.h to use')
|
||||
option('vmlinux-h-path', type : 'string', value : '',
|
||||
description : 'path to vmlinux.h to use')
|
||||
|
||||
option('default-mountfsd-trusted-directories', type : 'boolean', value: false,
|
||||
description : 'controls whether mountfsd should apply a relaxed policy on DDIs in system DDI directories')
|
||||
|
||||
@@ -23,9 +23,10 @@ enable systemd-homed.service
|
||||
enable systemd-homed-activate.service
|
||||
enable systemd-homed-firstboot.service
|
||||
enable systemd-journald-audit.socket
|
||||
enable systemd-mountfsd.socket
|
||||
enable systemd-network-generator.service
|
||||
enable systemd-networkd-wait-online.service
|
||||
enable systemd-networkd.service
|
||||
enable systemd-networkd-wait-online.service
|
||||
enable systemd-nsresourced.socket
|
||||
enable systemd-pstore.service
|
||||
enable systemd-resolved.service
|
||||
|
||||
70
src/mountfsd/io.systemd.mount-file-system.policy
Normal file
70
src/mountfsd/io.systemd.mount-file-system.policy
Normal file
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
|
||||
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||
"https://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||
|
||||
<!--
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
This file is part of systemd.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
-->
|
||||
|
||||
<policyconfig>
|
||||
|
||||
<vendor>The systemd Project</vendor>
|
||||
<vendor_url>https://systemd.io</vendor_url>
|
||||
|
||||
<!-- Allow mounting DDIs into the host user namespace -->
|
||||
<action id="io.systemd.mount-file-system.mount-image">
|
||||
<!-- This action is generally checked first: we'll first try to mount the image with
|
||||
signature checks on. If that fails, we'll retry with the untrusted action below. -->
|
||||
<description gettext-domain="systemd">Allow mounting of file system image</description>
|
||||
<message gettext-domain="systemd">Authentication is required for an application to mount a file system image.</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>yes</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="io.systemd.mount-file-system.mount-untrusted-image">
|
||||
<!-- If the image cannot be mounted via the regular action because it is not signed by a
|
||||
recognized key, we'll try this action. -->
|
||||
<description gettext-domain="systemd">Allow mounting of untrusted file system image</description>
|
||||
<message gettext-domain="systemd">Authentication is required for an application to mount a cryptographically unsigned file system image or an image whose cryptographic signature is not recognized.</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin</allow_active>
|
||||
</defaults>
|
||||
|
||||
<annotate key="org.freedesktop.policykit.imply">io.systemd.mount-file-system.mount-image</annotate>
|
||||
</action>
|
||||
|
||||
<!-- Allow mounting DDIs into a private user namespace -->
|
||||
<action id="io.systemd.mount-file-system.mount-image-privately">
|
||||
<description gettext-domain="systemd">Allow private mounting of trusted file system image</description>
|
||||
<message gettext-domain="systemd">Authentication is required for an application to privately mount a file system image or an image whose cryptographic signature is recognized.</message>
|
||||
<defaults>
|
||||
<allow_any>yes</allow_any>
|
||||
<allow_inactive>yes</allow_inactive>
|
||||
<allow_active>yes</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="io.systemd.mount-file-system.mount-untrusted-image-privately">
|
||||
<description gettext-domain="systemd">Allow private mounting of untrusted file system image</description>
|
||||
<message gettext-domain="systemd">Authentication is required for an application to privately mount a cryptographically unsigned file system image or an image whose cryptographic signature is not recognized.</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin</allow_active>
|
||||
</defaults>
|
||||
|
||||
<annotate key="org.freedesktop.policykit.imply">io.systemd.mount-file-system.mount-image-privately</annotate>
|
||||
</action>
|
||||
</policyconfig>
|
||||
28
src/mountfsd/meson.build
Normal file
28
src/mountfsd/meson.build
Normal file
@@ -0,0 +1,28 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
systemd_mountwork_sources = files(
|
||||
'mountwork.c',
|
||||
)
|
||||
|
||||
systemd_mountfsd_sources = files(
|
||||
'mountfsd.c',
|
||||
'mountfsd-manager.c',
|
||||
)
|
||||
|
||||
executables += [
|
||||
libexec_template + {
|
||||
'name' : 'systemd-mountfsd',
|
||||
'conditions' : ['ENABLE_MOUNTFSD'],
|
||||
'sources' : systemd_mountfsd_sources,
|
||||
},
|
||||
libexec_template + {
|
||||
'name' : 'systemd-mountwork',
|
||||
'conditions' : ['ENABLE_MOUNTFSD'],
|
||||
'sources' : systemd_mountwork_sources,
|
||||
'link_with' : common_libs,
|
||||
'dependencies' : common_deps,
|
||||
},
|
||||
]
|
||||
|
||||
install_data('io.systemd.mount-file-system.policy',
|
||||
install_dir : polkitpolicydir)
|
||||
277
src/mountfsd/mountfsd-manager.c
Normal file
277
src/mountfsd/mountfsd-manager.c
Normal file
@@ -0,0 +1,277 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "sd-daemon.h"
|
||||
|
||||
#include "build-path.h"
|
||||
#include "common-signal.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "mountfsd-manager.h"
|
||||
#include "process-util.h"
|
||||
#include "set.h"
|
||||
#include "signal-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "umask-util.h"
|
||||
|
||||
#define LISTEN_TIMEOUT_USEC (25 * USEC_PER_SEC)
|
||||
|
||||
static int start_workers(Manager *m, bool explicit_request);
|
||||
|
||||
static size_t manager_current_workers(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
return set_size(m->workers_fixed) + set_size(m->workers_dynamic);
|
||||
}
|
||||
|
||||
static int on_worker_exit(sd_event_source *s, const siginfo_t *si, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
assert(s);
|
||||
|
||||
assert_se(!set_remove(m->workers_dynamic, s) != !set_remove(m->workers_fixed, s));
|
||||
sd_event_source_disable_unref(s);
|
||||
|
||||
if (si->si_code == CLD_EXITED) {
|
||||
if (si->si_status == EXIT_SUCCESS)
|
||||
log_debug("Worker " PID_FMT " exited successfully.", si->si_pid);
|
||||
else
|
||||
log_warning("Worker " PID_FMT " died with a failure exit status %i, ignoring.", si->si_pid, si->si_status);
|
||||
} else if (si->si_code == CLD_KILLED)
|
||||
log_warning("Worker " PID_FMT " was killed by signal %s, ignoring.", si->si_pid, signal_to_string(si->si_status));
|
||||
else if (si->si_code == CLD_DUMPED)
|
||||
log_warning("Worker " PID_FMT " dumped core by signal %s, ignoring.", si->si_pid, signal_to_string(si->si_status));
|
||||
else
|
||||
log_warning("Got unexpected exit code via SIGCHLD, ignoring.");
|
||||
|
||||
(void) start_workers(m, /* explicit_request= */ false); /* Fill up workers again if we fell below the low watermark */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
(void) start_workers(m, /* explicit_request= */ true); /* Workers told us there's more work, let's add one more worker as long as we are below the high watermark */
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
event_source_hash_ops,
|
||||
sd_event_source,
|
||||
(void (*)(const sd_event_source*, struct siphash*)) trivial_hash_func,
|
||||
(int (*)(const sd_event_source*, const sd_event_source*)) trivial_compare_func,
|
||||
sd_event_source_disable_unref);
|
||||
|
||||
int manager_new(Manager **ret) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
int r;
|
||||
|
||||
m = new(Manager, 1);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
*m = (Manager) {
|
||||
.listen_fd = -EBADF,
|
||||
.worker_ratelimit = {
|
||||
.interval = 5 * USEC_PER_SEC,
|
||||
.burst = 50,
|
||||
},
|
||||
};
|
||||
|
||||
r = sd_event_new(&m->event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_set_signal_exit(m->event, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_add_signal(m->event, NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
|
||||
|
||||
r = sd_event_set_watchdog(m->event, true);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to enable watchdog handling, ignoring: %m");
|
||||
|
||||
r = sd_event_add_signal(m->event, NULL, SIGUSR2|SD_EVENT_SIGNAL_PROCMASK, on_sigusr2, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Manager* manager_free(Manager *m) {
|
||||
if (!m)
|
||||
return NULL;
|
||||
|
||||
set_free(m->workers_fixed);
|
||||
set_free(m->workers_dynamic);
|
||||
|
||||
/* Note: we rely on PR_DEATHSIG to kill the workers for us */
|
||||
|
||||
sd_event_unref(m->event);
|
||||
|
||||
return mfree(m);
|
||||
}
|
||||
|
||||
static int start_one_worker(Manager *m) {
|
||||
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *source = NULL;
|
||||
bool fixed;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
fixed = set_size(m->workers_fixed) < MOUNTFS_WORKERS_MIN;
|
||||
|
||||
r = safe_fork_full(
|
||||
"(sd-worker)",
|
||||
/* stdio_fds= */ NULL,
|
||||
&m->listen_fd, 1,
|
||||
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_CLOSE_ALL_FDS,
|
||||
&pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork new worker child: %m");
|
||||
if (r == 0) {
|
||||
char pids[DECIMAL_STR_MAX(pid_t)];
|
||||
/* Child */
|
||||
|
||||
if (m->listen_fd == 3) {
|
||||
r = fd_cloexec(3, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to turn off O_CLOEXEC for fd 3: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (dup2(m->listen_fd, 3) < 0) { /* dup2() creates with O_CLOEXEC off */
|
||||
log_error_errno(errno, "Failed to move listen fd to 3: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
safe_close(m->listen_fd);
|
||||
}
|
||||
|
||||
xsprintf(pids, PID_FMT, pid);
|
||||
if (setenv("LISTEN_PID", pids, 1) < 0) {
|
||||
log_error_errno(errno, "Failed to set $LISTEN_PID: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setenv("LISTEN_FDS", "1", 1) < 0) {
|
||||
log_error_errno(errno, "Failed to set $LISTEN_FDS: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (setenv("MOUNTFS_FIXED_WORKER", one_zero(fixed), 1) < 0) {
|
||||
log_error_errno(errno, "Failed to set $MOUNTFS_FIXED_WORKER: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = setenv_systemd_log_level();
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set $SYSTEMD_LOG_LEVEL: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = invoke_callout_binary(SYSTEMD_MOUNTWORK_PATH, STRV_MAKE("systemd-mountwork", "xxxxxxxxxxxxxxxx")); /* With some extra space rename_process() can make use of */
|
||||
log_error_errno(r, "Failed start worker process: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = sd_event_add_child(m->event, &source, pid, WEXITED, on_worker_exit, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to watch child " PID_FMT ": %m", pid);
|
||||
|
||||
r = set_ensure_put(
|
||||
fixed ? &m->workers_fixed : &m->workers_dynamic,
|
||||
&event_source_hash_ops,
|
||||
source);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add child process to set: %m");
|
||||
|
||||
TAKE_PTR(source);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_workers(Manager *m, bool explicit_request) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
for (;;) {
|
||||
size_t n;
|
||||
|
||||
n = manager_current_workers(m);
|
||||
|
||||
log_debug("%zu workers running.", n);
|
||||
|
||||
if (n >= MOUNTFS_WORKERS_MIN && (!explicit_request || n >= MOUNTFS_WORKERS_MAX))
|
||||
break;
|
||||
|
||||
if (!ratelimit_below(&m->worker_ratelimit)) {
|
||||
/* If we keep starting workers too often, let's fail the whole daemon, something is wrong */
|
||||
sd_event_exit(m->event, EXIT_FAILURE);
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), "Worker threads requested too frequently, something is wrong.");
|
||||
}
|
||||
|
||||
r = start_one_worker(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
explicit_request = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_startup(Manager *m) {
|
||||
int n;
|
||||
|
||||
assert(m);
|
||||
assert(m->listen_fd < 0);
|
||||
|
||||
n = sd_listen_fds(false);
|
||||
if (n < 0)
|
||||
return log_error_errno(n, "Failed to determine number of passed file descriptors: %m");
|
||||
if (n > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected one listening fd, got %i.", n);
|
||||
if (n == 1)
|
||||
m->listen_fd = SD_LISTEN_FDS_START;
|
||||
else {
|
||||
static const union sockaddr_union sockaddr = {
|
||||
.un.sun_family = AF_UNIX,
|
||||
.un.sun_path = "/run/systemd/io.systemd.MountFileSystem",
|
||||
};
|
||||
|
||||
m->listen_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
if (m->listen_fd < 0)
|
||||
return log_error_errno(errno, "Failed to bind on socket: %m");
|
||||
|
||||
(void) sockaddr_un_unlink(&sockaddr.un);
|
||||
|
||||
WITH_UMASK(0000)
|
||||
if (bind(m->listen_fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0)
|
||||
return log_error_errno(errno, "Failed to bind socket: %m");
|
||||
|
||||
if (listen(m->listen_fd, SOMAXCONN) < 0)
|
||||
return log_error_errno(errno, "Failed to listen on socket: %m");
|
||||
}
|
||||
|
||||
/* Let's make sure every accept() call on this socket times out after 25s. This allows workers to be
|
||||
* GC'ed on idle */
|
||||
if (setsockopt(m->listen_fd, SOL_SOCKET, SO_RCVTIMEO, TIMEVAL_STORE(LISTEN_TIMEOUT_USEC), sizeof(struct timeval)) < 0)
|
||||
return log_error_errno(errno, "Failed to se SO_RCVTIMEO: %m");
|
||||
|
||||
return start_workers(m, /* explicit_request= */ false);
|
||||
}
|
||||
30
src/mountfsd/mountfsd-manager.h
Normal file
30
src/mountfsd/mountfsd-manager.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "ratelimit.h"
|
||||
|
||||
#define MOUNTFS_WORKERS_MIN 3
|
||||
#define MOUNTFS_WORKERS_MAX 4096
|
||||
|
||||
struct Manager {
|
||||
sd_event *event;
|
||||
|
||||
Set *workers_fixed; /* Workers 0…MOUNTFS_WORKERS_MIN */
|
||||
Set *workers_dynamic; /* Workers MOUNTFS_WORKERS_MIN+1…MOUNTFS_WORKERS_MAX */
|
||||
|
||||
int listen_fd;
|
||||
|
||||
RateLimit worker_ratelimit;
|
||||
};
|
||||
|
||||
int manager_new(Manager **ret);
|
||||
Manager* manager_free(Manager *m);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||
|
||||
int manager_startup(Manager *m);
|
||||
43
src/mountfsd/mountfsd.c
Normal file
43
src/mountfsd/mountfsd.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "daemon-util.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "mountfsd-manager.h"
|
||||
#include "signal-util.h"
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
int r;
|
||||
|
||||
log_setup();
|
||||
|
||||
umask(0022);
|
||||
|
||||
if (argc != 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
|
||||
|
||||
r = manager_new(&m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not create manager: %m");
|
||||
|
||||
r = manager_startup(m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start up daemon: %m");
|
||||
|
||||
notify_stop = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
|
||||
|
||||
r = sd_event_loop(m->event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Event loop failed: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
703
src/mountfsd/mountwork.c
Normal file
703
src/mountfsd/mountwork.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -181,6 +181,7 @@ shared_sources = files(
|
||||
'varlink-io.systemd.Hostname.c',
|
||||
'varlink-io.systemd.Journal.c',
|
||||
'varlink-io.systemd.ManagedOOM.c',
|
||||
'varlink-io.systemd.MountFileSystem.c',
|
||||
'varlink-io.systemd.NamespaceResource.c',
|
||||
'varlink-io.systemd.Network.c',
|
||||
'varlink-io.systemd.PCRExtend.c',
|
||||
|
||||
69
src/shared/varlink-io.systemd.MountFileSystem.c
Normal file
69
src/shared/varlink-io.systemd.MountFileSystem.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "varlink-io.systemd.MountFileSystem.h"
|
||||
|
||||
static VARLINK_DEFINE_ENUM_TYPE(
|
||||
PartitionDesignator,
|
||||
VARLINK_DEFINE_ENUM_VALUE(root),
|
||||
VARLINK_DEFINE_ENUM_VALUE(usr),
|
||||
VARLINK_DEFINE_ENUM_VALUE(home),
|
||||
VARLINK_DEFINE_ENUM_VALUE(srv),
|
||||
VARLINK_DEFINE_ENUM_VALUE(esp),
|
||||
VARLINK_DEFINE_ENUM_VALUE(xbootldr),
|
||||
VARLINK_DEFINE_ENUM_VALUE(swap),
|
||||
VARLINK_DEFINE_ENUM_VALUE(root_verity),
|
||||
VARLINK_DEFINE_ENUM_VALUE(usr_verity),
|
||||
VARLINK_DEFINE_ENUM_VALUE(root_verity_sig),
|
||||
VARLINK_DEFINE_ENUM_VALUE(usr_verity_sig),
|
||||
VARLINK_DEFINE_ENUM_VALUE(tmp),
|
||||
VARLINK_DEFINE_ENUM_VALUE(var));
|
||||
|
||||
static VARLINK_DEFINE_STRUCT_TYPE(
|
||||
PartitionInfo,
|
||||
VARLINK_DEFINE_FIELD(designator, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_FIELD(writable, VARLINK_BOOL, 0),
|
||||
VARLINK_DEFINE_FIELD(growFileSystem, VARLINK_BOOL, 0),
|
||||
VARLINK_DEFINE_FIELD(partitionNumber, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(architecture, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(partitionUuid, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(fileSystemType, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_FIELD(partitionLabel, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(size, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_FIELD(offset, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_FIELD(mountFileDescriptor, VARLINK_INT, 0));
|
||||
|
||||
static VARLINK_DEFINE_METHOD(
|
||||
MountImage,
|
||||
VARLINK_DEFINE_INPUT(imageFileDescriptor, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_INPUT(userNamespaceFileDescriptor, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(readOnly, VARLINK_BOOL, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(growFileSystems, VARLINK_BOOL, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(password, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(imagePolicy, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(allowInteractiveAuthentication, VARLINK_BOOL, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT_BY_TYPE(partitions, PartitionInfo, VARLINK_ARRAY),
|
||||
VARLINK_DEFINE_OUTPUT(imagePolicy, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_OUTPUT(imageSize, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_OUTPUT(sectorSize, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_OUTPUT(imageName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT(imageUuid, VARLINK_STRING, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_ERROR(IncompatibleImage);
|
||||
static VARLINK_DEFINE_ERROR(MultipleRootPartitionsFound);
|
||||
static VARLINK_DEFINE_ERROR(RootPartitionNotFound);
|
||||
static VARLINK_DEFINE_ERROR(DeniedByImagePolicy);
|
||||
static VARLINK_DEFINE_ERROR(KeyNotFound);
|
||||
static VARLINK_DEFINE_ERROR(VerityFailure);
|
||||
|
||||
VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_MountFileSystem,
|
||||
"io.systemd.MountFileSystem",
|
||||
&vl_type_PartitionDesignator,
|
||||
&vl_type_PartitionInfo,
|
||||
&vl_method_MountImage,
|
||||
&vl_error_IncompatibleImage,
|
||||
&vl_error_MultipleRootPartitionsFound,
|
||||
&vl_error_RootPartitionNotFound,
|
||||
&vl_error_DeniedByImagePolicy,
|
||||
&vl_error_KeyNotFound,
|
||||
&vl_error_VerityFailure);
|
||||
6
src/shared/varlink-io.systemd.MountFileSystem.h
Normal file
6
src/shared/varlink-io.systemd.MountFileSystem.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "varlink-idl.h"
|
||||
|
||||
extern const VarlinkInterface vl_interface_io_systemd_MountFileSystem;
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "varlink-io.systemd.Credentials.h"
|
||||
#include "varlink-io.systemd.Journal.h"
|
||||
#include "varlink-io.systemd.ManagedOOM.h"
|
||||
#include "varlink-io.systemd.MountFileSystem.h"
|
||||
#include "varlink-io.systemd.NamespaceResource.h"
|
||||
#include "varlink-io.systemd.Network.h"
|
||||
#include "varlink-io.systemd.PCRExtend.h"
|
||||
@@ -140,6 +141,8 @@ TEST(parse_format) {
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_ManagedOOM);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_MountFileSystem);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_Network);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_oom);
|
||||
|
||||
@@ -732,6 +732,14 @@ units = [
|
||||
'file' : 'systemd-userdbd.socket',
|
||||
'conditions' : ['ENABLE_USERDB'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-mountfsd.service.in',
|
||||
'conditions' : ['ENABLE_MOUNTFSD'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-mountfsd.socket',
|
||||
'conditions' : ['ENABLE_MOUNTFSD'],
|
||||
},
|
||||
{
|
||||
'file' : 'systemd-nsresourced.service.in',
|
||||
'conditions' : ['ENABLE_NSRESOURCED'],
|
||||
|
||||
46
units/systemd-mountfsd.service.in
Normal file
46
units/systemd-mountfsd.service.in
Normal file
@@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=DDI File System Mounter
|
||||
Documentation=man:systemd-mountfsd.service(8)
|
||||
Requires=systemd-mountfsd.socket
|
||||
After=systemd-mountfsd.socket
|
||||
Conflicts=shutdown.target
|
||||
Before=sysinit.target shutdown.target
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
#CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_SYS_RESOURCE CAP_BPF CAP_PERFMON CAP_SETGID CAP_SETUID
|
||||
ExecStart={{LIBEXECDIR}}/systemd-mountfsd
|
||||
IPAddressDeny=any
|
||||
LimitNOFILE={{HIGH_RLIMIT_NOFILE}}
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
NoNewPrivileges=yes
|
||||
ProtectProc=invisible
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectHostname=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectSystem=strict
|
||||
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
|
||||
RestrictRealtime=yes
|
||||
RestrictSUIDSGID=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallErrorNumber=EPERM
|
||||
SystemCallFilter=@system-service @mount
|
||||
Type=notify
|
||||
NotifyAccess=all
|
||||
FileDescriptorStoreMax=4096
|
||||
{{SERVICE_WATCHDOG}}
|
||||
|
||||
[Install]
|
||||
Also=systemd-mountfsd.socket
|
||||
22
units/systemd-mountfsd.socket
Normal file
22
units/systemd-mountfsd.socket
Normal file
@@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=DDI File System Mounter Socket
|
||||
Documentation=man:systemd-mountfsd.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Before=sockets.target shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.MountFileSystem
|
||||
SocketMode=0666
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
Reference in New Issue
Block a user