diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/debian/changelog systemd-252.39/debian/changelog
--- systemd-252.38/debian/changelog 2025-05-29 18:04:02.000000000 +0100
+++ systemd-252.39/debian/changelog 2025-06-26 15:58:40.000000000 +0100
@@ -1,3 +1,9 @@
+systemd (252.39-1~deb12u1) bookworm; urgency=medium
+
+ * New upstream version 252.39
+
+ -- Luca Boccassi Thu, 26 Jun 2025 15:58:40 +0100
+
systemd (252.38-1~deb12u1) bookworm-security; urgency=medium
* New upstream version 252.38 (fixes CVE-2025-4598)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/hwdb.d/meson.build systemd-252.39/hwdb.d/meson.build
--- systemd-252.38/hwdb.d/meson.build 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/hwdb.d/meson.build 2025-06-26 15:56:09.000000000 +0100
@@ -34,6 +34,7 @@
'70-mouse.hwdb',
'70-pda.hwdb',
'70-pointingstick.hwdb',
+ '70-software-radio.hwdb',
'70-sound-card.hwdb',
'70-touchpad.hwdb',
'80-ieee1394-unit-function.hwdb')
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/man/machine-id.xml systemd-252.39/man/machine-id.xml
--- systemd-252.38/man/machine-id.xml 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/man/machine-id.xml 2025-06-26 15:56:09.000000000 +0100
@@ -84,9 +84,9 @@
containers or in the cloud, /etc/machine-id should be either missing or an empty
file in the generic file system image (the difference between the two options is described under "First
Boot Semantics" below). An ID will be generated during boot and saved to this file if possible. Having an
- empty file in place is useful because it allows a temporary file to be bind-mounted over the real file,
- in case the image is used read-only. Also see Safely
- Building Images.
+ empty file in place is recommended because it allows a temporary file to be bind-mounted over the real file,
+ in case the image is used read-only and when /etc is mounted read-only in the early boot.
+ Also see Safely Building Images.
systemd-firstboot1
may be used to initialize /etc/machine-id on mounted (but not
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/man/systemd.timer.xml systemd-252.39/man/systemd.timer.xml
--- systemd-252.38/man/systemd.timer.xml 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/man/systemd.timer.xml 2025-06-26 15:56:09.000000000 +0100
@@ -260,9 +260,9 @@
Delay the timer by a randomly selected, evenly distributed amount of time between 0
and the specified time value. Defaults to 0, indicating that no randomized delay shall be applied.
- Each timer unit will determine this delay randomly before each iteration, and the delay will simply
- be added on top of the next determined elapsing time, unless modified with
- FixedRandomDelay=, see below.
+ Each timer unit will determine this delay randomly before each iteration, unless modified with
+ FixedRandomDelay=, see below. The delay is added on top of the next determined
+ elapsing time or the service manager's startup time, whichever is later.
This setting is useful to stretch dispatching of similarly configured timer events over a
certain time interval, to prevent them from firing all at the same time, possibly resulting in
@@ -284,12 +284,12 @@
FixedRandomDelay=
- Takes a boolean argument. When enabled, the randomized offset specified by
- RandomizedDelaySec= is reused for all firings of the same timer. For a given timer
- unit, the offset depends on the machine ID, user identifier and timer name, which means that it is
- stable between restarts of the manager. This effectively creates a fixed offset for an individual
- timer, reducing the jitter in firings of this timer, while still avoiding firing at the same time as
- other similarly configured timers.
+ Takes a boolean argument. When enabled, the randomized delay specified by
+ RandomizedDelaySec= is chosen deterministically, and remains stable between all
+ firings of the same timer, even if the manager is restarted. The delay is derived from the machine
+ ID, the manager's user identifier, and the timer unit's name. This effectively creates a unique fixed
+ offset for each timer, reducing the jitter in firings of an individual timer while still avoiding
+ firing at the same time as other similarly configured timers.
This setting has no effect if RandomizedDelaySec= is set to 0. Defaults to
.
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/basic/compress.c systemd-252.39/src/basic/compress.c
--- systemd-252.38/src/basic/compress.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/basic/compress.c 2025-06-26 15:56:09.000000000 +0100
@@ -704,9 +704,12 @@
if (ret_uncompressed_size)
*ret_uncompressed_size = total_in;
- log_debug("LZ4 compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
- total_in, total_out,
- (double) total_out / total_in * 100);
+ if (total_in == 0)
+ log_debug("LZ4 compression finished (no input data)");
+ else
+ log_debug("LZ4 compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+ total_in, total_out,
+ (double) total_out / total_in * 100);
return COMPRESSION_LZ4;
#else
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/basic/io-util.c systemd-252.39/src/basic/io-util.c
--- systemd-252.38/src/basic/io-util.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/basic/io-util.c 2025-06-26 15:56:09.000000000 +0100
@@ -23,12 +23,10 @@
int r;
r = fd_wait_for_event(fd, POLLIN, 0);
- if (r < 0) {
- if (r == -EINTR)
- continue;
-
+ if (r == -EINTR)
+ continue;
+ if (r < 0)
return r;
- }
if (r == 0)
return count;
@@ -36,7 +34,6 @@
if (l < 0) {
if (errno == EINTR)
continue;
-
if (errno == EAGAIN)
return count;
@@ -44,6 +41,9 @@
} else if (l == 0)
return count;
+ if (l > INT_MAX-count) /* On overflow terminate */
+ return INT_MAX;
+
count += (int) l;
}
}
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/boot/efi/console.c systemd-252.39/src/boot/efi/console.c
--- systemd-252.38/src/boot/efi/console.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/boot/efi/console.c 2025-06-26 15:56:09.000000000 +0100
@@ -249,38 +249,72 @@
return CONSOLE_MODE_80_25;
}
+static int next_mode(int64_t mode, int64_t direction) {
+ assert(IN_SET(direction, 1, -1));
+ assert(ST->ConOut->Mode->MaxMode > 0);
+
+ /* Always start at the beginning if we are out of range or reached the last mode already */
+ if (direction > 0) {
+ if (mode < CONSOLE_MODE_RANGE_MIN || mode >= ST->ConOut->Mode->MaxMode-1)
+ return CONSOLE_MODE_RANGE_MIN;
+ } else if (direction < 0) {
+ if (mode <= CONSOLE_MODE_RANGE_MIN || mode > ST->ConOut->Mode->MaxMode-1)
+ return ST->ConOut->Mode->MaxMode-1;
+ } else
+ assert_not_reached();
+
+ return mode + direction;
+}
+
EFI_STATUS console_set_mode(int64_t mode) {
+ EFI_STATUS r;
+
+ /* If there are no modes defined, fail immediately */
+ if (ST->ConOut->Mode->MaxMode <= 0)
+ return mode == CONSOLE_MODE_KEEP ? EFI_SUCCESS : EFI_UNSUPPORTED;
+
+ int64_t target, direction = 1;
switch (mode) {
case CONSOLE_MODE_KEEP:
/* If the firmware indicates the current mode is invalid, change it anyway. */
- if (ST->ConOut->Mode->Mode < CONSOLE_MODE_RANGE_MIN)
- return change_mode(CONSOLE_MODE_RANGE_MIN);
- return EFI_SUCCESS;
+ if (ST->ConOut->Mode->Mode >= CONSOLE_MODE_RANGE_MIN &&
+ ST->ConOut->Mode->Mode < ST->ConOut->Mode->MaxMode)
+ return EFI_SUCCESS;
- case CONSOLE_MODE_NEXT:
- if (ST->ConOut->Mode->MaxMode <= CONSOLE_MODE_RANGE_MIN)
- return EFI_UNSUPPORTED;
+ target = CONSOLE_MODE_RANGE_MIN;
+ break;
- mode = MAX(CONSOLE_MODE_RANGE_MIN, ST->ConOut->Mode->Mode);
- do {
- mode = (mode + 1) % ST->ConOut->Mode->MaxMode;
- if (change_mode(mode) == EFI_SUCCESS)
- break;
- /* If this mode is broken/unsupported, try the next.
- * If mode is 0, we wrapped around and should stop. */
- } while (mode > CONSOLE_MODE_RANGE_MIN);
-
- return EFI_SUCCESS;
+ case CONSOLE_MODE_NEXT:
+ target = next_mode(ST->ConOut->Mode->Mode, direction);
+ break;
case CONSOLE_MODE_AUTO:
- return change_mode(get_auto_mode());
+ target = get_auto_mode();
+ break;
case CONSOLE_MODE_FIRMWARE_MAX:
/* Note: MaxMode is the number of modes, not the last mode. */
- return change_mode(ST->ConOut->Mode->MaxMode - 1LL);
+ target = ST->ConOut->Mode->MaxMode - 1;
+ direction = -1; /* search backwards for a working mode */
+ break;
+
+ case CONSOLE_MODE_RANGE_MIN...CONSOLE_MODE_RANGE_MAX:
+ target = mode;
+ break;
default:
- return change_mode(mode);
+ assert_not_reached();
+ }
+
+ for (int64_t attempt = 0;; attempt++) {
+ r = change_mode(target);
+ if (r == EFI_SUCCESS)
+ return EFI_SUCCESS;
+ if (attempt >= ST->ConOut->Mode->MaxMode-1) /* give up, once we tried them all */
+ return r;
+
+ /* If this mode is broken/unsupported, try the next. */
+ target = next_mode(target, direction);
}
}
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/core/socket.c systemd-252.39/src/core/socket.c
--- systemd-252.38/src/core/socket.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/core/socket.c 2025-06-26 15:56:09.000000000 +0100
@@ -1029,7 +1029,7 @@
if (s->pass_sec) {
r = setsockopt_int(fd, SOL_SOCKET, SO_PASSSEC, true);
if (r < 0)
- log_unit_warning_errno(UNIT(s), r, "SO_PASSSEC failed: %m");
+ log_unit_full_errno(UNIT(s), ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, "SO_PASSSEC failed: %m");
}
if (s->pass_pktinfo) {
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/fstab-generator/fstab-generator.c systemd-252.39/src/fstab-generator/fstab-generator.c
--- systemd-252.38/src/fstab-generator/fstab-generator.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/fstab-generator/fstab-generator.c 2025-06-26 15:56:09.000000000 +0100
@@ -823,7 +823,7 @@
static int add_sysroot_mount(void) {
_cleanup_free_ char *what = NULL;
- const char *opts, *fstype;
+ const char *extra_opts = NULL, *fstype;
bool default_rw;
int r;
@@ -872,6 +872,9 @@
fstype = arg_root_fstype ?: "tmpfs"; /* tmpfs, unless overridden */
default_rw = true; /* writable, unless overridden */;
+
+ if (streq(fstype, "tmpfs") && !fstab_test_option(arg_root_options, "mode\0"))
+ extra_opts = "mode=0755"; /* root directory should not be world/group writable, unless overridden */
} else {
what = fstab_node_to_udev_node(arg_root_what);
@@ -883,15 +886,20 @@
default_rw = false; /* read-only, unless overridden */
}
- if (!arg_root_options)
- opts = arg_root_rw > 0 || (arg_root_rw < 0 && default_rw) ? "rw" : "ro";
- else if (arg_root_rw >= 0 ||
- !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
- opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
- else
- opts = arg_root_options;
+ _cleanup_free_ char *combined_options = NULL;
+ combined_options = strdup(strempty(arg_root_options));
+ if (!combined_options)
+ return log_oom();
+
+ if (arg_root_rw >= 0 || !fstab_test_option(combined_options, "ro\0" "rw\0"))
+ if (!strextend_with_separator(&combined_options, ",", arg_root_rw > 0 || (arg_root_rw < 0 && default_rw) ? "rw" : "ro"))
+ return log_oom();
+
+ if (extra_opts)
+ if (!strextend_with_separator(&combined_options, ",", extra_opts))
+ return log_oom();
- log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(arg_root_fstype), strempty(opts));
+ log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(fstype), strempty(combined_options));
if (is_device_path(what)) {
r = generator_write_initrd_root_device_deps(arg_dest, what);
@@ -905,7 +913,7 @@
"/sysroot",
NULL,
fstype,
- opts,
+ combined_options,
is_device_path(what) ? 1 : 0, /* passno */
0, /* makefs off, growfs off, noauto off, nofail off, automount off */
SPECIAL_INITRD_ROOT_FS_TARGET);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/home/homed-home.c systemd-252.39/src/home/homed-home.c
--- systemd-252.38/src/home/homed-home.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/home/homed-home.c 2025-06-26 15:56:09.000000000 +0100
@@ -1173,7 +1173,7 @@
if (stdin_fd < 0)
return stdin_fd;
- log_debug("Sending to worker: %s", formatted);
+ log_debug("Sending request to worker");
stdout_fd = memfd_create("homework-stdout", MFD_CLOEXEC);
if (stdout_fd < 0)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/journal/journald-native.c systemd-252.39/src/journal/journald-native.c
--- systemd-252.38/src/journal/journald-native.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/journal/journald-native.c 2025-06-26 15:56:09.000000000 +0100
@@ -7,6 +7,7 @@
#include
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "io-util.h"
@@ -486,7 +487,7 @@
if (mac_selinux_use()) {
r = setsockopt_int(s->native_fd, SOL_SOCKET, SO_PASSSEC, true);
if (r < 0)
- log_warning_errno(r, "SO_PASSSEC failed: %m");
+ log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, "SO_PASSSEC failed: %m");
}
r = setsockopt_int(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, true);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/journal/journald-syslog.c systemd-252.39/src/journal/journald-syslog.c
--- systemd-252.38/src/journal/journald-syslog.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/journal/journald-syslog.c 2025-06-26 15:56:09.000000000 +0100
@@ -7,6 +7,7 @@
#include "sd-messages.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "io-util.h"
@@ -485,7 +486,7 @@
if (mac_selinux_use()) {
r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, true);
if (r < 0)
- log_warning_errno(r, "SO_PASSSEC failed: %m");
+ log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, "SO_PASSSEC failed: %m");
}
r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, true);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/network/networkd-link.c systemd-252.39/src/network/networkd-link.c
--- systemd-252.38/src/network/networkd-link.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/network/networkd-link.c 2025-06-26 15:56:09.000000000 +0100
@@ -1995,8 +1995,8 @@
r = sd_netlink_message_read_u32(message, IFLA_MASTER, (uint32_t*) &master_ifindex);
if (r == -ENODATA)
- return 0;
- if (r < 0)
+ master_ifindex = 0; /* no master interface */
+ else if (r < 0)
return log_link_debug_errno(link, r, "rtnl: failed to read master ifindex: %m");
if (master_ifindex == link->ifindex)
@@ -2013,6 +2013,9 @@
link_drop_from_master(link);
link->master_ifindex = master_ifindex;
+
+ /* Updating master ifindex may cause operational state change, e.g. carrier <-> enslaved */
+ link_dirty(link);
}
r = link_append_to_master(link);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/network/tc/htb.c systemd-252.39/src/network/tc/htb.c
--- systemd-252.38/src/network/tc/htb.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/network/tc/htb.c 2025-06-26 15:56:09.000000000 +0100
@@ -470,6 +470,8 @@
if (r < 0)
return log_error_errno(r, "Failed to read /proc/net/psched: %m");
+ /* Kernel would never hand us 0 Hz. */
+ assert(hz > 0);
if (htb->buffer == 0)
htb->buffer = htb->rate / hz + htb->mtu;
if (htb->ceil_buffer == 0)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/partition/repart.c systemd-252.39/src/partition/repart.c
--- systemd-252.38/src/partition/repart.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/partition/repart.c 2025-06-26 15:56:09.000000000 +0100
@@ -716,7 +716,6 @@
/* How much do we need to fit? */
required = partition_min_size_with_padding(context, p);
- assert(required % context->grain_size == 0);
for (size_t i = 0; i < context->n_free_areas; i++) {
a = context->free_areas[i];
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/resolve/resolved-dns-cache.c systemd-252.39/src/resolve/resolved-dns-cache.c
--- systemd-252.38/src/resolve/resolved-dns-cache.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/resolve/resolved-dns-cache.c 2025-06-26 15:56:09.000000000 +0100
@@ -854,7 +854,11 @@
return r;
}
-static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, DnsResourceKey *k) {
+static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(
+ DnsCache *c,
+ DnsResourceKey *k,
+ uint64_t query_flags) {
+
DnsCacheItem *i;
const char *n;
int r;
@@ -877,7 +881,7 @@
if (i && i->type == DNS_CACHE_NXDOMAIN)
return i;
- if (dns_type_may_redirect(k->type)) {
+ if (dns_type_may_redirect(k->type) && !FLAGS_SET(query_flags, SD_RESOLVED_NO_CNAME)) {
/* Check if we have a CNAME record instead */
i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_CNAME, n));
if (i && i->type != DNS_CACHE_NODATA)
@@ -997,7 +1001,7 @@
goto miss;
}
- first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key);
+ first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key, query_flags);
if (!first) {
/* If one question cannot be answered we need to refresh */
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/resolve/resolved-dns-query.c systemd-252.39/src/resolve/resolved-dns-query.c
--- systemd-252.38/src/resolve/resolved-dns-query.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/resolve/resolved-dns-query.c 2025-06-26 15:56:09.000000000 +0100
@@ -199,6 +199,8 @@
/* Let's keep a reference to the query while we're operating */
keep_c = dns_query_candidate_ref(c);
+ uint64_t generation = c->generation;
+
/* Start the transactions that are not started yet */
SET_FOREACH(t, c->transactions) {
if (t->state != DNS_TRANSACTION_NULL)
@@ -208,6 +210,13 @@
if (r < 0)
return r;
+ if (c->generation != generation)
+ /* The transaction has been completed, and dns_transaction_complete() ->
+ * dns_query_candidate_notify() has been already called. Moreover, the query
+ * candidate has been regenerated, and the query should be already restarted.
+ * Let's exit from the loop now. */
+ return 0;
+
n++;
}
@@ -271,6 +280,8 @@
dns_query_candidate_stop(c);
+ c->generation++;
+
if (c->query->question_bypass) {
/* If this is a bypass query, then pass the original query packet along to the transaction */
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/resolve/resolved-dns-query.h systemd-252.39/src/resolve/resolved-dns-query.h
--- systemd-252.38/src/resolve/resolved-dns-query.h 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/resolve/resolved-dns-query.h 2025-06-26 15:56:09.000000000 +0100
@@ -18,6 +18,7 @@
struct DnsQueryCandidate {
unsigned n_ref;
int error_code;
+ uint64_t generation;
DnsQuery *query;
DnsScope *scope;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/resolve/resolved-link.c systemd-252.39/src/resolve/resolved-link.c
--- systemd-252.38/src/resolve/resolved-link.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/resolve/resolved-link.c 2025-06-26 15:56:09.000000000 +0100
@@ -670,14 +670,35 @@
return 0;
}
+static bool link_has_link_local_dns(Link *l, int family) {
+
+ /* Check if the link has a link-local dns server for the specified family */
+
+ LIST_FOREACH(servers, s, l->dns_servers)
+ if ((family == AF_UNSPEC || s->family == family) &&
+ in_addr_is_link_local(s->family, &s->address))
+ return true;
+
+ return false;
+}
+
bool link_relevant(Link *l, int family, bool local_multicast) {
+ bool allow_link_local;
+
assert(l);
- /* A link is relevant for local multicast traffic if it isn't a loopback device, has a link
- * beat, can do multicast and has at least one link-local (or better) IP address.
- *
- * A link is relevant for non-multicast traffic if it isn't a loopback device, has a link beat, and has at
- * least one routable address. */
+ /*
+ * A link is relevant if:
+ * - it isn't a loopback device
+ * - has a link beat
+ * - for multicast traffic:
+ * - can do multicast
+ * - has at least one link-local (or better) IP address.
+ * - for non-multicast traffic:
+ * - has at least one address that must be:
+ * - At least link-local, if using a link-local dns server to this interface.
+ * - Better than link-local.
+ */
if ((l->flags & (IFF_LOOPBACK | IFF_DORMANT)) != 0)
return false;
@@ -696,8 +717,11 @@
!IN_SET(l->networkd_operstate, LINK_OPERSTATE_DEGRADED_CARRIER, LINK_OPERSTATE_DEGRADED, LINK_OPERSTATE_ROUTABLE))
return false;
+ allow_link_local = local_multicast || link_has_link_local_dns(l, family);
+
LIST_FOREACH(addresses, a, l->addresses)
- if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a, local_multicast))
+ if ((family == AF_UNSPEC || a->family == family) &&
+ link_address_relevant(a, allow_link_local))
return true;
return false;
@@ -1127,13 +1151,13 @@
return 0;
}
-bool link_address_relevant(LinkAddress *a, bool local_multicast) {
+bool link_address_relevant(LinkAddress *a, bool allow_link_local) {
assert(a);
if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
return false;
- if (a->scope >= (local_multicast ? RT_SCOPE_HOST : RT_SCOPE_LINK))
+ if (a->scope >= (allow_link_local ? RT_SCOPE_HOST : RT_SCOPE_LINK))
return false;
return true;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/resolve/resolved-link.h systemd-252.39/src/resolve/resolved-link.h
--- systemd-252.38/src/resolve/resolved-link.h 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/resolve/resolved-link.h 2025-06-26 15:56:09.000000000 +0100
@@ -111,7 +111,7 @@
int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr);
LinkAddress *link_address_free(LinkAddress *a);
int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m);
-bool link_address_relevant(LinkAddress *l, bool local_multicast);
+bool link_address_relevant(LinkAddress *l, bool allow_link_local);
void link_address_add_rrs(LinkAddress *a, bool force_remove);
bool link_negative_trust_anchor_lookup(Link *l, const char *name);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/src/sysupdate/sysupdate.c systemd-252.39/src/sysupdate/sysupdate.c
--- systemd-252.38/src/sysupdate/sysupdate.c 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/src/sysupdate/sysupdate.c 2025-06-26 15:56:09.000000000 +0100
@@ -829,6 +829,9 @@
log_info("%s Successfully installed update '%s'.", special_glyph(SPECIAL_GLYPH_SPARKLES), us->version);
+ (void) sd_notifyf(/* unset_environment=*/ false,
+ "STATUS=Installed '%s'.", us->version);
+
if (ret_applied)
*ret_applied = us;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount systemd-252.39/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount
--- systemd-252.38/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount 2025-06-26 15:56:09.000000000 +0100
@@ -9,4 +9,4 @@
What=rootfs
Where=/sysroot
Type=tmpfs
-Options=rw
+Options=rw,mode=0755
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/test/test-network/systemd-networkd-tests.py systemd-252.39/test/test-network/systemd-networkd-tests.py
--- systemd-252.38/test/test-network/systemd-networkd-tests.py 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/test/test-network/systemd-networkd-tests.py 2025-06-26 15:56:09.000000000 +0100
@@ -3931,6 +3931,21 @@
print(output)
self.assertRegex(output, 'master bond199')
+ # Test case for #37629
+ for _ in range(3):
+ # When a slave leaved from its master bonding interface, the kernel brings down the slave.
+ check_output('ip link set dummy98 nomaster')
+ self.wait_online('dummy98:off')
+
+ # Bring up the interface to check if networkd recognizes the interface has no master now.
+ check_output('ip link set dummy98 up')
+ self.wait_online('dummy98:carrier')
+
+ # We need to first bring down the interface to make it join a bonding interface.
+ check_output('ip link set dummy98 down')
+ check_output('ip link set dummy98 master bond199')
+ self.wait_online('dummy98:enslaved')
+
def test_bond_active_slave(self):
copy_network_unit('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
start_networkd()
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/test/units/testsuite-71.sh systemd-252.39/test/units/testsuite-71.sh
--- systemd-252.38/test/units/testsuite-71.sh 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/test/units/testsuite-71.sh 2025-06-26 15:56:09.000000000 +0100
@@ -29,7 +29,7 @@
if [[ -n "$orig" ]]; then
assert_in "Static hostname: $orig" "$(hostnamectl)"
fi
- assert_in "Kernel: $(uname -s) $(uname -r)" "$(hostnamectl)"
+ assert_in "Kernel: $(uname -s) $(uname -r | sed 's/\+/\\+/g')" "$(hostnamectl)"
# change hostname
assert_rc 0 hostnamectl set-hostname testhost
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.38/test/units/testsuite-74.coredump.sh systemd-252.39/test/units/testsuite-74.coredump.sh
--- systemd-252.38/test/units/testsuite-74.coredump.sh 2025-05-29 18:44:54.000000000 +0100
+++ systemd-252.39/test/units/testsuite-74.coredump.sh 2025-06-26 15:56:09.000000000 +0100
@@ -166,7 +166,7 @@
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509902 12345 youmachine 1
# Wait a bit for the coredumps to get processed
-timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
+timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 3 ]]; do sleep 1; done"
coredumpctl info $$
coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
coredumpctl info COREDUMP_TIMESTAMP=1679509901000000