Skip to content

Modinfo rework - #451

Open
evelikov wants to merge 18 commits into
kmod-project:masterfrom
evelikov:modinfo-rework
Open

Modinfo rework#451
evelikov wants to merge 18 commits into
kmod-project:masterfrom
evelikov:modinfo-rework

Conversation

@evelikov

Copy link
Copy Markdown
Collaborator

Here's a series addressing most of the formatting issues raised in #434. In particular the formatting code is unified and beaten into shape to use consistent formatting. With the outstanding bits being:

  • the module description string is free-form and can have misc whitespace characters - \t, \n et al
  • the signature value is still has multi-line/wrapped/tabbed formatting

In all fairness, I'm inclined to leave those as-is and let other handle them in a future PR.

The first 3 commits are something we'd probably want for the stable 34.x branch assuming there will be another release. Although, in that case we should probably check the other PRs for similar non-invasive fixes.

For the PR itself - it mostly small prep and fixup patches with the most sizable change being modinfo: rework parm handling.

Resolves: #434

@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 73.01587% with 34 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
tools/modinfo.c 73.73% 13 Missing and 13 partials ⚠️
testsuite/test-shared.c 71.42% 1 Missing and 5 partials ⚠️
shared/strbuf.c 66.66% 0 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
shared/macro.h 100.00% <ø> (ø)
shared/strbuf.h 75.00% <ø> (ø)
shared/strbuf.c 80.39% <66.66%> (+3.03%) ⬆️
testsuite/test-shared.c 76.42% <71.42%> (ø)
tools/modinfo.c 52.80% <73.73%> (+2.99%) ⬆️

... and 17 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread tools/modinfo.c Fixed
@evelikov

evelikov commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

The latest revision has all the yaks shaved on my end ;-)

v2:

  • drop calloc commit
  • enum names p_parm{desc,type} -> parm_{desc,type]
  • find matching or empty entry in a single loop (add_param)
  • match up-to UINT_MAX parm/parmtype entries
  • drop unneeded INT_MAX checks for strlen(value)
  • don't return success if we fail to [cm]alloc
  • kill off struct param::{desc,type}len
  • rework parm string length validation

Edit: this time for real - aka rebase + clang-format nitpick

@evelikov

evelikov commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

NOTE: this effectively prints the "parm" entries in inverse order... AFAICT that should not be an issue, since the output order was never meant to be deterministic.

Comment thread tools/modinfo.c Outdated
Comment thread tools/modinfo.c Outdated
Comment thread tools/modinfo.c Outdated
{
const enum kmod_module_initstate state = kmod_module_get_initstate(mod);
const bool is_builtin = state == KMOD_MODULE_BUILTIN;
const char *filename = is_builtin ? "(builtin)" : kmod_module_get_path(mod);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we need to be careful here... we may be running modinfo() into a module that is builtin for the current kernel, but we are actually doing modinfo for something else.

Example: ext4 builtin on my distro, but I'm doing modinfo ./ext4.ko for a kernel I'm developing for another system. Previously it would notice that mod got constructed from a module and use that as filename. Here you'd wrongly report that it is builtin.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Valid point - dropped for now.

As a whole, a few functions rely on parsing /sys/modules and friends even when a different kernel version is explicitly provided to kmod_ctx_new. The current behaviour seems suboptimal/buggy.

IMHO we should probably error out, although I could be missing something?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Somewhat related:

It looks like we have different filename (path really) in database vs filesystem... without ever flagging it as an issue. Observed this while copying/adding more modinfo tests. To make it more interesting, setup-rootfs.sh manually changes the path in .dep files but not in .dep.bin and co.

One possible (perhaps overly comprehensive) solution is:

  • have the proper depmod artefacts checked-in
  • on test prep, re-generate ^^ into a throwaway location and error on miss-match
  • ensure correct path is used across .dep/.dep.bin/etc - might need a patch to libkmod/depmod/
  • on test closure, flag files with unchanged atime - ignoring the depmod regen/check

What do you think?

Comment thread tools/modinfo.c Outdated
@evelikov
evelikov force-pushed the modinfo-rework branch 2 times, most recently from 3978b74 to a20e6ab Compare August 2, 2026 12:46
@evelikov

evelikov commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator Author

v3:

  • scope variable declaration

  • code dedup in parm/parmtype paths

  • use correct counter

  • avoid allocations on 0 parm(s)

  • remove param::{desc,type}len

  • move parm* len validation further up the call stack

  • make strbuf_reserve_extra public again + reintroduce tests

  • fix overflow in ^^

  • use ALIGN in ^^

  • remove strbuf_init -

Comment thread tools/modinfo.c Outdated
Comment thread libkmod/libkmod-builtin.c Outdated
uaddsz_overflow(strbuf_used(buf), vec_size, &total_size))
return NULL;

/* XXX: Do not handle bytes behind the object's back */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

and we had strbuf_steal() for this kind of situation that got removed. IMO let's not drop these helpers if they may be used in future?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looking at the PR that removed it:

  • there is one overflow bug (fixed in this PR)
  • the function comment/description didn't get updated
  • the above workaround was pre-existing

Can reintroduce and fix ^^ as a follow up PR.

Would you be OK with dropping "strbuf_init` or prefer to keep it - I don't mind either way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can reintroduce and fix ^^ as a follow up PR.

sounds good

Would you be OK with dropping "strbuf_init` or prefer to keep it - I don't mind either way.

we can drop the callers from the codebase, but let's keep it in the more-or-less-self-contained strbuf implementation. I'll push an update here before merging.

As a followup I think it's also reasonable to move strbuf_to_vector() to be in strbuf.c so the re-init happens inside the strbuf implementation. Then we document that sbuf becomes invalid afte the call.

Comment thread tools/modinfo.c
Comment thread shared/macro.h Outdated
Comment thread tools/modinfo.c Outdated
@lucasdemarchi

Copy link
Copy Markdown
Contributor

Also getting this:

=================================================================
==195428==ERROR: AddressSanitizer: attempting double-free on 0x6e5cad5e03c0 in thread T0:
    #0 0x712caf32a3ff in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:51
    #1 0x64011a76b0f4 in modinfo_do ../tools/modinfo.c:109

Since it's now using DECLARE_STRBUF_WITH_STACK(), we need to remove the strbuf_release() at the end.

Added 2 fixup commits to handle the comments.

@evelikov

evelikov commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Added 2 fixup commits to handle the comments.

The two extra fixups look good to me. Thanks o/

@lucasdemarchi

Copy link
Copy Markdown
Contributor

double checking this commit:

  • modinfo: omit param::desc == NULL case

"printf("%.s", 0, NULL) is a perfectly valid use."

it actually isn't. Passing NULL here is undefined behavior regardless of the precision specifier. In the end this code was converted to strbuf so we don't need it. I will simply drop the commit and solve the conflicts.

@evelikov

evelikov commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

double checking this commit:

* modinfo: omit param::desc == NULL case

"printf("%.s", 0, NULL) is a perfectly valid use."

it actually isn't. Passing NULL here is undefined behavior regardless of the precision specifier. In the end this code was converted to strbuf so we don't need it. I will simply drop the commit and solve the conflicts.

May I ask where did you spot that?

The man page suggests that up-to precision specifier characters of the string are accessed/printed. Plus the undefined sanitizer included in gcc (16.1.1 20260725) doesn't complain either.

Either way, thanks o/

@lucasdemarchi

Copy link
Copy Markdown
Contributor

There's some discussion here about that part of the standard: https://stackoverflow.com/questions/70499706/is-it-guaranteed-by-the-c-standard-to-be-safe-to-do-printf-s-0-null

@lucasdemarchi
lucasdemarchi force-pushed the modinfo-rework branch 3 times, most recently from 20881c8 to 67c2ae8 Compare August 5, 2026 15:53
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
The generic (full) expression is:
 - "$name:$parm ($type)"

Although currently, if no $parm is available and --field isn't used we
instead print:
 - "$name:$type"

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
Currently we assume that the module is built-in if
kmod_module_get_path() returns NULL... Which isn't quite true, since it
can fail for a range of reasons.

Use kmod_module_get_initstate() instead, which will incur in an extra
open("/sys/module/.../initstate") + read() for non built-in modules.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
Specially crafted/corrupt modules may have a parm/parmtype entry which
lacks the "name:" prefix. Throw a warning and skip such entries.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
The respective strings are guaranteed to be nil terminated, so drop the
strlen() and respective len(th) fields.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
Currently, we if we fail to find a name, description or type in the
value token we emit an error and continue.

At the same time, if the name is longer than INT_MAX we error out.
Move the validation (overall strlen(value), which includes namelen)
further up the call stack and make it a non-fatal.

This allows us to garbage collect the no longer reachable error paths
around {add,process}_param().

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
lucasdemarchi pushed a commit that referenced this pull request Aug 6, 2026
This gets Valgrind on my Arch box to be 100% "leak-free" ;-)

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: #451
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
@lucasdemarchi

Copy link
Copy Markdown
Contributor

