diff --git a/.semaphore/semaphore-runner.sh b/.semaphore/semaphore-runner.sh index 4a37ee20149..87ba3a694d2 100755 --- a/.semaphore/semaphore-runner.sh +++ b/.semaphore/semaphore-runner.sh @@ -11,7 +11,8 @@ SALSA_URL="${SALSA_URL:-https://salsa.debian.org/systemd-team/systemd.git}" BRANCH="${BRANCH:-upstream-ci}" ARCH="${ARCH:-amd64}" CONTAINER="${RELEASE}-${ARCH}" -CACHE_DIR="${SEMAPHORE_CACHE_DIR:-/tmp}" +CACHE_DIR=/var/tmp +TMPDIR=/var/tmp AUTOPKGTEST_DIR="${CACHE_DIR}/autopkgtest" # semaphore cannot expose these, but useful for interactive/local runs ARTIFACTS_DIR=/tmp/artifacts @@ -64,7 +65,7 @@ for phase in "${PHASES[@]}"; do sudo apt-get install -y -t "$UBUNTU_RELEASE-backports" lxc sudo apt-get install -y python3-debian git dpkg-dev fakeroot python3-jinja2 - [ -d "$AUTOPKGTEST_DIR" ] || git clone --quiet --branch=debian/5.32 --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR" + [ -d "$AUTOPKGTEST_DIR" ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR" create_container ;; @@ -91,7 +92,7 @@ EOF # disable autopkgtests which are not for upstream sed -i '/# NOUPSTREAM/ q' debian/tests/control # enable more unit tests - sed -i '/^CONFFLAGS =/ s/=/= --werror -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true -Dfuzz-tests=true -Dman=true /' debian/rules + sed -i '/^CONFFLAGS =/ s/=/= --werror -Dsplit-usr=true /' debian/rules # no orig tarball echo '1.0' > debian/source/format @@ -101,8 +102,11 @@ EOF # now build the package and run the tests rm -rf "$ARTIFACTS_DIR" # autopkgtest exits with 2 for "some tests skipped", accept that - sudo "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS=noudeb \ - --env TEST_UPSTREAM=1 ../systemd_*.dsc \ + sudo TMPDIR=/var/tmp "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS="noudeb nostrip nodoc optimize=-lto" \ + --env DPKG_DEB_COMPRESSOR_TYPE="none" \ + --env DEB_BUILD_PROFILES="noudeb nodoc" \ + --env TEST_UPSTREAM=1 \ + ../systemd_*.dsc \ -o "$ARTIFACTS_DIR" \ -- lxc -s "$CONTAINER" \ || [ $? -eq 2 ] diff --git a/hwdb.d/60-evdev.hwdb b/hwdb.d/60-evdev.hwdb index 0b70a82093c..372ae682ed7 100644 --- a/hwdb.d/60-evdev.hwdb +++ b/hwdb.d/60-evdev.hwdb @@ -255,6 +255,13 @@ evdev:input:b0003v0ED1p7821* # Dell ######################################### +# Dell AlpsPS/2 ALPS DualPoint TouchPad +evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*:svnDellInc.*:pnLatitudeE7440*: + EVDEV_ABS_00=:::28 + EVDEV_ABS_01=:::28 + EVDEV_ABS_35=:::28 + EVDEV_ABS_36=:::28 + # Dell Vostro 1510 evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510:* EVDEV_ABS_00=::14 diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb index 15c0d4ca31f..5a089316360 100644 --- a/hwdb.d/60-keyboard.hwdb +++ b/hwdb.d/60-keyboard.hwdb @@ -223,7 +223,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPackard*Bell*:pn*:* # Swift SF314-511 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnSwiftSF314-511:pvr* - KEYBOARD_KEY_8a=f20 # Fn+F12, microphone mute + KEYBOARD_KEY_8a=f20 # Fn+F12, microphone mute # Predator PHN16-71 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-71:* @@ -231,6 +231,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-71:* KEYBOARD_KEY_f5=prog1 # "predator sense" button KEYBOARD_KEY_66=micmute # Microphone mute button +# Predator PHN16-72 +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-72:* + KEYBOARD_KEY_66=micmute # Microphone mute button + # Nitro AN515-58 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnNitro*AN*515-58:pvr* KEYBOARD_KEY_8a=f20 # Microphone mute button @@ -259,7 +263,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pnM17xR3:* # Aquarius Cmp NS483 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAquarius*:pnCmp*NS483*:* KEYBOARD_KEY_56=backslash - KEYBOARD_KEY_76=f21 # Touchpad Toggle + KEYBOARD_KEY_76=f21 # Touchpad Toggle ########################################################### # Asus @@ -341,6 +345,9 @@ evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnV54x_6x_TU:* KEYBOARD_KEY_f7=f21 # Touchpad Toggle KEYBOARD_KEY_f8=f21 # Touchpad Toggle +evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnV5xTNC_TND_TNE:* + KEYBOARD_KEY_81=f20 # Fn+4; Mic Mute + ########################################################### # Compal ########################################################### @@ -973,7 +980,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnJP-IK:pnLEAPW502:pvr* # LE14U/LE15U evdev:atkbd:dmi:bvn*:bvr*:bd*:svnKVADRA*:pn*LE1*U*:* - KEYBOARD_KEY_76=f21 # Fn+F1 Toggle touchpad, sends meta+ctrl+toggle + KEYBOARD_KEY_76=f21 # Fn+F1 Toggle touchpad, sends meta+ctrl+toggle ########################################################### # Lenovo @@ -1901,9 +1908,9 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:* # Galaxy Book (2021) NP750XDA-KD4SE evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn750XDA:pvr* KEYBOARD_KEY_81=!esc - KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings - KEYBOARD_KEY_ae=!volumedown # Fn+F7 volume down - KEYBOARD_KEY_b0=!volumeup # Fn+F8 volume up + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings + KEYBOARD_KEY_ae=!volumedown # Fn+F7 volume down + KEYBOARD_KEY_b0=!volumeup # Fn+F8 volume up ########################################################### @@ -2028,13 +2035,13 @@ evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A: # Portege Z830 ACPI quickstart buttons evdev:name:Quickstart Button 1:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:* - KEYBOARD_KEY_1=prog1 # TOSHIBA eco button + KEYBOARD_KEY_1=prog1 # TOSHIBA eco button evdev:name:Quickstart Button 2:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:* - KEYBOARD_KEY_1=prog2 # TOSHIBA Presentation button + KEYBOARD_KEY_1=prog2 # TOSHIBA Presentation button evdev:name:Quickstart Button 3:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:* - KEYBOARD_KEY_1=f21 # Touchpad toggle + KEYBOARD_KEY_1=f21 # Touchpad toggle ########################################################### # VIA @@ -2067,11 +2074,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINET:pnP325J:* # Home: LeftCtrl + Esc -> LeftMeta (ignore LeftCtrl, map Esc to LeftMeta) # Back: Backspace -> back (map backspace to back) evdev:name:FTSC1000:00 2808:509C Keyboard:dmi:*:svnXiaomiInc:pnMipad2:* - KEYBOARD_KEY_700e0=unknown # LeftCtrl -> ignore - KEYBOARD_KEY_700e3=unknown # LeftMeta -> ignore - KEYBOARD_KEY_70016=menu # S -> menu - KEYBOARD_KEY_70029=leftmeta # Esc -> LeftMeta (Windows key / Win8 tablets home) - KEYBOARD_KEY_7002a=back # Backspace -> back + KEYBOARD_KEY_700e0=unknown # LeftCtrl -> ignore + KEYBOARD_KEY_700e3=unknown # LeftMeta -> ignore + KEYBOARD_KEY_70016=menu # S -> menu + KEYBOARD_KEY_70029=leftmeta # Esc -> LeftMeta (Windows key / Win8 tablets home) + KEYBOARD_KEY_7002a=back # Backspace -> back ########################################################### # Zepto @@ -2183,7 +2190,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnViewSonic:pnVPAD10:* evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO:pnVJPW1[12]F11X*:pvr*:* # Vaio FE14 (VJFE41F11X, VJE42F11X, VJFE44F11X, VJFE54F11X) evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO:pnVJFE*:pvr*:* - KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad + KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad ########################################################### # Positivo @@ -2288,6 +2295,18 @@ evdev:input:b0003v05FEp1010* # # Presence of a LED is implicit when the property is absent. +# Apple Wireless keyboards +evdev:input:b0005v05aCp022C* +evdev:input:b0005v05aCp022D* +evdev:input:b0005v05aCp022E* +evdev:input:b0005v05aCp0239* +evdev:input:b0005v05aCp023A* +evdev:input:b0005v05aCp023B* +evdev:input:b0005v05aCp0255* +evdev:input:b0005v05aCp0256* +evdev:input:b0005v05aCp0257* + KEYBOARD_LED_NUMLOCK=0 + # Logitech K750 evdev:input:b0003v046Dp4002* KEYBOARD_LED_NUMLOCK=0 diff --git a/hwdb.d/60-sensor.hwdb b/hwdb.d/60-sensor.hwdb index 21f4380dd08..80547834d24 100644 --- a/hwdb.d/60-sensor.hwdb +++ b/hwdb.d/60-sensor.hwdb @@ -152,6 +152,7 @@ sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnM80TA:* sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TA:* sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TAF:* sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TAM:* +sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TAS:* sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT200TA:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 @@ -163,6 +164,7 @@ sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LA:* sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LD:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 +sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pn*Q551LB:* sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pn*Q551LN:* ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1 diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 1e12e8f6827..5bd38134603 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -2344,18 +2344,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { was already active). ActiveState contains a state value that reflects whether the unit is currently - active or not. The following states are currently defined: active, - reloading, inactive, failed, - activating, and deactivating. active indicates - that unit is active (obviously...). reloading indicates that the unit is active and - currently reloading its configuration. inactive indicates that it is inactive and - the previous run was successful or no previous run has taken place yet. failed - indicates that it is inactive and the previous run was not successful (more information about the - reason for this is available on the unit type specific interfaces, for example for services in the - Result property, see below). activating indicates that the unit - has previously been inactive but is currently in the process of entering an active state. Conversely - deactivating indicates that the unit is currently in the process of - deactivation. + active or not. The following states are currently defined: + + SubState encodes states of the same state machine that ActiveState covers, but knows more fine-grained states that are diff --git a/man/sd_bus_message_append_array.xml b/man/sd_bus_message_append_array.xml index da72b78cb07..94bbb8be774 100644 --- a/man/sd_bus_message_append_array.xml +++ b/man/sd_bus_message_append_array.xml @@ -34,7 +34,7 @@ int sd_bus_message_append_array sd_bus_message *m char type - void *ptr + const void *ptr size_t size diff --git a/man/systemctl.xml b/man/systemctl.xml index 862609fe5af..cfaf8a8cb59 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -96,12 +96,15 @@ To show all installed unit files use 'systemctl list-unit-files'.The LOAD column shows the load state, one of loaded, not-found, bad-setting, error, - masked. The ACTIVE columns shows the general unit state, one of - active, reloading, inactive, - failed, activating, deactivating. The SUB - column shows the unit-type-specific detailed state of the unit, possible values vary by unit type. The list - of possible LOAD, ACTIVE, and SUB states is not constant and new systemd releases may both add and remove - values. systemctl --state=help command maybe be used to display the + masked. The ACTIVE columns shows the general unit state, one of the + following: + + + + The SUB column shows the unit-type-specific detailed state of the unit, possible values + vary by unit type. The list of possible LOAD, ACTIVE, and SUB states is not constant and new + systemd releases may both add and remove values. + systemctl --state=help command may be used to display the current set of possible values. This is the default command. diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 85eb8ad0762..46a148bc1ba 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -229,6 +229,11 @@ names like single, rescue, 1, 3, 5, …; see systemd1. + + For typical unit files please set WantedBy= to a regular target (like + multi-user.target or graphical.target), + instead of default.target, since such a service will also be run on special + boots like on system update, emergency boot… diff --git a/man/systemd.xml b/man/systemd.xml index d292ceb5ab7..126382c4b0e 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -74,21 +74,12 @@ configuration files, whose syntax and basic set of options is described in systemd.unit5, - however some are created automatically from other configuration - files, dynamically from system state or programmatically at runtime. - Units may be "active" (meaning started, bound, plugged in, …, - depending on the unit type, see below), or "inactive" (meaning - stopped, unbound, unplugged, …), as well as in the process of - being activated or deactivated, i.e. between the two states (these - states are called "activating", "deactivating"). A special - "failed" state is available as well, which is very similar to - "inactive" and is entered when the service failed in some way - (process returned error code on exit, or crashed, an operation - timed out, or after too many restarts). If this state is entered, - the cause will be logged, for later reference. Note that the - various unit types may have a number of additional substates, - which are mapped to the five generalized unit states described - here. + however some are created automatically from other configuration files, dynamically from system state or + programmatically at runtime. Units may be in a number of states, described in the following table. Note + that the various unit types may have a number of additional substates, which are mapped to the + generalized unit states described here. + + The following unit types are available: diff --git a/man/unit-states.xml b/man/unit-states.xml new file mode 100644 index 00000000000..b772c3f19a7 --- /dev/null +++ b/man/unit-states.xml @@ -0,0 +1,56 @@ + + + + + + + + + <table id="table"> + <title>Unit ACTIVE states + + + + + + State + Description + + + + + active + Started, bound, plugged in, …, depending on the unit type. + + + inactive + Stopped, unbound, unplugged, …, depending on the unit type. + + + failed + Similar to inactive, but the unit failed in some way (process returned error code on exit, crashed, an operation timed out, or after too many restarts). + + + + activating + Changing from inactive to active. + + + deactivating + Changing from active to inactive. + + + maintenance + Unit is inactive and a maintenance operation is in progress. + + + reloading + Unit is active and it is reloading its configuration. + + + + + + diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index f2dce206b37..fb72e4ce336 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -101,7 +101,7 @@ static int try_audit_request(int fd) { n = recvmsg_safe(fd, &mh, 0); if (n < 0) - return -errno; + return n; if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr))) return -EIO; diff --git a/src/basic/missing_loop.h b/src/basic/missing_loop.h index 24b3e0def9f..e9c8bae6622 100644 --- a/src/basic/missing_loop.h +++ b/src/basic/missing_loop.h @@ -22,3 +22,7 @@ struct loop_config { #ifndef LOOP_SET_STATUS_SETTABLE_FLAGS #define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN) #endif + +#ifndef LOOP_SET_BLOCK_SIZE +# define LOOP_SET_BLOCK_SIZE 0x4C09 +#endif diff --git a/src/basic/os-util.c b/src/basic/os-util.c index 8f8bb0881e9..27faf0a6eea 100644 --- a/src/basic/os-util.c +++ b/src/basic/os-util.c @@ -44,8 +44,9 @@ int path_is_extension_tree(const char *path, const char *extension, bool relax_e /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir * always results in -ENOENT, and we can properly distinguish the case where the whole root doesn't exist from * the case where just the os-release file is missing. */ - if (laccess(path, F_OK) < 0) - return -errno; + r = laccess(path, F_OK); + if (r < 0) + return r; /* We use /usr/lib/extension-release.d/extension-release[.NAME] as flag for something being a system extension, * and {/etc|/usr/lib}/os-release as a flag for something being an OS (when not an extension). */ diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c index 36f386254b7..1fe4bb5fbdd 100644 --- a/src/basic/path-lookup.c +++ b/src/basic/path-lookup.c @@ -881,6 +881,7 @@ char **env_generator_binary_paths(bool is_system) { int find_portable_profile(const char *name, const char *unit, char **ret_path) { const char *p, *dot; + int r; assert(name); assert(ret_path); @@ -894,13 +895,13 @@ int find_portable_profile(const char *name, const char *unit, char **ret_path) { if (!joined) return -ENOMEM; - if (laccess(joined, F_OK) >= 0) { + r = laccess(joined, F_OK); + if (r >= 0) { *ret_path = TAKE_PTR(joined); return 0; } - - if (errno != ENOENT) - return -errno; + if (r != -ENOENT) + return r; } return -ENOENT; diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index 94cd603e32c..31d4dc8b1e3 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -96,6 +96,7 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); +/* Keep in sync with man/unit-states.xml */ static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { [UNIT_ACTIVE] = "active", [UNIT_RELOADING] = "reloading", diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 2c1828c3908..4663ae16b9e 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1506,7 +1506,7 @@ static void config_entry_add_type1( if (streq8(key, "architecture")) { /* do not add an entry for an EFI image of architecture not matching with that of the image */ - if (!streq8(value, EFI_MACHINE_TYPE_NAME)) { + if (!strcaseeq8(value, EFI_MACHINE_TYPE_NAME)) { entry->type = LOADER_UNDEFINED; break; } diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index ee4002f7b46..3a88769b6dc 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -1259,7 +1259,7 @@ int bus_cgroup_set_property( for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) a->limits[type] = cgroup_io_limit_defaults[type]; - LIST_PREPEND(device_limits, c->io_device_limits, a); + LIST_APPEND(device_limits, c->io_device_limits, a); } a->limits[iol_type] = u64; @@ -1338,7 +1338,7 @@ int bus_cgroup_set_property( free(a); return -ENOMEM; } - LIST_PREPEND(device_weights, c->io_device_weights, a); + LIST_APPEND(device_weights, c->io_device_weights, a); } a->weight = weight; @@ -1411,7 +1411,7 @@ int bus_cgroup_set_property( free(a); return -ENOMEM; } - LIST_PREPEND(device_latencies, c->io_device_latencies, a); + LIST_APPEND(device_latencies, c->io_device_latencies, a); } a->target_usec = target; @@ -1491,7 +1491,7 @@ int bus_cgroup_set_property( return -ENOMEM; } - LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); + LIST_APPEND(device_bandwidths, c->blockio_device_bandwidths, a); } if (read) @@ -1585,7 +1585,7 @@ int bus_cgroup_set_property( free(a); return -ENOMEM; } - LIST_PREPEND(device_weights, c->blockio_device_weights, a); + LIST_APPEND(device_weights, c->blockio_device_weights, a); } a->weight = weight; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 11166f9509d..224e41873c0 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -4237,7 +4237,7 @@ int config_parse_io_device_weight( w->path = TAKE_PTR(resolved); w->weight = u; - LIST_PREPEND(device_weights, c->io_device_weights, w); + LIST_APPEND(device_weights, c->io_device_weights, w); return 0; } @@ -4308,7 +4308,7 @@ int config_parse_io_device_latency( l->path = TAKE_PTR(resolved); l->target_usec = usec; - LIST_PREPEND(device_latencies, c->io_device_latencies, l); + LIST_APPEND(device_latencies, c->io_device_latencies, l); return 0; } @@ -4396,7 +4396,7 @@ int config_parse_io_limit( for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++) l->limits[ttype] = cgroup_io_limit_defaults[ttype]; - LIST_PREPEND(device_limits, c->io_device_limits, l); + LIST_APPEND(device_limits, c->io_device_limits, l); } l->limits[type] = num; @@ -4477,7 +4477,7 @@ int config_parse_blockio_device_weight( w->path = TAKE_PTR(resolved); w->weight = u; - LIST_PREPEND(device_weights, c->blockio_device_weights, w); + LIST_APPEND(device_weights, c->blockio_device_weights, w); return 0; } @@ -4564,7 +4564,7 @@ int config_parse_blockio_bandwidth( b->rbps = CGROUP_LIMIT_MAX; b->wbps = CGROUP_LIMIT_MAX; - LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b); + LIST_APPEND(device_bandwidths, c->blockio_device_bandwidths, b); } if (read) diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 16616b8be37..33644303362 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -1986,11 +1986,11 @@ static int wait_for_devlink(const char *path) { _cleanup_free_ char *dn = NULL; usec_t w; - if (laccess(path, F_OK) < 0) { - if (errno != ENOENT) - return log_error_errno(errno, "Failed to determine whether %s exists: %m", path); - } else + r = laccess(path, F_OK); + if (r >= 0) return 0; /* Found it */ + if (r != -ENOENT) + return log_error_errno(r, "Failed to determine whether %s exists: %m", path); if (inotify_fd < 0) { /* We need to wait for the device symlink to show up, let's create an inotify watch for it */ diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 9b11b2f1606..3e7d412d7e4 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -396,6 +396,7 @@ static int ipv4acd_on_packet( } break; + case IPV4ACD_STATE_STARTED: case IPV4ACD_STATE_WAITING_PROBE: case IPV4ACD_STATE_PROBING: case IPV4ACD_STATE_WAITING_ANNOUNCE: diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 763ecb93df9..074f08eaea9 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -119,6 +119,7 @@ static void test_message_handler(void) { .s_addr = htobe32(INADDR_LOOPBACK + 42), }; static uint8_t static_lease_client_id[7] = {0x01, 'A', 'B', 'C', 'D', 'E', 'G' }; + int r; log_debug("/* %s */", __func__); @@ -129,7 +130,10 @@ static void test_message_handler(void) { assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0); assert_se(sd_dhcp_server_start(server) >= 0); - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); + r = dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)); + if (r == -ENETDOWN) + return (void) log_tests_skipped("Network is not available"); + assert_se(r == DHCP_OFFER); test.end = 0; /* TODO, shouldn't this fail? */ diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 199d10a00ea..82836de66b5 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -616,17 +616,18 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) { } _public_ int sd_booted(void) { - /* We test whether the runtime unit file directory has been - * created. This takes place in mount-setup.c, so is - * guaranteed to happen very early during boot. */ + int r; - if (laccess("/run/systemd/system/", F_OK) >= 0) - return true; + /* We test whether the runtime unit file directory has been created. This takes place in mount-setup.c, + * so is guaranteed to happen very early during boot. */ - if (errno == ENOENT) + r = laccess("/run/systemd/system/", F_OK); + if (r >= 0) + return true; + if (r == -ENOENT) return false; - return -errno; + return r; } _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index df2e203abd8..71926100d00 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -95,18 +95,24 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) { struct in_addr in_data; struct ifa_cacheinfo cache; const char *label; + int ret; log_debug("/* %s */", __func__); assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0); assert_se(m); assert_se(sd_netlink_message_set_request_dump(m, true) >= 0); - assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1); - assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0); - assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0); - assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0); - assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0); + ret = sd_netlink_call(rtnl, m, -1, &r); + assert_se(ret >= 0); + + /* If the loopback device is down we won't get any results. */ + if (ret > 0) { + assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0); + assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0); + assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0); + assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0); + } } static void test_route(sd_netlink *rtnl) { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index b3e6867887a..afc3835e911 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2264,7 +2264,7 @@ static int copy_devnodes(const char *dest) { /* Explicitly warn the user when /dev is already populated. */ if (errno == EEXIST) log_notice("%s/dev is pre-mounted and pre-populated. If a pre-mounted /dev is provided it needs to be an unpopulated file system.", dest); - if (errno != EPERM) + if (errno != EPERM || arg_uid_shift != 0) return log_error_errno(errno, "mknod(%s) failed: %m", to); /* Some systems abusively restrict mknod but allow bind mounts. */ @@ -2274,12 +2274,12 @@ static int copy_devnodes(const char *dest) { r = mount_nofollow_verbose(LOG_DEBUG, from, to, NULL, MS_BIND, NULL); if (r < 0) return log_error_errno(r, "Both mknod and bind mount (%s) failed: %m", to); + } else { + r = userns_lchown(to, 0, 0); + if (r < 0) + return log_error_errno(r, "chown() of device node %s failed: %m", to); } - r = userns_lchown(to, 0, 0); - if (r < 0) - return log_error_errno(r, "chown() of device node %s failed: %m", to); - dn = path_join("/dev", S_ISCHR(st.st_mode) ? "char" : "block"); if (!dn) return log_oom(); diff --git a/src/partition/repart.c b/src/partition/repart.c index 9ccacc42a7d..f22b8c69986 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3291,13 +3291,13 @@ static int do_copy_files(Partition *p, const char *root) { sfd, ".", pfd, fn, UID_INVALID, GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS); + COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_RESTORE_DIRECTORY_TIMESTAMPS); } else r = copy_tree_at( sfd, ".", tfd, ".", UID_INVALID, GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS); + COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_RESTORE_DIRECTORY_TIMESTAMPS); if (r < 0) return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target); } else { @@ -5862,6 +5862,10 @@ static int run(int argc, char *argv[]) { if (!context) return log_oom(); + r = context_read_seed(context, arg_root); + if (r < 0) + return r; + strv_uniq(arg_definitions); r = context_read_definitions(context, arg_definitions, arg_root); @@ -5926,10 +5930,6 @@ static int run(int argc, char *argv[]) { putchar('\n'); #endif - r = context_read_seed(context, arg_root); - if (r < 0) - return r; - /* Open all files to copy blocks from now, since we want to take their size into consideration */ r = context_open_copy_block_paths( context, diff --git a/src/portable/portable.c b/src/portable/portable.c index 70f9071b352..91c5fb2173d 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -1083,8 +1083,12 @@ static int install_profile_dropin( return -ENOMEM; if (flags & PORTABLE_PREFER_COPY) { + CopyFlags copy_flags = COPY_REFLINK|COPY_FSYNC; - r = copy_file_atomic(from, dropin, 0644, 0, 0, COPY_REFLINK|COPY_FSYNC); + if (flags & PORTABLE_FORCE_ATTACH) + copy_flags |= COPY_REPLACE; + + r = copy_file_atomic(from, dropin, 0644, 0, 0, copy_flags); if (r < 0) return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin); @@ -1092,8 +1096,12 @@ static int install_profile_dropin( } else { - if (symlink(from, dropin) < 0) - return log_debug_errno(errno, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin); + if (flags & PORTABLE_FORCE_ATTACH) + r = symlink_atomic(from, dropin); + else + r = RET_NERRNO(symlink(from, dropin)); + if (r < 0) + return log_debug_errno(r, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin); (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, dropin, from); } @@ -1177,8 +1185,12 @@ static int attach_unit_file( if ((flags & PORTABLE_PREFER_SYMLINK) && m->source) { - if (symlink(m->source, path) < 0) - return log_debug_errno(errno, "Failed to symlink unit file '%s': %m", path); + if (flags & PORTABLE_FORCE_ATTACH) + r = symlink_atomic(m->source, path); + else + r = RET_NERRNO(symlink(m->source, path)); + if (r < 0) + return log_debug_errno(r, "Failed to symlink unit file '%s': %m", path); (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, path, m->source); @@ -1200,6 +1212,9 @@ static int attach_unit_file( if (fchmod(fd, 0644) < 0) return log_debug_errno(errno, "Failed to change unit file access mode for '%s': %m", path); + if (flags & PORTABLE_FORCE_ATTACH) + (void) unlink(path); + r = link_tmpfile(fd, tmp, path); if (r < 0) return log_debug_errno(r, "Failed to install unit file '%s': %m", path); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 4a34ec9b901..fde49694991 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -111,6 +111,7 @@ static inline uint8_t* DNS_PACKET_DATA(const DnsPacket *p) { #define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1) #define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1) +#define DNS_PACKET_FLAG_AD (UINT16_C(1) << 5) #define DNS_PACKET_FLAG_TC (UINT16_C(1) << 9) static inline uint16_t DNS_PACKET_RCODE(DnsPacket *p) { diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 4e903f13f97..ffbb27dd98c 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -685,7 +685,8 @@ static int dns_stub_send_failure( static int dns_stub_patch_bypass_reply_packet( DnsPacket **ret, /* Where to place the patched packet */ DnsPacket *original, /* The packet to patch */ - DnsPacket *request) { /* The packet the patched packet shall look like a reply to */ + DnsPacket *request, /* The packet the patched packet shall look like a reply to */ + bool authenticated) { _cleanup_(dns_packet_unrefp) DnsPacket *c = NULL; int r; @@ -725,6 +726,10 @@ static int dns_stub_patch_bypass_reply_packet( DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) | DNS_PACKET_FLAG_TC); } + /* Ensure we don't pass along an untrusted ad flag for bypass packets */ + if (!authenticated) + DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) & ~DNS_PACKET_FLAG_AD); + *ret = TAKE_PTR(c); return 0; } @@ -745,7 +750,8 @@ static void dns_stub_query_complete(DnsQuery *query) { q->answer_full_packet->protocol == DNS_PROTOCOL_DNS) { _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; - r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet); + r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet, + FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED)); if (r < 0) log_debug_errno(r, "Failed to patch bypass reply packet: %m"); else diff --git a/src/shared/bpf-dlopen.c b/src/shared/bpf-dlopen.c index 808f8c0bb7d..9243162b50e 100644 --- a/src/shared/bpf-dlopen.c +++ b/src/shared/bpf-dlopen.c @@ -49,13 +49,13 @@ int dlopen_bpf(void) { void *dl; int r; - dl = dlopen("libbpf.so.1", RTLD_LAZY); + dl = dlopen("libbpf.so.1", RTLD_NOW|RTLD_NODELETE); if (!dl) { /* libbpf < 1.0.0 (we rely on 0.1.0+) provide most symbols we care about, but * unfortunately not all until 0.7.0. See bpf-compat.h for more details. * Once we consider we can assume 0.7+ is present we can just use the same symbol * list for both files, and when we assume 1.0+ is present we can remove this dlopen */ - dl = dlopen("libbpf.so.0", RTLD_LAZY); + dl = dlopen("libbpf.so.0", RTLD_NOW|RTLD_NODELETE); if (!dl) return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "neither libbpf.so.1 nor libbpf.so.0 are installed: %s", dlerror()); diff --git a/src/shared/condition.c b/src/shared/condition.c index b624f2ee31b..18c97f0ab58 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -172,10 +172,11 @@ static int condition_test_credential(Condition *c, char **env) { if (!j) return -ENOMEM; - if (laccess(j, F_OK) >= 0) + r = laccess(j, F_OK); + if (r >= 0) return true; /* yay! */ - if (errno != ENOENT) - return -errno; + if (r != -ENOENT) + return r; /* not found in this dir */ } diff --git a/src/shared/copy.c b/src/shared/copy.c index 64c61e15ab2..dc18ea0e20b 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -908,6 +908,7 @@ static int fd_copy_directory( _cleanup_close_ int fdf = -1, fdt = -1; _cleanup_closedir_ DIR *d = NULL; + struct stat dt_st; bool exists, created; int r; @@ -966,6 +967,9 @@ static int fd_copy_directory( if (fdt < 0) return -errno; + if (exists && FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS) && fstat(fdt, &dt_st) < 0) + return -errno; + r = 0; FOREACH_DIRENT_ALL(de, d, return -errno) { @@ -1050,7 +1054,9 @@ static int fd_copy_directory( (void) copy_xattr(dirfd(d), fdt, copy_flags); (void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim }); - } + } else if (FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS)) + /* If the directory already exists, make sure the timestamps stay the same as before. */ + (void) futimens(fdt, (struct timespec[]) { dt_st.st_atim, dt_st.st_mtim }); if (copy_flags & COPY_FSYNC_FULL) { if (fsync(fdt) < 0) diff --git a/src/shared/copy.h b/src/shared/copy.h index d755916bd98..bdbe8ccc9c4 100644 --- a/src/shared/copy.h +++ b/src/shared/copy.h @@ -25,6 +25,7 @@ typedef enum CopyFlags { COPY_SYNCFS = 1 << 12, /* syncfs() the *top-level* dir after we are done */ COPY_ALL_XATTRS = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */ COPY_HOLES = 1 << 14, /* Copy holes */ + COPY_RESTORE_DIRECTORY_TIMESTAMPS = 1 << 15, /* Make sure existing directory timestamps don't change during copying. */ } CopyFlags; typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata); diff --git a/src/shared/dlfcn-util.c b/src/shared/dlfcn-util.c index 8022f552943..2ebb1463c20 100644 --- a/src/shared/dlfcn-util.c +++ b/src/shared/dlfcn-util.c @@ -44,7 +44,7 @@ int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_l if (*dlp) return 0; /* Already loaded */ - dl = dlopen(filename, RTLD_LAZY); + dl = dlopen(filename, RTLD_NOW|RTLD_NODELETE); if (!dl) return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not installed: %s", filename, dlerror()); diff --git a/src/shared/idn-util.c b/src/shared/idn-util.c index d9e0cca433e..38ed6267021 100644 --- a/src/shared/idn-util.c +++ b/src/shared/idn-util.c @@ -42,11 +42,11 @@ int dlopen_idn(void) { if (idn_dl) return 0; /* Already loaded */ - dl = dlopen("libidn.so.12", RTLD_LAZY); + dl = dlopen("libidn.so.12", RTLD_NOW|RTLD_NODELETE); if (!dl) { /* libidn broke ABI in 1.34, but not in a way we care about (a new field got added to an * open-coded struct we do not use), hence support both versions. */ - dl = dlopen("libidn.so.11", RTLD_LAZY); + dl = dlopen("libidn.so.11", RTLD_NOW|RTLD_NODELETE); if (!dl) return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libidn support is not installed: %s", dlerror()); @@ -54,7 +54,6 @@ int dlopen_idn(void) { } else log_debug("Loaded 'libidn.so.12' via dlopen()"); - r = dlsym_many_or_warn( dl, LOG_DEBUG, diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index dd3fd7919bf..04804f35eec 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -446,8 +446,9 @@ int bind_remount_one_with_mountinfo( fs = mnt_table_find_target(table, path, MNT_ITER_FORWARD); if (!fs) { - if (laccess(path, F_OK) < 0) /* Hmm, it's not in the mount table, but does it exist at all? */ - return -errno; + r = laccess(path, F_OK); /* Hmm, it's not in the mount table, but does it exist at all? */ + if (r < 0) + return r; return -EINVAL; /* Not a mount point we recognize */ } diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 1c6bdc5e431..ab985813f4e 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -854,6 +854,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { .name = "@sync", .help = "Synchronize files and memory to storage", .value = + /* Please also update the list in seccomp_suppress_sync(). */ "fdatasync\0" "fsync\0" "msync\0" @@ -2331,8 +2332,10 @@ int seccomp_suppress_sync(void) { uint32_t arch; int r; - /* This is mostly identical to SystemCallFilter=~@sync:0, but simpler to use, and separately - * manageable, and also masks O_SYNC/O_DSYNC */ + /* This behaves slightly differently from SystemCallFilter=~@sync:0, in that negative fds (which + * we can determine to be invalid) are still refused with EBADF. See #34478. + * + * Additionally, O_SYNC/O_DSYNC are masked. */ SECCOMP_FOREACH_LOCAL_ARCH(arch) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; @@ -2351,11 +2354,21 @@ int seccomp_suppress_sync(void) { continue; } - r = seccomp_rule_add_exact( - seccomp, - SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */ - id, - 0); + if (STR_IN_SET(c, "fdatasync", "fsync", "sync_file_range", "sync_file_range2", "syncfs")) + r = seccomp_rule_add_exact( + seccomp, + SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */ + id, + 1, + SCMP_A0(SCMP_CMP_LE, INT_MAX)); /* The rule handles arguments in unsigned. Hence, this + * means non-negative fd matches the rule, and the negative + * fd passed to the syscall (then it fails with EBADF). */ + else + r = seccomp_rule_add_exact( + seccomp, + SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */ + id, + 0); if (r < 0) log_debug_errno(r, "Failed to add filter for system call %s, ignoring: %m", c); } diff --git a/src/shared/tests.c b/src/shared/tests.c index a06e458d33a..d623a5a801a 100644 --- a/src/shared/tests.c +++ b/src/shared/tests.c @@ -35,6 +35,7 @@ #include "strv.h" #include "tests.h" #include "tmpfile-util.h" +#include "uid-range.h" char* setup_fake_runtime_dir(void) { char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p; @@ -172,6 +173,20 @@ bool have_namespaces(void) { assert_not_reached(); } +bool userns_has_single_user(void) { + _cleanup_(uid_range_freep) UidRange *uidrange = NULL; + + /* Check if we're in a user namespace with only a single user mapped in. We special case this + * scenario in a few tests because it's the only kind of namespace that can be created unprivileged + * and as such happens more often than not, so we make sure to deal with it so that all tests pass + * in such environments. */ + + if (uid_range_load_userns(&uidrange, NULL) < 0) + return false; + + return uidrange->n_entries == 1 && uidrange->entries[0].nr == 1; +} + bool can_memlock(void) { /* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against * RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we diff --git a/src/shared/tests.h b/src/shared/tests.h index a02bfa8f02d..d3c488deb9b 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -48,6 +48,7 @@ void test_setup_logging(int level); int write_tmpfile(char *pattern, const char *contents); bool have_namespaces(void); +bool userns_has_single_user(void); /* We use the small but non-trivial limit here */ #define CAN_MEMLOCK_SIZE (512 * 1024U) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 04794c5be48..e8646e5b803 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -195,7 +195,7 @@ int tpm2_context_init(const char *device, struct tpm2_context *ret) { if (!filename_is_valid(fn)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name '%s' not valid, refusing.", driver); - dl = dlopen(fn, RTLD_NOW); + dl = dlopen(fn, RTLD_NOW|RTLD_NODELETE); if (!dl) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror()); diff --git a/src/shared/userdb.c b/src/shared/userdb.c index 4974ad0f5fb..7613223367f 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -1454,7 +1454,7 @@ int userdb_block_nss_systemd(int b) { /* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */ - dl = dlopen(ROOTLIBDIR "/libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE); + dl = dlopen(ROOTLIBDIR "/libnss_systemd.so.2", RTLD_NOW|RTLD_NODELETE); if (!dl) { /* If the file isn't installed, don't complain loudly */ log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror()); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index ed3fefe51c2..4787f5767e7 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -676,13 +676,11 @@ static int merge_subprocess(Hashmap *images, const char *workspace) { if (!p) return log_oom(); - if (laccess(p, F_OK) < 0) { - if (errno != ENOENT) - return log_error_errno(errno, "Failed to check if '%s' exists: %m", p); - - /* Hierarchy apparently was empty in all extensions, and wasn't mounted, ignoring. */ + r = laccess(p, F_OK); + if (r == -ENOENT) /* Hierarchy apparently was empty in all extensions, and wasn't mounted, ignoring. */ continue; - } + if (r < 0) + return log_error_errno(r, "Failed to check if '%s' exists: %m", p); r = chase_symlinks(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL); if (r < 0) diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c index fc5aaa9bac3..5ba5217f114 100644 --- a/src/system-update-generator/system-update-generator.c +++ b/src/system-update-generator/system-update-generator.c @@ -20,12 +20,14 @@ static const char *arg_dest = NULL; static int generate_symlink(void) { const char *p = NULL; + int r; - if (laccess("/system-update", F_OK) < 0) { - if (errno == ENOENT) + r = laccess("/system-update", F_OK); + if (r < 0) { + if (r == -ENOENT) return 0; - log_error_errno(errno, "Failed to check for system update: %m"); + log_error_errno(r, "Failed to check for system update: %m"); return -EINVAL; } diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c index 1ce14f5aa51..07a2fe79473 100644 --- a/src/systemctl/systemctl-show.c +++ b/src/systemctl/systemctl-show.c @@ -1645,6 +1645,29 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m bus_print_property_value(name, expected_value, flags, affinity); return 1; + + } else if (streq(name, "RootImageOptions")) { + const char *a, *p; + + /* In config files, the syntax allows the partition name to be omitted. Here, we + * always print the partition name, also because we have no way of knowing if it was + * originally omitted or not. We also print the partitions on separate lines. */ + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(ss)", &a, &p)) > 0) + bus_print_property_valuef(name, expected_value, flags, "%s:%s", a, p); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 1; + } else if (streq(name, "MountImages")) { _cleanup_free_ char *paths = NULL; diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c index 8e4fa69212f..f2288af2d14 100644 --- a/src/test/test-acl-util.c +++ b/src/test/test-acl-util.c @@ -34,7 +34,7 @@ TEST_RET(add_acls_for_user) { cmd = strjoina("getfacl -p ", fn); assert_se(system(cmd) == 0); - if (getuid() == 0) { + if (getuid() == 0 && !userns_has_single_user()) { const char *nobody = NOBODY_USER_NAME; r = get_user_creds(&nobody, &uid, NULL, NULL, NULL, 0); if (r < 0) diff --git a/src/test/test-capability.c b/src/test/test-capability.c index 466223e4788..40ad3916f5f 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -267,10 +267,13 @@ int main(int argc, char *argv[]) { show_capabilities(); - test_drop_privileges(); + if (!userns_has_single_user()) + test_drop_privileges(); + test_update_inherited_set(); - fork_test(test_have_effective_cap); + if (!userns_has_single_user()) + fork_test(test_have_effective_cap); if (run_ambient) fork_test(test_apply_ambient_caps); diff --git a/src/test/test-chown-rec.c b/src/test/test-chown-rec.c index 0d8b3249676..7ff7f0c8cf4 100644 --- a/src/test/test-chown-rec.c +++ b/src/test/test-chown-rec.c @@ -153,8 +153,8 @@ TEST(chown_recursive) { } static int intro(void) { - if (geteuid() != 0) - return log_tests_skipped("not running as root"); + if (geteuid() != 0 || userns_has_single_user()) + return log_tests_skipped("not running as root or in userns with single user"); return EXIT_SUCCESS; } diff --git a/src/test/test-condition.c b/src/test/test-condition.c index a4b75bd5ae1..0e3b5ff406f 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -995,6 +995,13 @@ TEST(condition_test_group) { condition_free(condition); free(gid); + /* In an unprivileged user namespace with the current user mapped to root, all the auxiliary groups + * of the user will be mapped to the nobody group, which means the user in the user namespace is in + * both the root and the nobody group, meaning the next test can't work, so let's skip it in that + * case. */ + if (in_group(NOBODY_GROUP_NAME) && in_group("root")) + return (void) log_tests_skipped("user is in both root and nobody group"); + groupname = (char*)(getegid() == 0 ? NOBODY_GROUP_NAME : "root"); condition = condition_new(CONDITION_GROUP, groupname, false, false); assert_se(condition); diff --git a/src/test/test-dlopen.c b/src/test/test-dlopen.c index 9c315373b4f..6704e936e7b 100644 --- a/src/test/test-dlopen.c +++ b/src/test/test-dlopen.c @@ -10,7 +10,7 @@ int main(int argc, char **argv) { int i; for (i = 0; i < argc - 1; i++) - assert_se(handles[i] = dlopen(argv[i + 1], RTLD_NOW)); + assert_se(handles[i] = dlopen(argv[i + 1], RTLD_NOW|RTLD_NODELETE)); for (i--; i >= 0; i--) assert_se(dlclose(handles[i]) == 0); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index 35b93b6a57b..69c1502aa55 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -775,8 +775,8 @@ TEST(chmod_and_chown) { struct stat st; const char *p; - if (geteuid() != 0) - return; + if (geteuid() != 0 || userns_has_single_user()) + return (void) log_tests_skipped("not running as root or in userns with single user"); BLOCK_WITH_UMASK(0000); diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c index 72a9c6454c6..611e1357664 100644 --- a/src/test/test-nss-hosts.c +++ b/src/test/test-nss-hosts.c @@ -380,7 +380,7 @@ static int test_one_module(const char *dir, log_info("======== %s ========", module); - _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE); + _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_NOW|RTLD_NODELETE); if (!handle) return -EINVAL; diff --git a/src/test/test-nss-users.c b/src/test/test-nss-users.c index 5178779d54a..cba0f823b92 100644 --- a/src/test/test-nss-users.c +++ b/src/test/test-nss-users.c @@ -166,7 +166,7 @@ static int test_one_module(const char *dir, log_info("======== %s ========", module); - _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE); + _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_NOW|RTLD_NODELETE); if (!handle) return -EINVAL; diff --git a/src/test/test-rm-rf.c b/src/test/test-rm-rf.c index 6a8b7d823fb..b560f89f60f 100644 --- a/src/test/test-rm-rf.c +++ b/src/test/test-rm-rf.c @@ -89,6 +89,9 @@ static void test_rm_rf_chmod_inner(void) { TEST(rm_rf_chmod) { int r; + if (getuid() == 0 && userns_has_single_user()) + return (void) log_tests_skipped("running as root or in userns with single user"); + if (getuid() == 0) { /* This test only works unpriv (as only then the access mask for the owning user matters), * hence drop privs here */ diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 874f08b59f0..27749d097ff 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -18,6 +18,7 @@ #include "capability-util.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "macro.h" #include "memory-util.h" #include "missing_sched.h" @@ -1227,4 +1228,55 @@ TEST(restrict_suid_sgid) { assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); } +static void test_seccomp_suppress_sync_child(void) { + _cleanup_(unlink_and_freep) char *path = NULL; + _cleanup_close_ int fd = -EBADF; + + assert_se(tempfn_random("/tmp/seccomp_suppress_sync", NULL, &path) >= 0); + assert_se((fd = open(path, O_RDWR | O_CREAT | O_SYNC | O_CLOEXEC, 0666)) >= 0); + fd = safe_close(fd); + + assert_se(fdatasync(-1) < 0 && errno == EBADF); + assert_se(fsync(-1) < 0 && errno == EBADF); + assert_se(syncfs(-1) < 0 && errno == EBADF); + + assert_se(fdatasync(INT_MAX) < 0 && errno == EBADF); + assert_se(fsync(INT_MAX) < 0 && errno == EBADF); + assert_se(syncfs(INT_MAX) < 0 && errno == EBADF); + + assert_se(seccomp_suppress_sync() >= 0); + + assert_se((fd = open(path, O_RDWR | O_CREAT | O_SYNC | O_CLOEXEC, 0666)) < 0 && errno == EINVAL); + + assert_se(fdatasync(INT_MAX) >= 0); + assert_se(fsync(INT_MAX) >= 0); + assert_se(syncfs(INT_MAX) >= 0); + + assert_se(fdatasync(-1) < 0 && errno == EBADF); + assert_se(fsync(-1) < 0 && errno == EBADF); + assert_se(syncfs(-1) < 0 && errno == EBADF); +} + +TEST(seccomp_suppress_sync) { + pid_t pid; + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); + return; + } + if (!have_seccomp_privs()) { + log_notice("Not privileged, skipping %s", __func__); + return; + } + + assert_se((pid = fork()) >= 0); + + if (pid == 0) { + test_seccomp_suppress_sync_child(); + _exit(EXIT_SUCCESS); + } + + assert_se(wait_for_terminate_and_check("seccomp_suppress_sync", pid, WAIT_LOG) == EXIT_SUCCESS); +} + DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 2da98e700eb..2aad36287dc 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -170,7 +170,7 @@ TEST(getpeercred_getpeergroups) { struct ucred ucred; int pair[2]; - if (geteuid() == 0) { + if (geteuid() == 0 && !userns_has_single_user()) { test_uid = 1; test_gid = 2; test_gids = (gid_t*) gids; diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c index 1d3201aa918..449f65c4796 100644 --- a/src/udev/cdrom_id/cdrom_id.c +++ b/src/udev/cdrom_id/cdrom_id.c @@ -476,7 +476,7 @@ static int cd_profiles(Context *c) { switch (feature) { case 0x00: - log_debug("GET CONFIGURATION: feature 'profiles', with %u entries", features[i + 3] / 4); + log_debug("GET CONFIGURATION: feature 'profiles', with %u entries", features[i + 3] / 4U); feature_profiles(c, features + i + 4, MIN(features[i + 3], len - i - 4)); break; default: diff --git a/src/udev/dmi_memory_id/dmi_memory_id.c b/src/udev/dmi_memory_id/dmi_memory_id.c index 4ce6b332410..4793c0f038e 100644 --- a/src/udev/dmi_memory_id/dmi_memory_id.c +++ b/src/udev/dmi_memory_id/dmi_memory_id.c @@ -399,7 +399,7 @@ static void dmi_memory_device_manufacturer_id( /* LSB is 7-bit Odd Parity number of continuation codes */ if (code != 0) printf("MEMORY_DEVICE_%u_%s=Bank %d, Hex 0x%02X\n", slot_num, attr_suffix, - (code & 0x7F) + 1, code >> 8); + (code & 0x7F) + 1, (uint16_t) (code >> 8)); } static void dmi_memory_device_product_id( diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 9e34ea6b01f..cc103cf2de6 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -385,6 +385,87 @@ static int stack_directory_get_name(const char *slink, char **ret) { return 0; } +static int link_update_diskseq(sd_device *dev, const char *slink, bool add) { + _cleanup_free_ char *buf = NULL; + const char *fname, *diskseq, *subsystem = NULL, *devtype = NULL; + int r; + + assert(dev); + assert(slink); + + (void) sd_device_get_subsystem(dev, &subsystem); + if (!streq_ptr(subsystem, "block")) + return 0; + + fname = path_startswith(slink, "/dev/disk/by-diskseq"); + if (isempty(fname)) + return 0; + + (void) sd_device_get_devtype(dev, &devtype); + if (streq_ptr(devtype, "partition")) { + _cleanup_free_ char *suffix = NULL; + const char *partn, *p; + + /* Check if the symlink has an expected suffix "-part%n". See 60-persistent-storage.rules. */ + + r = sd_device_get_sysnum(dev, &partn); + if (r < 0) { + /* Cannot verify the symlink is owned by this device. Let's create the stack directory for the symlink. */ + log_device_debug_errno(dev, r, "Failed to get sysnum, but symlink '%s' is requested, ignoring: %m", slink); + return 0; + } + + suffix = strjoin("-part", partn); + if (!suffix) + return -ENOMEM; + + p = endswith(fname, suffix); + if (!p) { + log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested, proceeding anyway.", slink); + return 0; + } + + buf = strndup(fname, p - fname); + if (!buf) + return -ENOMEM; + + fname = buf; + } + + /* Check if the diskseq part of the symlink is in digits. */ + if (!in_charset(fname, DIGITS)) { + log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested, proceeding anyway.", slink); + return 0; /* unexpected by-diskseq symlink */ + } + + /* On removal, we cannot verify the diskseq. Skipping further check below. */ + if (!add) { + if (unlink(slink) < 0 && errno != ENOENT) + return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", slink); + + (void) rmdir_parents(slink, "/dev"); + return 1; /* done */ + } + + /* Check if the diskseq matches with the DISKSEQ property. */ + r = sd_device_get_property_value(dev, "DISKSEQ", &diskseq); + if (r < 0) { + log_device_debug_errno(dev, r, "Failed to get DISKSEQ property, but symlink '%s' is requested, ignoring: %m", slink); + return 0; + } + + if (!streq(fname, diskseq)) { + log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested (DISKSEQ=%s), proceeding anyway.", slink, diskseq); + return 0; + } + + r = node_symlink(dev, /* devnode = */ NULL, slink); + if (r < 0) + return r; + + return 1; /* done */ +} + static int link_update(sd_device *dev, const char *slink, bool add) { _cleanup_free_ char *dirname = NULL, *devnode = NULL; _cleanup_close_ int dirfd = -1, lockfd = -1; @@ -393,6 +474,10 @@ static int link_update(sd_device *dev, const char *slink, bool add) { assert(dev); assert(slink); + r = link_update_diskseq(dev, slink, add); + if (r != 0) + return r; + r = stack_directory_get_name(slink, &dirname); if (r < 0) return log_device_debug_errno(dev, r, "Failed to build stack directory name for '%s': %m", slink); diff --git a/test/TEST-64-UDEV-STORAGE/test.sh b/test/TEST-64-UDEV-STORAGE/test.sh index e329433a903..40c000db0d4 100755 --- a/test/TEST-64-UDEV-STORAGE/test.sh +++ b/test/TEST-64-UDEV-STORAGE/test.sh @@ -474,7 +474,7 @@ EOF qemu_opts+=("-device pci-bridge,id=pci_bridge$brid,bus=pci_bridge$((brid-1)),chassis_nr=$((64+brid))") done - qemu_opts+=("-device virtio-blk-pci,drive=drive0,scsi=off,bus=pci_bridge$brid") + qemu_opts+=("-device virtio-blk-pci,drive=drive0,bus=pci_bridge$brid") KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}" QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}" diff --git a/test/test-functions b/test/test-functions index ec8c034b939..642a3df0123 100644 --- a/test/test-functions +++ b/test/test-functions @@ -1826,13 +1826,9 @@ strip_binaries() { } create_rc_local() { - dinfo "Create rc.local" - mkdir -p "${initdir:?}/etc/rc.d" - cat >"$initdir/etc/rc.d/rc.local" </run/systemd/system/test-diskseq.service <"$output" + diff -u "$output" - </run/systemd/system/test1.service <"$output" + diff -u "$output" - </run/systemd/system.attached/minimal-app0.service +[Unit] +Description=Minimal App 0 +EOF +cat </run/systemd/system.attached/minimal-app0.service.d/10-profile.conf +[Unit] +Description=Minimal App 0 +EOF +cat </run/systemd/system.attached/minimal-app0.service.d/20-portable.conf +[Unit] +Description=Minimal App 0 +EOF +systemctl daemon-reload + portablectl "${ARGS[@]}" attach --force --now --runtime /usr/share/minimal_0.raw minimal-app0 portablectl is-attached --force minimal-app0 @@ -210,6 +225,28 @@ systemctl is-active app1.service portablectl detach --now --runtime overlay app1 +# Ensure --force works also when symlinking +mkdir -p /run/systemd/system.attached/app1.service.d +cat </run/systemd/system.attached/app1.service +[Unit] +Description=App 1 +EOF +cat </run/systemd/system.attached/app1.service.d/10-profile.conf +[Unit] +Description=App 1 +EOF +cat </run/systemd/system.attached/app1.service.d/20-portable.conf +[Unit] +Description=App 1 +EOF +systemctl daemon-reload + +portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime /tmp/overlay app1 + +systemctl is-active app1.service + +portablectl detach --now --runtime overlay app1 + umount /tmp/overlay portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 diff --git a/test/units/testsuite-58.sh b/test/units/testsuite-58.sh index 5b72a49e0fb..097d772e51c 100755 --- a/test/units/testsuite-58.sh +++ b/test/units/testsuite-58.sh @@ -914,6 +914,47 @@ EOF assert_in "${loop}p3 : start= *${start}, size= *${size}, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=DB081670-07AE-48CA-9F5E-813D5E40B976, name=\"linux-generic-2\"" "$output" } +testcase_random_seed() { + local defs imgs output + + # For issue #34257 + + defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")" + imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")" + # shellcheck disable=SC2064 + trap "rm -rf '$defs' '$imgs'" RETURN + chmod 0755 "$defs" + + tee "$defs/root.conf" <= 512 and <= PAGE_SIZE, and # must be powers of 2. Which leaves exactly four different ones to test on diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh index eb24b70b84d..4e49143c2cd 100755 --- a/test/units/testsuite-75.sh +++ b/test/units/testsuite-75.sh @@ -16,6 +16,12 @@ run() { "$@" |& tee "$RUN_OUT" } +run_delv() { + # Since [0] delv no longer loads /etc/(bind/)bind.keys by default, so we + # have to do that explicitly for each invocation + run delv -a /etc/bind.keys "$@" +} + monitor_check_rr() ( set +x set +o pipefail @@ -214,9 +220,9 @@ grep -qF "unsigned.test IN MX 15 mail.unsigned.test" "$RUN_OUT" # Check the trust chain (with and without systemd-resolved in between # Issue: https://github.com/systemd/systemd/issues/22002 # PR: https://github.com/systemd/systemd/pull/23289 -run delv @10.0.0.1 signed.test +run_delv @10.0.0.1 signed.test grep -qF "; fully validated" "$RUN_OUT" -run delv signed.test +run_delv signed.test grep -qF "; fully validated" "$RUN_OUT" run dig +short signed.test @@ -239,9 +245,9 @@ grep -qF "authenticated: yes" "$RUN_OUT" # DNSSEC validation with multiple records of the same type for the same name # Issue: https://github.com/systemd/systemd/issues/22002 # PR: https://github.com/systemd/systemd/pull/23289 -run delv @10.0.0.1 dupe.signed.test +run_delv @10.0.0.1 dupe.signed.test grep -qF "; fully validated" "$RUN_OUT" -run delv dupe.signed.test +run_delv dupe.signed.test grep -qF "; fully validated" "$RUN_OUT" # Test resolution of CNAME chains @@ -266,9 +272,9 @@ grep -qE "^follow14\.final\.signed\.test\..+IN\s+NSEC\s+" "$RUN_OUT" # Check the trust chain (with and without systemd-resolved in between # Issue: https://github.com/systemd/systemd/issues/22002 # PR: https://github.com/systemd/systemd/pull/23289 -run delv @10.0.0.1 sub.onlinesign.test +run_delv @10.0.0.1 sub.onlinesign.test grep -qF "; fully validated" "$RUN_OUT" -run delv sub.onlinesign.test +run_delv sub.onlinesign.test grep -qF "; fully validated" "$RUN_OUT" run dig +short sub.onlinesign.test