diff options
-rw-r--r-- | man/org.freedesktop.systemd1.xml | 6 | ||||
-rw-r--r-- | man/systemd.automount.xml | 9 | ||||
-rw-r--r-- | src/core/automount.c | 36 | ||||
-rw-r--r-- | src/core/automount.h | 1 | ||||
-rw-r--r-- | src/core/dbus-automount.c | 4 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.in | 1 | ||||
-rw-r--r-- | src/shared/bus-unit-util.c | 3 | ||||
-rw-r--r-- | test/fuzz/fuzz-unit-file/directives.automount | 1 | ||||
-rw-r--r-- | test/test-functions | 22 | ||||
-rwxr-xr-x | test/units/testsuite-55.sh | 19 |
10 files changed, 81 insertions, 21 deletions
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 86bf7ef108..e878f65de1 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -7595,6 +7595,8 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s Where = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ExtraOptions = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly u DirectoryMode = ...; readonly s Result = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -7609,6 +7611,8 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount <!--property Where is not documented!--> + <!--property ExtraOptions is not documented!--> + <!--property DirectoryMode is not documented!--> <!--property TimeoutIdleUSec is not documented!--> @@ -7625,6 +7629,8 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount <variablelist class="dbus-property" generated="True" extra-ref="Where"/> + <variablelist class="dbus-property" generated="True" extra-ref="ExtraOptions"/> + <variablelist class="dbus-property" generated="True" extra-ref="DirectoryMode"/> <variablelist class="dbus-property" generated="True" extra-ref="Result"/> diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml index 37fd743552..da35a7d26b 100644 --- a/man/systemd.automount.xml +++ b/man/systemd.automount.xml @@ -145,6 +145,15 @@ </varlistentry> <varlistentry> + <term><varname>ExtraOptions=</varname></term> + <listitem><para>Extra mount options to use when creating the autofs + mountpoint. This takes a comma-separated list of options. This setting + is optional. Note that the usual specifier expansion is applied to this + setting, literal percent characters should hence be written as + <literal class='specifiers'>%%</literal>.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>DirectoryMode=</varname></term> <listitem><para>Directories of automount points (and any parent directories) are automatically created if needed. This diff --git a/src/core/automount.c b/src/core/automount.c index 0bb58fdcd1..02089aed4e 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -19,6 +19,7 @@ #include "dbus-unit.h" #include "fd-util.h" #include "format-util.h" +#include "fstab-util.h" #include "io-util.h" #include "label.h" #include "mkdir-label.h" @@ -109,6 +110,7 @@ static void automount_done(Unit *u) { unmount_autofs(a); a->where = mfree(a->where); + a->extra_options = mfree(a->extra_options); a->tokens = set_free(a->tokens); a->expire_tokens = set_free(a->expire_tokens); @@ -168,6 +170,15 @@ static int automount_add_default_dependencies(Automount *a) { } static int automount_verify(Automount *a) { + static const char *const reserved_options[] = { + "fd\0", + "pgrp\0", + "minproto\0", + "maxproto\0", + "direct\0", + "indirect\0", + }; + _cleanup_free_ char *e = NULL; int r; @@ -184,6 +195,14 @@ static int automount_verify(Automount *a) { if (!unit_has_name(UNIT(a), e)) return log_unit_error_errno(UNIT(a), SYNTHETIC_ERRNO(ENOEXEC), "Where= setting doesn't match unit name. Refusing."); + for (size_t i = 0; i < ELEMENTSOF(reserved_options); i++) + if (fstab_test_option(a->extra_options, reserved_options[i])) + return log_unit_error_errno( + UNIT(a), + SYNTHETIC_ERRNO(ENOEXEC), + "ExtraOptions= setting may not contain reserved option %s.", + reserved_options[i]); + return 0; } @@ -313,11 +332,13 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) { "%sAutomount State: %s\n" "%sResult: %s\n" "%sWhere: %s\n" + "%sExtraOptions: %s\n" "%sDirectoryMode: %04o\n" "%sTimeoutIdleUSec: %s\n", prefix, automount_state_to_string(a->state), prefix, automount_result_to_string(a->result), prefix, a->where, + prefix, a->extra_options, prefix, a->directory_mode, prefix, FORMAT_TIMESPAN(a->timeout_idle_usec, USEC_PER_SEC)); } @@ -552,8 +573,7 @@ static void automount_enter_waiting(Automount *a) { _cleanup_close_ int ioctl_fd = -1; int p[2] = { -1, -1 }; char name[STRLEN("systemd-") + DECIMAL_STR_MAX(pid_t) + 1]; - char options[STRLEN("fd=,pgrp=,minproto=5,maxproto=5,direct") - + DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1]; + _cleanup_free_ char *options = NULL; bool mounted = false; int r, dev_autofs_fd; struct stat st; @@ -586,7 +606,17 @@ static void automount_enter_waiting(Automount *a) { if (r < 0) goto fail; - xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp()); + if (asprintf( + &options, + "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct%s%s", + p[1], + getpgrp(), + isempty(a->extra_options) ? "" : ",", + strempty(a->extra_options)) < 0) { + r = -ENOMEM; + goto fail; + } + xsprintf(name, "systemd-"PID_FMT, getpid_cached()); r = mount_nofollow(name, a->where, "autofs", 0, options); if (r < 0) diff --git a/src/core/automount.h b/src/core/automount.h index 4b0c633b79..684f2759a6 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -22,6 +22,7 @@ struct Automount { AutomountState state, deserialized_state; char *where; + char *extra_options; usec_t timeout_idle_usec; int pipe_fd; diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c index 3f74488dad..881bf50b6e 100644 --- a/src/core/dbus-automount.c +++ b/src/core/dbus-automount.c @@ -11,6 +11,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, Autom const sd_bus_vtable bus_automount_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ExtraOptions", "s", NULL, offsetof(Automount, extra_options), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST), @@ -35,6 +36,9 @@ static int bus_automount_set_transient_property( if (streq(name, "Where")) return bus_set_transient_path(u, name, &a->where, message, flags, error); + if (streq(name, "ExtraOptions")) + return bus_set_transient_string(u, name, &a->extra_options, message, flags, error); + if (streq(name, "TimeoutIdleUSec")) return bus_set_transient_usec_fix_0(u, name, &a->timeout_idle_usec, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 71a5904a70..67cb2d70a2 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -503,6 +503,7 @@ Mount.ReadWriteOnly, config_parse_bool, {{ CGROUP_CONTEXT_CONFIG_ITEMS('Mount') }} {{ KILL_CONTEXT_CONFIG_ITEMS('Mount') }} Automount.Where, config_parse_unit_path_printf, 0, offsetof(Automount, where) +Automount.ExtraOptions, config_parse_unit_string_printf, 0, offsetof(Automount, extra_options) Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) Automount.TimeoutIdleSec, config_parse_sec_fix_0, 0, offsetof(Automount, timeout_idle_usec) Swap.What, config_parse_unit_path_printf, 0, offsetof(Swap, parameters_fragment.what) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index bbf7499e57..b8fd85a191 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -894,7 +894,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons } static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) { - if (streq(field, "Where")) + if (STR_IN_SET(field, "Where", + "ExtraOptions")) return bus_append_string(m, field, eq); if (streq(field, "DirectoryMode")) diff --git a/test/fuzz/fuzz-unit-file/directives.automount b/test/fuzz/fuzz-unit-file/directives.automount index 70772ba06d..fd0ce64a2e 100644 --- a/test/fuzz/fuzz-unit-file/directives.automount +++ b/test/fuzz/fuzz-unit-file/directives.automount @@ -3,3 +3,4 @@ automount DirectoryMode= TimeoutIdleSec= Where= +ExtraOptions= diff --git a/test/test-functions b/test/test-functions index 00a808bf28..a4b7efb5ec 100644 --- a/test/test-functions +++ b/test/test-functions @@ -778,9 +778,23 @@ if [[ ! -e "$ASAN_RT_PATH" ]]; then exit 1 fi +# Suppress certain leaks reported by LSan (either in external tools or bogus +# ones) +# Docs: # https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#suppressions +# +# - fsck is called by systemd-homed and is reporting a leak we're not interested +# in +# - libLLVM is a "side effect" caused by the previous fsck leak +cat >/systemd-lsan.supp <<INNER_EOF +leak:/bin/fsck$ +leak:/sbin/fsck$ +leak:/lib/libLLVM +INNER_EOF + +DEFAULT_LSAN_OPTIONS=${LSAN_OPTIONS:-}:suppressions=/systemd-lsan.supp DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1} DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1} -DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS" +DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS LSAN_OPTIONS=\$DEFAULT_LSAN_OPTIONS" # As right now bash is the PID 1, we can't expect PATH to have a sane value. # Let's make one to prevent unexpected "<bin> not found" issues in the future @@ -2083,7 +2097,7 @@ dfatal() { # Generic substring function. If $2 is in $1, return 0. -strstr() { [ "${1#*$2*}" != "$1" ]; } +strstr() { [ "${1#*"$2"*}" != "$1" ]; } # normalize_path <path> # Prints the normalized path, where it removes any duplicated @@ -2498,12 +2512,12 @@ image_install() { install_kmod_with_fw() { local module="${1:?}" # no need to go further if the module is already installed - [[ -e "${initdir:?}/lib/modules/${KERNEL_VER:?}/${module##*/lib/modules/$KERNEL_VER/}" ]] && return 0 + [[ -e "${initdir:?}/lib/modules/${KERNEL_VER:?}/${module##*"/lib/modules/$KERNEL_VER/"}" ]] && return 0 [[ -e "$initdir/.kernelmodseen/${module##*/}" ]] && return 0 [ -d "$initdir/.kernelmodseen" ] && : >"$initdir/.kernelmodseen/${module##*/}" - inst_simple "$module" "/lib/modules/$KERNEL_VER/${module##*/lib/modules/$KERNEL_VER/}" || return $? + inst_simple "$module" "/lib/modules/$KERNEL_VER/${module##*"/lib/modules/$KERNEL_VER/"}" || return $? local modname="${module##*/}" local fwdir found fw diff --git a/test/units/testsuite-55.sh b/test/units/testsuite-55.sh index b265c8cce7..db13964311 100755 --- a/test/units/testsuite-55.sh +++ b/test/units/testsuite-55.sh @@ -60,36 +60,29 @@ if ! systemctl status testsuite-55-testchill.service; then exit 24; fi # Make sure we also work correctly on user units. -runas() { - declare userid=$1 - shift - # shellcheck disable=SC2016 - su "$userid" -s /bin/sh -c 'XDG_RUNTIME_DIR=/run/user/$UID exec "$@"' -- sh "$@" -} - -runas testuser systemctl start --user testsuite-55-testchill.service -runas testuser systemctl start --user testsuite-55-testbloat.service +systemctl start --machine "testuser@.host" --user testsuite-55-testchill.service +systemctl start --machine "testuser@.host" --user testsuite-55-testbloat.service # Verify systemd-oomd is monitoring the expected units oomctl | grep -E "/user.slice.*/testsuite-55-workload.slice" oomctl | grep "20.00%" oomctl | grep "Default Memory Pressure Duration: 2s" -runas testuser systemctl --user status testsuite-55-testchill.service +systemctl --machine "testuser@.host" --user status testsuite-55-testchill.service # systemd-oomd watches for elevated pressure for 2 seconds before acting. # It can take time to build up pressure so either wait 2 minutes or for the service to fail. timeout="$(date -ud "2 minutes" +%s)" while [[ $(date -u +%s) -le $timeout ]]; do - if ! runas testuser systemctl --user status testsuite-55-testbloat.service; then + if ! systemctl --machine "testuser@.host" --user status testsuite-55-testbloat.service; then break fi sleep 2 done # testbloat should be killed and testchill should be fine -if runas testuser systemctl --user status testsuite-55-testbloat.service; then exit 42; fi -if ! runas testuser systemctl --user status testsuite-55-testchill.service; then exit 24; fi +if systemctl --machine "testuser@.host" --user status testsuite-55-testbloat.service; then exit 42; fi +if ! systemctl --machine "testuser@.host" --user status testsuite-55-testchill.service; then exit 24; fi # only run this portion of the test if we can set xattrs if setfattr -n user.xattr_test -v 1 /sys/fs/cgroup/; then |