Applied, thanks

@evelikov

evelikov commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

It seems like v2 got merged, including the UB printf("%.s", 0, NULL) piece.

I'm assuming that's by mistake - will send an update PR tomorrow/day after, with all of your comments addressed.

@lucasdemarchi

Copy link
Copy Markdown
Contributor

ugh... sorry. That's what I get for working in 2 different computers :-/.

@lucasdemarchi

Copy link
Copy Markdown
Contributor

I removed the commits from the master branch and will re-add once I get my other computer back. Sorry about that.

@lucasdemarchi lucasdemarchi reopened this Aug 6, 2026
evelikov added 18 commits August 6, 2026 18:08
The generic (full) expression is:
 - "$name:$parm ($type)"

Although currently, if no $parm is available and --field isn't used we
instead print:
 - "$name:$type"

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Specially crafted/corrupt modules may have a parm/parmtype entry which
lacks the "name:" prefix. Throw a warning and skip such entries.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
The field provides end-user description what the parameter is used for.
Rename it accordingly.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Store the `parm` vs `parmtype` instance as an enum, saving another
streq() shortly afterwards.

There's no practical benefit apart from making the code a tiny bit
clearer IMHO.

v2: Change enum names

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Thus using the correct format when `--null` is specified. In particular,
the both name + filename use the correct format, when --null (mode) is
requested.

v2:
 - call kmod_module_get_name() as needed

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
No point in continuing if only a certain field is requested.

While in here, use a consistent code-pattern for the process.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Add a couple of booleans to arguably make the code a wee-bit cleaner
to follow. A follow-up commit will further reuse the latter (print_parm)
to avoid repeatedly calling streq().

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Earlier commit reworked so we always allocate space for the \0 byte.
Although it did not (fully) consider that it can be the reason for an
overflow.

Cc: Tobias Stoeckmann <tobias@stoeckmann.org>
Fixes: 2b47598 ("shared: let strbuf_str never fail")
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
The only caller of buf_realloc() already ensues that the size is 1 or
more so let's drop the if statement.

Cc: Tobias Stoeckmann <tobias@stoeckmann.org>
Fixes: 2b47598 ("shared: let strbuf_str never fail")
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Introduce the simple macro and use it to (better) illustrate the strbuf
size calculation.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
We'll need the function shortly, so make it public (within kmod).
In the process, re-introduce the test with some changes:
 - cosmetics - test function signature, new test macros, DECLARE_*
 - do not request an extra byte for \0
 - check both ::size and ::bytes

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
_cleanup_strbuf_ + strbuf_init() can be replaced by DECLARE_STRBUF.
Make all call-sites to use the respective macro.

The one place still calling strbuf_init() in strbuf_to_vector()
is "documenting" that strbuf is invalidated after its data is stolen,
so keep it as is for now.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
Currently, we grow a list of parm entries and print each entry upon
being added. In addition, we have two separate code-paths for printing
depending if "--field parm" was provided on not.

Swap that for sufficiently sized, pre-allocated, buffers and unify the
print paths. Effectively fixing the broken `modinfo -0 modulename`
output.

v2:
 - find matching or empty entry in a single loop (add_param)
 - match up-to UINT_MAX parm/parmtype entries
 - drop unneeded INT_MAX checks for strlen(value)
 - don't return success if we fail to [cm]alloc

v3:
 - scope variable declaration
 - code dedup in parm/parmtype paths
 - use correct counter
 - avoid allocations on 0 parm(s)
 - (re)use strbuf

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
The respective strings are guaranteed to be nil terminated, so drop the
strlen() and respective len(th) fields.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Currently, we if we fail to find a name, description or type in the
value token we emit an error and continue.

At the same time, if the name is longer than INT_MAX we error out.
Move the validation (overall strlen(value), which includes namelen)
further up the call stack and make it a non-fatal.

This allows us to garbage collect the no longer reachable error paths
around {add,process}_param().

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
This gets Valgrind on my Arch box to be 100% "leak-free" ;-)

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
The `caf` originates from the manual tar caf invocation, as part of the
(now defunct) autotools build.

Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
@lucasdemarchi

Copy link
Copy Markdown
Contributor

Ok, now it's hopefully the right branch pushed here. @evelikov can you double check?

@evelikov

evelikov commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

I removed the commits from the master branch and will re-add once I get my other computer back. Sorry about that.

No problem - sh*t happens. Would prefer if we don't rewrite the branch history but revert/fixup instead. The former erodes the distro maintainers' trust, et al.

The updated branch looks great. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

modinfo uses mixed delimiters in --null mode

4 participants