chore(Makefile): filter out chrony dracut module for non-systemd
chrony dracut module in its current form depends on the systemd
dracut module. Filter out chrony dracut module during build
time for enviroments not supporting systemd to be consisent with
othersystemd dependent dracut modules.
Benjamin Drung [Thu, 23 Jul 2026 10:40:46 +0000 (12:40 +0200)]
fix(mdraid): install 59-persistent-storage-md.rules only when needed
Dracut installs in the initrd a custom `59-persistent-storage-md.rules`
only to set the option `db_persist`. The main purpose is that if an MD
device is activated in the initrd, its properties are kept on the udev
database after the transition from the initrd to the rootfs. This was
added to fix detection issues when LVM is on top.
mdadm 4.5 included this change from Dracut. Therefore installing
`59-persistent-storage-md.rules` is not needed any more when using
mdadm >= 4.5. `59-persistent-storage-md.rules` can be removed completely
once Dracut drops support for mdadm < 4.5.
See also: https://github.com/md-raid-utilities/mdadm/pull/143
fix(nfs): rpc.statd binary is not required for NFSv4
Dracut fails to create initramfs on nfs4-only host as
the rpc.statd binary is not required for NFSv4 and yet
dracut is checking for its existence and fails.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2483609 Fixes: https://github.com/dracut-ng/dracut/issues/2488 Co-authored-by: Pavel Simó <pavel.simo@gmail.com>
This new module relies on chrony to add support for NTP in the initrd. By
default, it also uses NTP sources from DHCP.
It provides two new kernel command line options:
- `rd.ntp`: it can be used multiple times to specify server, pool and peer time
sources.
- `rd.ntp.nodhcp`: it disables the use of NTP sources from DHCP.
In some environments, it's necessary to fetch live images from HTTPS URLs. The
problem is that the hardware clock may be off, so the validation of the SSL
certificates may fail if the time is out of sync. Also, some systems may not
have access to DHCP for security reasons, that's why we need a way to configure
them on the kernel command line.
Hans de Goede [Fri, 13 Mar 2026 18:13:57 +0000 (19:13 +0100)]
feat(dracut): add module to load Qualcomm ADSP module pre-udev
On Qualcomm sc8280xp and x1e laptops the kernel reboots the ADSP with new
firmware because the BIOS loads ADSP firmware with limited functionality
without sound or battery charge/status reading support.
Unfortunately the ADSP also controls the TCPM (Type-C Port Manager) and
rebooting the ADSP also resets the TCPM, causing any USB devices connected
over Type-C ports to get disconnected as all devices on the USB bus are
removed and re-enumerated.
This breaks booting from USB-drives as the drive gets disconnected and
re-enumerated as a new block device, leaving any filesystems mounted
before the ADSP reset without any backing device.
To workaround this add a module to load the ADSP driver from a pre-udev
hook so that the USB re-enumeration happens before the rootfs is mounted.
Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
Changes in v5:
- Sort `inst_multiple` arguments alphabetically
Changes in v4:
- Change host-only check to [[ $hostonly_mode == "strict" ]] so that
30-qcom-adsp-pre-udev.sh gets installed in sloppy hostonly mode
- Add modprobe to list of binaries to install from install()
Changes in v3:
- Add "inst grep" to install()
Changes in v2:
- Directly use $DRACUT_ARCH instead of defining _arch local var
- Add the new module to labeler.yml and core.adoc
Benjamin Drung [Fri, 24 Jul 2026 12:41:22 +0000 (14:41 +0200)]
style: remove unneeded function keyword
`function` is a non-standard keyword that can be used to declare
functions in Bash and Ksh, but this would not work with POSIX shell.
Remove it to make the code more consistent (and potential easier to port
to POSIX).
fix(dracut-install): check return value in modalias read()
`find_kmod_module_from_sysfs_modalias()` reads the content of the modalias file
via `len = read()`, and then writes to `alias[len - 1]` without checking if
read() returned 0 (empty file) or -1 (error), potentially causing a stack buffer
out-of-bounds write.
fix(dracut-install): handle empty string in dir_len()
`strlen()` returns the unsigned type size_t, so if `file` were an empty string,
`strlen(file) - 1` would return SIZE_MAX, causing an out-of-bounds read.
Benjamin Drung [Thu, 18 Jun 2026 13:23:30 +0000 (15:23 +0200)]
ci: unify timeout to 10 min by default
Most tests take only a few seconds or minutes on AMD. The tests on ARM
are two to four times slower than their AMD counterparts (due to not
using KVM).
All tests finish in under five minutes except test 60-NFS on AMD (which
can take six to seven minutes) and following tests on ARM:
| Test | Duration | Timeout |
| ----------------- | --------- | ------- |
| 11-USR-MOUNT | 5-10 min | 20 min |
| 20-STORAGE | 9-22 min | 40 min |
| 21-OVERLAYFS | 5-11 min | 20 min |
| 26-ENC-RAID-LVM | 9-21 min | 40 min |
| 30-DMSQUASH | 5-10 min | 20 min |
| 41-FULL-SYSTEMD | 5-9 min | 20 min |
| 45-SYSTEMD-IMPORT | 7 min | 20 min |
| 60-NFS | 19-49 min | 60 min |
| 71-ISCSI | 9 min | 20 min |
| 72-ISCSI-MULTI | 9-20 min | 40 min |
So use a 10 min timeout on all AMD tests and most ARM tests, but
increase the timeout for ARM for those test mentioned above. So use 20
min timeout for several ARM tests, 40 min timeout for 20-STORAGE,
26-ENC-RAID-LVM, 72-ISCSI-MULTI on ARM, and 60 min timeout for 60-NFS
on ARM.
Jihong Min [Tue, 7 Jul 2026 22:07:05 +0000 (07:07 +0900)]
fix(kernel-modules): include xhci-pci-prom21 for early USB
Since Linux 7.2-rc1, AMD PROM21 xHCI controllers may be handled by the
separate xhci-pci-prom21 PCI glue driver.
When CONFIG_USB_XHCI_PCI_PROM21=m, plain xhci-pci intentionally returns
-ENODEV for the PROM21 PCI IDs so that xhci-pci-prom21 can bind them.
However, xhci-pci-prom21 is not a dependency of xhci-pci, so an
initramfs can include xhci-pci.ko while missing xhci-pci-prom21.ko.
On systems where USB keyboard or storage is attached through a PROM21
controller, this can make USB unavailable during initrd, for example at
Plymouth/LUKS unlock.
This is the same class of issue as xhci-pci-renesas, which dracut
already includes explicitly.
Benjamin Drung [Tue, 21 Jul 2026 23:26:43 +0000 (01:26 +0200)]
test(DRACUT-CPIO): fix specifying initrd name twice
The initrd output file name parameter was moved to the `test_dracut`.
Thus specifying the initrd name in the `test_dracut` would become the
second parameter for dracut and interpreted as kernel name. This would
lead to this `realpath` failure:
```
Calling dracut --confdir /var/tmp/dracut-test.NilYUr/dracut.conf.d --add-confdir test --tmpdir /var/tmp/dracut-test.NilYUr/initrd --no-kernel --drivers '' --add-confdir test --enhanced-cpio --no-compress --nostrip --include /var/tmp/dracut-test.NilYUr/cpio-test.Gg7wLrYrO7/simple/init.sh /usr/lib/dracut/hooks/emergency/00-init.sh --install poweroff /var/tmp/dracut-test.NilYUr/cpio-test.Gg7wLrYrO7/simple/initramfs /var/tmp/dracut-test.NilYUr/initramfs.testing
realpath: /lib/modules//var/tmp/dracut-test.NilYUr/initramfs.testing: No such file or directory
```
So use the common initrd output file name in the dracut-cpio test case
as well.
Fixes: 4d55517094f6 ("ci: consolidate output filename for test runs")
Benjamin Drung [Thu, 16 Jul 2026 14:18:08 +0000 (16:18 +0200)]
feat(resume): include in hostonly sloppy mode if supported by kernel
Systems might support hibernation. They need the resume module to get a
working hibernation. Users might configure their systems to enable
hibernation, but the correct order of steps are crucial for it.
Currently this workflow does not work:
1. Make sure system is supported the power state:
```
$ cat /sys/power/state
freeze mem disk
```
2. Configured swap partition
3. Populated the resume kernel boot parameter `resume=/dev/<swap partition>`
4. update grub
5. regenerate initrd
Regenerating the initrd will not include the resume module, because it
hits the "hibernation supported by the kernel, but not enabled" code
path (`/proc/cmdline` doesn not contain `resume=` yet and
`/sys/power/resume` contains `0:0`). A user would need to reboot once
before regenerating the initrd.
To make the system more predictable, include the `resume` module in
hostonly `sloppy` mode if hibernation is supported by the kernel.
fix(network-manager): prevent command injection while parsing DHCP options
Replacing `printf '%q'` with the custom `escape` function introduced a flaw: if
the whole format string is surrounded by single quotes (`'%s='%s'\n'`),
the shell consumes those inner `'` characters as quoting delimiters instead of
passing them to printf, so it receives just `%s=%s\n`, i.e., the surrounding
quotes around the value are gone. Since nothing is quoted, now commands can be
injected via dhcpopts files.
fix(systemd-networkd): escape values from DHCP options
Although systemd-networkd filters invalid values for DHCP options before writing
them to lease files, it's a good practice to escape values read from lease files
before writing them to ".dhcpopts" files, because ".dhcpopts" files are sourced
as a shell script in multiple parts [1][2][3].
fix(dracut-lib): sanitize variable assignments using eval
`splitsep()` uses `eval "$1='${tmp}'"` and `eval "$1='$str'"` to assign values
to caller-named variables. A single quote in the value breaks out of the
assignment.
`export_n()` uses `eval "$var=\"$val\""` to re-assign an unexported variable. A
double quote in the value breaks out of the assignment.
fix(overlayfs-crypt): prevent eval injection in parse_overlay_opts()
parse_overlay_opts() used eval "${ns}${key}='${val}'" to assign
parsed options from the rd.overlay.crypt kernel cmdline parameter.
A single quote in the value breaks out of the assignment and allows
arbitrary command execution.
Fixes: GHSA-wr6r-5whr-98qx Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
systemd-pcrnvdone.service was added in systemd-v259, but runs in the initrd
since systemd-v261 [1], and it acts as additional separator measurement
separating pre-boot (firmware + bootloader) measurements from OS measurements.
systemd-pcrosseparator.service was added in systemd-v261 [2], and it measures a
separator event into PCR 9 once all NvPCRs have completed initialization.
Miao Wang [Fri, 3 Jul 2026 11:57:53 +0000 (19:57 +0800)]
fix(dracut-systemd): add ordering constraints
When dracut-initqueue is not enabled, there would be no
dracut-initqueue.service as a sequence point. So explicitly
declare After = basic.target to order dracut-pre-mount.service
after all the services ordered before dracut-initqueue.service.
Fixes: b1ae591945ac ("dracut-systemd: add back missing dependencies")
fix(dracut-install): remove FTS_NOSTAT in install_modules() fts traversal
install_modules() uses FTS_NOSTAT when traversing kernel module
directories. With FTS_NOSTAT, fts may skip stat() and report regular
files as FTS_NSOK instead of FTS_F. However, the fts_info check only
accepts FTS_F and FTS_SL, causing all .ko files found this way to be
silently skipped.
This was previously masked by glibc's fts implementation which ignored
FTS_NOSTAT when FTS_LOGICAL was also set, always calling stat and
returning FTS_F. A recent glibc change (commit 99303f3871, "io: Use
gnulib fts implementation") now honors FTS_NOSTAT regardless, exposing
this bug.
The result is that all '=directory' pattern module installs (=drivers,
=crypto, =fs, etc.) find zero modules, producing an initramfs with only
explicitly-named modules (~40 instead of ~500+), which typically fails
to boot.
Fix it by removing FTS_NOSTAT so that fts always stats files and
reliably reports actual file types.
Stuart Hayes [Fri, 15 May 2026 18:21:27 +0000 (20:21 +0200)]
fix(nvmf): parse json output from "nvme list-subsys"
Modify code that parses the output of "nvme list-subsys" to set up
rd.nvmf.discover parameter to use the json output of nvme rather than the
human-readable output.
A recent commit to nvme-cli changed the human-readable output to only
print the transport address rather than the address line that includes all
of the needed information, but the json output still contains the needed
information.
An even more recent commit to nvme-cli changed the json output (it moved
some details from the "Address" value to an "AddressDetails" object), so
support that as well as the previous format.
Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com> Signed-off-by: Martin Wilck <mwilck@suse.com>
Martin Wilck [Mon, 6 Jul 2026 20:35:27 +0000 (22:35 +0200)]
fix(nvmf): make network driver determination work without nbft$X
82f7f7d ("improvement(74nvmf): lookup required NIC kernel modules for NBFT
interfaces") assumes that the NBFT network interfaces are named according
to the nbft$X convention, which is no longer true with the latest patches.
Martin Wilck [Mon, 16 Feb 2026 22:34:20 +0000 (23:34 +0100)]
feat(nvmf): allow using system interface naming policy
nm-initrd-generator from NetworkManager 1.54 or newer supports parsing the
NBFT directly. Because NM allows identifying network interface by MAC
address, we don't need the ifname= setting any more to identify the
interface at the cmdline stage. We just need to check whether the system
has an NBFT with at least one entry.
Introduce the cmdline parameter "rd.nvmf.nm" to force dracut to use
nm-initrd-generator to set up network interfaces from the NBFT.
Martin Wilck [Mon, 16 Feb 2026 19:11:26 +0000 (20:11 +0100)]
feat(nvmf): add dracut.conf option nvmf_nbft_mode
Add a dracut.conf.d option to control the generation of rd.nvmf.discover=
entries if hostonly_cmdline = "yes".
The option can take the values "static" (previous default behavior,
generate cmdline entries for every NVMe subsystem in the device stack),
"nbft" (don't generate any for tcp transport if an NBFT is present),
and "match" (only generate rd.nvmf.discover= entries for subsystems that
are not matched by current NBFT entries, as implemented by the previous
commit).
The default is "match", because this should fit user expectations best.
Martin Wilck [Mon, 16 Feb 2026 17:40:25 +0000 (18:40 +0100)]
feat(nvmf): enable adapting to NBFT reconfiguration
The cmdline() function of the nvmf module creates rd.nvmf.discover=
cmdline entries for all discovered subsystems. But this is often
not desirable for systems booting from an NBFT table, where the
contents of the table may change between reboots. With hard-coded
rd.nvmf.discover= entries, booting may fail if the NBFT configuration
has changed.
Compare the traddr/trsvcid pairs that appear in the block device
stack with the contents of the NBFT, and don't create rd.nvmf.discover=
entries for those that are matched.
Note: This approach is simplified, as entries might differ by
host_traddr. But such configurations are extremely rare, and
because we don't use interface-specific routes (VRF-lite) in the
initrd, omitting these entries can't cause boot failure, as long
as they match by transport, traddr, and trsvcid.
A follow-up patch will introduce an option to modify this behavior.
Martin Wilck [Mon, 16 Feb 2026 19:29:19 +0000 (20:29 +0100)]
fix(dracut.conf.5): move fstab/chroot warning to hostonly_mode section
The warning about using --fstab when chrooted belongs into the
hostonly_mode section, as can be seen in commit 888d53f ("replace xml
documentation with asciidoc"). It seems to have moved slowly downward.
Fix it.
fix(network-legacy): sanitize DHCP values in dhclient-script.sh
A rogue DHCP server can inject shell commands through hostname,
domain, gateway, and classless static route values. These values
are written to /tmp files that setup_net() later sources as shell.
- Sanitize hostname to RFC 952 chars (a-zA-Z0-9.-)
- Strip control chars from domain (like search already does)
- Validate gateway IPs contain only digits and dots
- Single-quote interpolated values in generated shell commands
- Validate all parse_option_121 octets are numeric upfront;
the existing inline checks only validated mask and the first
destination octet, leaving dest octets 2-4 and all four
gateway octets unchecked — those flow into shell commands
written to the initqueue/setup_net_"$netif".sh hook script
via echo
Fixes: CVE-2026-6893 Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Benjamin Drung [Tue, 31 Mar 2026 14:15:49 +0000 (16:15 +0200)]
ci: switch from debian:latest to ubuntu:rolling
Commit 28323e6b769c ("ci: switch from ubuntu:devel to a more stable
debian:latest") switched away from the Ubuntu devel release (which can
be more unstable since it is a release in development) but also switched
from Ubuntu to Debian.
Switch to `ubuntu:rolling` which is the latest Ubuntu release which
should be stable enough for our purposes. Ubuntu gets a new release
every six month in comparsion to Debian which cuts a new release around
every two years.
Miao Wang [Fri, 3 Jul 2026 13:02:52 +0000 (21:02 +0800)]
fix(virtfs): move mount hook to pre-mount
Mount hooks are executed after sysroot.mount when systemd is used.
However, the systemd generated sysroot.mount from kernel cmdline will
always fail when the given root= begins with virtfs:, making the system
unable to start.
Moving the mount hook to pre-mount will mount the 9p virtfs directly
onto /sysroot and the generated sysroot.mount will be ignored. This
practice is similar to what is in virtiofs.
Miao Wang [Fri, 10 Jul 2026 09:12:51 +0000 (17:12 +0800)]
test(run-qemu): use -accel kvm instead of -enable-kvm
-enable-kvm is believed to be deprecated [1] and -accel kvm should be
used instead. -enable-kvm will not support new architectures even if KVM
is actually supported on these architectures. -accel kvm is recommended
instead as a unified option to enable KVM on all the architectures.
Benjamin Drung [Tue, 7 Jul 2026 12:49:31 +0000 (14:49 +0200)]
feat(resume): add debug logs to check()
To ease debugging, add debug logs to the different cases in `check()`.
Then the reason for not including the `resume` module can be seen in the
output of:
```
dracut -L 5 --force
```
Related issue: https://github.com/dracut-ng/dracut/issues/1472
test(systemd): disable man page checks in verify test
TEST-40-SYSTEMD verifies initrd systemd targets, but systemd-analyze
verify can also check referenced man pages. In the initrd test
environment this may fail on man systemd.special, causing a false
negative before the test reaches its success path.
Use --man=no so the test validates unit semantics without depending on
man page availability.
Miao Wang [Fri, 12 Jun 2026 10:47:40 +0000 (18:47 +0800)]
test(run-qemu): use efi firmware when testing on loongarch64
When testing on loongarch64, we should use EFI firmware, since
the UEFI runtime services and ACPI tables are required by the
linux kernel for loongarch64.
fiftydinar [Thu, 28 May 2026 15:07:19 +0000 (17:07 +0200)]
fix(base): use printf instead of echo for hook variable
Use printf instead of echo in list_hooks() to avoid dash's echo interpreting \x2f hex escapes, which corrupts hook file paths containing escaped slashes.
1. parse-root.sh creates a hook file with \x2f-escaped device paths via str_replace()
2. list_hooks() finds the file via glob but outputs it with echo, which dash interprets as hex escapes
3. The corrupted path causes check_finished() to never find the real hook, looping until timeout (~5 min boot delay)
Benjamin Drung [Thu, 7 May 2026 22:25:10 +0000 (00:25 +0200)]
test(SYSROOT): properly fail test in case of password mismatch
In case the password mismatches in the sysroot test, the test should
fail. So return with code 1 instead of removing `initramfs.testing`
(which will cause the test to fail later). This eases debugging.
Luca Boccassi [Sun, 31 May 2026 14:29:50 +0000 (15:29 +0100)]
fix(systemd-networkd): get DHCP options values from networkctl
The internal lease is no longer saved to the private /run/ directory
of networkd since v261, so it cannot be read from there. It was always
clearly marked as private anyway.
Use the new 'dhcp-lease' networkctl verb to print it instead.
fix(iscsi): handle empty URI in firmware boot mode
When rd.iscsi.firmware=1 is set, netroot is either 'iscsi' or 'iscsi:'
with no real URI. parse_iscsi_root() was called with these values causing
'shift count out of range' errors as shift was called on empty positional
parameters.
Add two guards in parse_iscsi_root() to return early when there are no
parameters left to parse, and skip handle_netroot() in iscsiroot.sh when
netroot has no real target.
fix(kernel-modules): add Mediatek MTU3 USB controller
This is the USB dual-role controller used by some MediaTek SoCs.
Adding it fixes booting from USB storage on Lenovo Chromebook Duet EDU
G2 (mt8188-geralt-ciri). That device does not have any SD slot, so USB
storage is the only usable external storage.
Benjamin Drung [Wed, 6 May 2026 16:36:43 +0000 (18:36 +0200)]
test: exit after create-root.sh has been run
The `create-root.sh` scripts are installed as initqueue hook and soured
by it. So just having an exit hook is not enough. The script needs to
exit explicitly to shutdown the boot.
Fixes: 39e4b0a37bb5 ("test: drop poweroff call where poweroff is called by EXIT trap")
Mewt R [Mon, 20 Apr 2026 00:37:27 +0000 (20:37 -0400)]
refactor(dracut): remove unnecessary 'realpath' call if -k/--kmoddir specified
No need to use 'realpath' to resolve a default directory to look for modules
if one has already been specified. 'realpath' will complain if the directory doesn't exist
which can lead a user to think that something went wrong.
According to https://github.com/systemd/systemd/issues/40159#issuecomment-3760597003
the initramfs is expected to include the nvpcr definition files from systemd for
v259 compatibility.
test(SYSTEMD-SYSEXT): introduce tests for systemd-sysext
- A confext creates a marker in /etc/dracut-confext with the content
"dracut-sysext-success".
- A sysext creates a script in
/usr/lib/dracut/hooks/initqueue/finished/dracut-sysext.sh that simply checks if
/etc/dracut-confext exists and prints a message with its content. If this
initqueue script does not succeed, the initqueue main loop will not exit and the
system will not boot.
- Also, check in the QEMU log that "dracut-sysext-success" was printed.
Note:
- systemd-repart creates erofs partitions by default. If it is not supported by
the running distribution, override it to use squashfs.
fix(systemd-sysext): add dependency to systemd-veritysetup
The common use case is a bootloader or a UEFI boot stub (e.g. systemd-stub(7))
that follows the BLS adding extensions found in the ESP to the /.extra directory
in the initrd. In this case, it's used by default a strict
"root=signed+absent:usr=signed+absent" image policy (see
systemd.image-policy(7)). This means, Verity authentication and a PKCS#7
signature of the Verity root hash.
fix(systemd-veritysetup): validate dm-verity signatures in userspace
Since [1], if the validation against the kernel does not work, systemd searches
for PKCS#7 certificates in `/{etc,usr/lib}/verity.d` as a fallback mechanism to
validate dm-verity signatures.
perf(systemd-sysext): do not attempt to install extension metadata
Files under /usr/lib/extension-release.d/extension-release.* and
/etc/extension-release.d/extension-release.* are self contained in sysexts and
confexts respectively. The important file to check if an extension can be
installed is the os-release.
fix(functions): prevent find_binary from dropping last PATH element
When `read` encounters EOF before the delimiter, it returns a non-zero
exit status, causing the while loop to terminate immediately. As a result,
if the PATH string doesn't end with a colon, the very last directory in
PATH is ignored by find_binary().
This caused regressions on split-usr architectures where critical
binaries reside exclusively in /bin, and /bin happens to be
appended at the very end of the PATH by dracut.sh.
Appending a virtual colon to the Here-String ensures the loop processes
all directories correctly.