Skip to content

fix(dracut-install): remove FTS_NOSTAT in install_modules() fts traversal#2394

Open
jpoimboe wants to merge 1 commit into
dracut-ng:mainfrom
jpoimboe:fix-fts-nsok
Open

fix(dracut-install): remove FTS_NOSTAT in install_modules() fts traversal#2394
jpoimboe wants to merge 1 commit into
dracut-ng:mainfrom
jpoimboe:fix-fts-nsok

Conversation

@jpoimboe
Copy link
Copy Markdown

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 checking for FTS_NSOK.

Checklist

  • I have tested it locally
  • I have reviewed and updated any documentation if relevant
  • I am providing new code and test(s) for it

@jpoimboe jpoimboe requested a review from a team as a code owner April 15, 2026 17:41
@github-actions github-actions Bot added dracut-install Issues related to dracut install c labels Apr 15, 2026
Copy link
Copy Markdown
Contributor

@aafeijoo-suse aafeijoo-suse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this well before the glibc 2.44 release. I tested dracut + glibc from git main without and with your patch and I can confirm its critical.

All the fts_open() in dracut-install have the FTS_NOSTAT flag, but the fts_info value is only filtered for directories.

FTR, I'm not sure the current glibc status in other distros, but openSUSE Tumbleweed ships 2.42, while 2.43 is in staging, so there is still time until dracut breaks the system if it's not fixed.

@jpoimboe
Copy link
Copy Markdown
Author

@aafeijoo-suse
Copy link
Copy Markdown
Contributor

Some related links for reference: https://sourceware.org/bugzilla/show_bug.cgi?id=34078 https://bugzilla.redhat.com/show_bug.cgi?id=2457183 https://inbox.sourceware.org/libc-alpha/lhutstid62v.fsf@oldenburg.str.redhat.com/

Ok, so it's already affecting rawhide. Let's wait and see if dracut is not the only one affected by this change.

@jpoimboe
Copy link
Copy Markdown
Author

Yeah, that's how I discovered it, I couldn't boot my kernel on Rawhide :-)

Conan-Kudo
Conan-Kudo previously approved these changes Apr 16, 2026
@Conan-Kudo Conan-Kudo enabled auto-merge (rebase) April 16, 2026 10:55
@eggert
Copy link
Copy Markdown

eggert commented Apr 16, 2026

The draft patch is dubious, because if ftsent->fts_info == FTS_NSOK we don't know whether the file is a regular file or a symbolic link or something else, so we don't know whether to ignore it. A safer and simpler patch would be this:

diff --git a/src/install/dracut-install.c b/src/install/dracut-install.c
index efa64306..ac70b8dd 100644
--- a/src/install/dracut-install.c
+++ b/src/install/dracut-install.c
@@ -2708,7 +2708,7 @@ static int install_modules(int argc, char **argv)
 
                         {
                                 char *paths[] = { path1, path2, path3, NULL };
-                                fts = fts_open(paths, FTS_COMFOLLOW | FTS_NOCHDIR | FTS_NOSTAT | FTS_LOGICAL, NULL);
+                                fts = fts_open(paths, FTS_COMFOLLOW | FTS_NOCHDIR | FTS_LOGICAL, NULL);
                         }
 
                         for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {

@eggert
Copy link
Copy Markdown

eggert commented Apr 16, 2026

A safer and simpler patch would be this:

Alternatively, if efficiency is important (and I guess it is, if you're using FTS_NOSTAT), here is a safe but slightly-more-complicated patch. (I have not compiled or tested either patch.)

diff --git a/src/install/dracut-install.c b/src/install/dracut-install.c
index efa64306..fa09cc69 100644
--- a/src/install/dracut-install.c
+++ b/src/install/dracut-install.c
@@ -2715,6 +2715,10 @@ static int install_modules(int argc, char **argv)
                                 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
                                 _cleanup_free_ const char *modname = NULL;
 
+                                if (ftsent->fts_info == FTS_NSOK) {
+                                        fts_set(fts, ftsent, FTS_AGAIN);
+                                        continue;
+                                }
                                 if ((ftsent->fts_info == FTS_D) && !check_module_path(ftsent->fts_accpath)) {
                                         fts_set(fts, ftsent, FTS_SKIP);
                                         log_debug("Skipping %s", ftsent->fts_accpath);

@aafeijoo-suse
Copy link
Copy Markdown
Contributor

The draft patch is dubious, because if ftsent->fts_info == FTS_NSOK we don't know whether the file is a regular file or a symbolic link or something else, so we don't know whether to ignore it.

I don't know about special kernel builds, but with the ones I tested, packaged and shipped by the distro, since we are traversing the kernel file tree, where we had FTS_F (".ko*" files), now we have FTS_NSOK. Exactly the same files, no additional surprises. So, for me the patch works fine. Let's see the feedback from others.

@eggert
Copy link
Copy Markdown

eggert commented Apr 17, 2026

I don't know about special kernel builds, but with the ones I tested, packaged and shipped by the distro, since we are traversing the kernel file tree, where we had FTS_F (".ko*" files), now we have FTS_NSOK. Exactly the same files, no additional surprises. So, for me the patch works fine.

Sure, but if all you have are directories and regular files, then the existing test (ftsent->fts_info != FTS_F) && (ftsent->fts_info != FTS_SL) would not be needed with old glibc - at that point the file cannot be a directory (this has already been checked) so if all you have are directories and regular files then it must be a regular file and the existing test will always yield false.

But surely that test was put in for a reason. dracut is checking for files that are neither directories nor regular files nor symbolic links because it wants to ignore them. And that means the patch originally proposed in this pull request cannot be right, because in some cases it would cause dracut to fail to ignore these files.

@aafeijoo-suse
Copy link
Copy Markdown
Contributor

But surely that test was put in for a reason.

10 years ago without any comments, so unfortunately the reason is unknown.

dracut is checking for files that are neither directories nor regular files nor symbolic links because it wants to ignore them. And that means the patch originally proposed in this pull request cannot be right, because in some cases it would cause dracut to fail to ignore these files.

Ack. I wonder which kernel source code tree files fail outside of these 3 categories. Maybe FTS_SLNONE if there is any broken symlink?

auto-merge was automatically disabled April 19, 2026 21:51

Head branch was pushed to by a user without write access

…rsal

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.
@jpoimboe jpoimboe changed the title fix(dracut-install): handle FTS_NSOK in install_modules() fts traversal fix(dracut-install): remove FTS_NOSTAT in install_modules() fts traversal Apr 19, 2026
@jpoimboe
Copy link
Copy Markdown
Author

Agreed, I changed it to remove FTS_NOSTAT so the existing error checking behavior for non-files and non-symlinks continues to work.

@haraldh
Copy link
Copy Markdown
Contributor

haraldh commented Apr 20, 2026

I guess it was just defensive programming back in the days... FTS_NOSTAT was of course only for speed, which in hindsight did not do anything 😄

aafeijoo-suse pushed a commit to openSUSE/dracut-ng that referenced this pull request May 7, 2026
…rsal

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.

(cherry picked from dracut-ng#2394)
aafeijoo-suse pushed a commit to openSUSE/dracut-ng that referenced this pull request May 7, 2026
…rsal

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.

(cherry picked from dracut-ng#2394)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c dracut-install Issues related to dracut install

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants