Skip to content

Add whitelist feature - #449

Open
paulmenzel wants to merge 10 commits into
kmod-project:masterfrom
paulmenzel:add-whitelist-feature
Open

Add whitelist feature#449
paulmenzel wants to merge 10 commits into
kmod-project:masterfrom
paulmenzel:add-whitelist-feature

Conversation

@paulmenzel

Copy link
Copy Markdown

Resolves: #444

buczek added 2 commits July 16, 2026 14:59
Resolves: kmod-project#444
Signed-off-by: Donald Buczek <buczek@molgen.mpg.de>
Add a "whitelist-test-mode" directive to /etc/kmod/whitelist.conf.
When active, modules are checked against the whitelist but always
permitted to load; any module that would have been denied is logged
via syslog(LOG_NOTICE) to allow auditing before enforcement.

Signed-off-by: Donald Buczek <buczek@molgen.mpg.de>
@paulmenzel

Copy link
Copy Markdown
Author

\cc @sathieu, @buczek

@evelikov

Copy link
Copy Markdown
Collaborator

Hi @paulmenzel a few high-level notes:

  • change needs to be properly integrated with kmod and the "out of tree" note effectively resolved
  • the interaction with soft and weak modules needs to be spelled out
  • the manual page need to be updated
  • test coverage is needed for the new feature

The above might be a bit more work than updating the original patch linked in the issue. Although it is doable - just wondering if it will save you some time.

Out of curiosity: is there any public reference (mailing list, bugzilla, PR, etc) where the original author submitted the change? If so, please add it as a Link: trailer.

Thanks o/

@buczek

buczek commented Jul 29, 2026

Copy link
Copy Markdown

Hi @paulmenzel a few high-level notes:

  • change needs to be properly integrated with kmod and the "out of tree" note effectively resolved
  • the interaction with soft and weak modules needs to be spelled out
  • the manual page need to be updated
  • test coverage is needed for the new feature

The above might be a bit more work than updating the original patch linked in the issue. Although it is doable - just wondering if it will save you some time.

We could certainly implement all of this and prepare the changes properly for integration into upstream. I'd just like to know beforehand whether the feature would be welcome in principle. It would be a waste to invest time in it if it isn't going to be merged in the end. I was surprised that such an obvious feature doesn't exist, so I'm concerned that there might be fundamental objections to it.

Out of curiosity: is there any public reference (mailing list, bugzilla, PR, etc) where the original author submitted the change? If so, please add it as a Link: trailer.

Original author here.

This was initially intended for our internal distribution only. Accordingly, there was no public discussion.

Here is the original history:

Best
Donald

Thanks o/

@lucasdemarchi

Copy link
Copy Markdown
Contributor

We could certainly implement all of this and prepare the changes properly for integration into upstream. I'd just like to know beforehand whether the feature would be welcome in principle. It would be a waste to invest time in it if it isn't going to be merged in the end. I was surprised that such an obvious feature doesn't exist, so I'm concerned that there might be fundamental objections to it.

I don't think there's a fundamental objection. It makes sense IMO. I was thinking that maybe it would make more sense in the kernel instead of kmod.... but after reading the PRs you linke it seems more a sysadmin conf, so userspace should be ok.

@evelikov

evelikov commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Same here - as mentioned in the issue, I am in favour.

One question that immediately comes to mind is should the whitelist be exposed via likmod similar to the original patch or not? Would love to see some arguments why/why not from the authors.

buczek added 8 commits August 4, 2026 11:33
Add storage for the whitelist config directives (a module-name list
plus active/test-mode flags) to struct kmod_config, mirroring the
existing blacklists field. Nothing populates or reads these fields
yet; this only prepares kmod_config_free() to release the list.
Recognise "whitelist <modname>", "whitelist-enable" and
"whitelist-test-mode" as modprobe.d directives, mirroring the
existing "blacklist" directive: kmod_config_add_whitelist() appends
entries to config->whitelists, the two bare keywords set the
active/test-mode flags. Populated fields are not consumed anywhere
yet, so this has no runtime effect.
Mirrors kmod_blacklist_get_modname(): retrieves the module name
stored in a config->whitelists list node. Unused for now.
Add module_is_whitelisted(), mirroring module_is_blacklisted(), and
module_whitelist_check() which applies the active/test-mode flags
from struct kmod_config. Wire it into
kmod_module_probe_insert_module() in place of the old
whitelist_allowed() call, which read a separate, out-of-tree
/etc/kmod/whitelist.conf.

Enforcement is now driven entirely by the "whitelist",
"whitelist-enable" and "whitelist-test-mode" directives parsed from
modprobe.d config files. The old whitelist_allowed() is unreferenced
outside libkmod-whitelist.c after this change; that file and its
forward declaration are removed next.

Test-mode and denial notices move from raw syslog() calls to the
ctx-based NOTICE() logging macro, consistent with the rest of
libkmod.
Its whitelist_allowed() has been unreferenced since
kmod_module_probe_insert_module() switched to the config-based
module_whitelist_check(). Drop the file, its meson.build entry, and
the stale forward declaration.
Exercise the whitelist enforcement path end to end through the
modprobe binary, mirroring the existing modprobe fixture/test
conventions (based on the "oldkernel" fixture):

 - whitelist_inactive: no whitelist directives -> module loads
 - whitelist_deny_all: whitelist-enable with no entries -> denied
 - whitelist_allowed: whitelist-enable + a hyphenated entry -> loads,
   also pinning the dash/underscore normalisation behaviour
 - whitelist_test_mode: whitelist-enable + whitelist-test-mode with
   the module unlisted -> still loads

scripts/setup-rootfs.sh gets three new map entries so the fixtures
that expect a successful load have a real mod-simple.ko installed,
same as every other module-loading test fixture.
Add COMMANDS entries for the three new modprobe.d directives, next
to the existing blacklist/softdep/weakdep entries.
The public API doc for this function still only mentioned blacklist
after it gained whitelist enforcement. No symbol or signature
changed, so no ABI/API-surface update is needed, but the gtk-doc
comment (source of the generated libkmod-3 reference) was stale.
@buczek

buczek commented Aug 4, 2026

Copy link
Copy Markdown

@paulmenzel: I've added commits on top of your PR branch which mangles it into something better integrated into upstream. Can you pull it from add-whitelist-feature and push it here or give me write access to your repository/branch so that I can push to it. I think we should keep the discussion/changes in this PR.

The commits are RFC and probably need to be rebased at a later time. Maybe the maintainers here don't want to pollute their history with the diversion over our out-of-tree code evolving into something else and would prefer commits which go directly from their master to the end result. Anyway, we can rebase/rewrite to whatever is wanted later.

Also I'm not happy with the logging yet: The specific "not in whitelist" message are probably lost in many environments because of log level LOG_NOTICE and unspecific messages ("could not insert %: EPERM") from modprobe are not really self-explanatory. Upgrading LOG_NOTICE to LOG_ERROR would emit two messages per denied module, which is ugly.

I think some basics concepts still need to be discussed, though: In the code change, whitelists are built to match blacklists. But this means, that only toplevel modules are checked, dependencies are not. There is KMOD_PROBE_APPLY_BLACKLIST_ALL but it looks like it is not used by modprobe. We want to use whitelists as a feature to reduce attack surface and I would say, that it would be safer if all modules would need to be whitelisted explicitly, not just the toplevel module requested by the kernel. But if whitelists don't semantically match blacklists, the functions would be more difficult to explain and understand.

@evelikov , I think I addressed your points in the new commits. I just wasn't sure about "the interaction with soft and weak modules needs to be spelled out". I think hard and soft dependencies are handled the same (maybe wrong, see above) and "weak" dependencies are out of scope. As far as I understand it (but I may by wrong, we don't use that), weak dependency are only used by external tooling, e.g. to decide what goes into a initramfs? When the modules are actually used at a later time, black/whitelists would apply.

@paulmenzel

Copy link
Copy Markdown
Author

@paulmenzel: I've added commits on top of your PR branch which mangles it into something better integrated into upstream. Can you pull it from add-whitelist-feature and push it here or give me write access to your repository/branch so that I can push to it. I think we should keep the discussion/changes in this PR.

@buczek, awesome that you found time to wok on this.I pushed your changes, and invited you as a collaborator.

@buczek

buczek commented Aug 4, 2026

Copy link
Copy Markdown

AI assistance disclosure: Portions of this patch series (implementation, tests, and documentation) were drafted with AI assistance under my direction and review. All design decisions, verification, and final review were performed by me.

@evelikov

evelikov commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Don't have a strong opinion on the LLM/AI use and in this case there is nothing ground breaking that would warrant licensing and/or other concerns, IMHO.

Would be great if @lucas can put together some rough notes in our contributing guide, for posterity sake.

Glancing through the patches (proper review will come in a few days), they all seem ok. Some questions come to mind:

  • some duplication wrt the "blacklist" equivalents - should be able to flesh out and reuse some helpers
  • what is the current means of obtaining the complete list - set flag, reboot, plug all devices, grep the logs? can we do something easier via say modprobe or depmod
  • if we stick with the original ^^ approach, can we merge whitelist-enable and whitelist-test-mode one - a tristate whitelist -> enable disable test
  • wrt the module interactions (hard, soft and/or weak), have you considered:
    • what should be reported if a required module is loaded, prior to having the "test-mode" enabled? eg. early initrd without the config
    • should all dependencies be tracked - including soft & weak ones?
    • how can admins ensure the list is complete? eg. is it uncommon/not allowed for a person to come with their own keyboard/mouse and expect it to work?

I suspect some of these might be covered in the patches already. If so, feel free to ignore ;-)

@lucasdemarchi

Copy link
Copy Markdown
Contributor

Don't have a strong opinion on the LLM/AI use and in this case there is nothing ground breaking that would warrant licensing and/or other concerns, IMHO.

Would be great if @lucas can put together some rough notes in our contributing guide, for posterity sake.

I guess you referred to me, even though that's not my @ handle :)

"AI is a tool, just like other tools we use. And it's clearly a useful one." - https://lore.kernel.org/linux-media/CAHk-=wi4zC+Ze8e+p3tMv8TtG_80KzsZ1syL9anBtmEh5Z40vg@mail.gmail.com/

@buczek

buczek commented Aug 7, 2026

Copy link
Copy Markdown
* some duplication wrt the "blacklist" equivalents - should be able to flesh out and reuse some helpers

Yes, the whitelist helpers are direct copies of the blacklist helpers and I've considered deduplication. In the end I decided to avoid changing existing code at this stage. Deduplication can be done with simple and easy to verify separate patches on top of these changes, either in this PR or independently. It's only a minor source code style issue, I guess the compiler would inline the short static functions anyway, thereby removing a "list" argument and using the caller's constants directly.

Someone just needs to tell me whether I should do it right away.

* what is the current means of obtaining the complete list - set flag, reboot, plug all devices, grep the logs? can we do something easier via say `modprobe` or `depmod`

We used "lsmod" across all our live machines and created a whitelist for our fleet from that. Then we let it run a few days in "test mode" to see if anything not yet covered is sometimes plugged in dynamically. Then we enabled it. Sysadmins need to be aware of it, because that can be relevant when new hardware is provisioned or kernel is updated. For that reason, a reliable and understandable log is important, see my note about that. In the out-of-tree variant we used syslog() with specific messages but this has been changed now to libkmod standard and I don't even know how other distributions configure their logs.

* if we stick with the original ^^ approach, can we merge `whitelist-enable` and `whitelist-test-mode` one - a tristate `whitelist` -> `enable` `disable` `test`

Yes, of course. Can someone decide, please?

* wrt the module interactions (hard, soft and/or weak), have you considered:
  
  * what should be reported if a required module is loaded, prior to having the "test-mode" enabled? eg. early initrd without the config

Hmmm. I wouldn't use whitelists in initrd at all. Our usage is kind of a lockdown mode. "no new modules without explicit approval". This is to prevent unprivileged attack code from triggering autoload of kernel modules with vulnerabilities.

  * should all dependencies be tracked - including soft & weak ones?

The lists don't apply to hard dependencies and I regard weak dependencies as out of scope (see my previous reply). The lists do apply to soft dependencies, though, because these are separately requested by the kernel (edit: The lists don't apply to soft dependencies). This is the current state with blacklists and the proposed whitelists follow along. Please correct me if I am wrong.

For us, that would definitely be fine. Is somebody requesting a change?

  * how can admins ensure the list is complete? eg. is it uncommon/not allowed for a person to come with their own keyboard/mouse and expect it to work?

I can only answer for our environment: No, they are not expected to connect their own hardware. Nevertheless most simple hardware like keyboards/mice works with the generic drivers which are already available. If they connect something which would require a new kernel module to be loaded, that would fail and the user would contact our helpdesk for assistance. This is a good thing, because we can review what the user is trying to do and either allow it or otherwise assist in resolving the underlying problem in a correct way.

I think a fleet of multi-user systems is uncommon nowadays. But a security-aware self-admin might use "lsmod" on his notebook and generate a whitelist from that with the same intent.

I suspect some of these might be covered in the patches already. If so, feel free to ignore ;-)

Thanks for your thoughts!

@buczek

buczek commented Aug 7, 2026

Copy link
Copy Markdown

Should we copy the KMOD_PROBE_APPLY_BLACKLIST* API for whitelist? I hesitate, because its somehow strange with KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY defaulted in modprobe.c.

@q1sh101

q1sh101 commented Aug 8, 2026

Copy link
Copy Markdown

On the soft dependency question, measured on kmod 34.2 in an isolated config dir so it reproduces anywhere:

d=$(mktemp -d)
printf 'softdep xfs pre: e1000e\ninstall e1000e /bin/false\n' > "$d/t.conf"
modprobe -C "$d" -n -v xfs

For a module reached through a softdep, the two deny mechanisms behave differently. An install command on e1000e is applied and the plan shows install /bin/false. A blacklist e1000e line is not, and e1000e is inserted anyway. So blacklist does not apply to soft dependencies, but install does.

The other direction is less obvious. If the requested module itself declares a pre: or post: softdep, its own install command is dropped and it is inserted directly:

printf 'install xfs /bin/false\nsoftdep xfs pre: e1000e\n' > "$d/t.conf"
modprobe -C "$d" -n -v xfs

This follows mod->ignorecmd = (pre != NULL || post != NULL) in __kmod_module_fill_softdep(), and modprobe.d(5) notes that softdep takes precedence over install. A softdep line with neither pre: nor post: leaves the command intact.

I cannot say much about weakdep. modules.weakdep is empty on this kernel, so I could only exercise the config directive, where the command is applied.

Since the two directions differ, it would help to state which one whitelist follows, in particular whether a pre:/post: softdep can pull in a module that whitelist-enable does not permit.

@evelikov evelikov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Was LLM/AI also used to replying to the review questions? They seems overly verbose and somewhat cautions not to make a statement.

Eg.

Yes, the whitelist helpers are direct copies of the blacklist helpers and I've considered deduplication. In the end I decided to avoid changing existing code at this stage. Deduplication can be done with simple and easy to verify separate patches on top of these changes, either in this PR or independently. It's only a minor source code style issue, I guess the compiler would inline the short static functions anyway, thereby removing a "list" argument and using the caller's constants directly.

Someone just needs to tell me whether I should do it right away.

Is usually I've considered it, but decided against for now. Can fixup or send a follow-up PR if people prefer

Let me see if I understood correctly, the usual/recommended workflow is:

  • construct a list from lsmod - PR should include a patch to make that process easier
  • enable test mode, gather logs/data, analyse and amend whitelist config - love the use of NOTICE (we don't use it yet), but we could use a phrase (like the original patch) to make process easier
  • no whitelisting - active or test-mode is present in initrd
  • for any issues - driver not loading, need keyboard, etc - sysadmin is involved

Overall I like the idea, although it brings a few questions - not relevant for kmod, but something to consider potentially in your org/setup.

  • does the initrd contain full-blown kernel module set - aka people can bypass the whitelist all together, the module isn't listed during test-mode phase.
  • in case of keyboard failures (infamous coffee spills), is the recovery process "remove the storage drive" (think soldered ssd/nvme) or there are sufficient backup devices

Wrt weak dependencies - they cannot be out of scope. The way they work is:

  • kernel module calls request_module(foobar), kernel executes modprobe -q -- foobar
  • kernel module adds MODULE_WEAKDEP blurb, to alert userspace - eg. make sure the module is available in initrd/rootfs

So as a whole, I think we don't want/care about the dependency type - hard/soft/weak/etc. Similarly, I don't see the point in adding KMOD_PROBE_APPLY_ - if anything, that would defeat the purpose of the option.

That said, I don't mind being proven wrong 😄

Left a few small inline comments. Let's rebase & squash this up (1-2 patches) and pump the commit message to include, some brief about:

  • the why
  • how-to-use recommendation

Comment thread libkmod/libkmod-module.c

if (config->whitelist_test_mode) {
NOTICE(mod->ctx,
"module '%s' would be denied (test mode active, load permitted)\n",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's have a clear/unique prefix like the original patch. Eg. whitelist: module %s....

Here and throughout.

Comment thread libkmod/libkmod-module.c

if (!module_whitelist_check(mod))
return -EPERM;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Curious about the train of thought here - do we want the check prior to any of the others - already_loaded, blacklist - or why not?

Comment thread man/modprobe.d.5.scd
Adds _modulename_ to the whitelist of modules that are permitted to
load. This command only has an effect once *whitelist-enable* is
also given (in this or any other configuration file); by itself, a
*whitelist* entry is parsed but has no effect.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not strictly related to this PR: Ideally we would have a way to validate the modulename(s) listed in the config. Think typos, people accidentally adding multiple on the same line (space, comma, other-separated), etc.

None of this is a blocker for this feature, but if you feel like sending separate PR that would be really appreciated.

.config = {
[TC_UNAME_R] = "3.3.3",
[TC_ROOTFS] = TESTSUITE_ROOTFS "test-whitelist/deny-all",
[TC_INIT_MODULE_RETCODES] = "",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we need the empty TC_INIT_MODULE_RETCODES here?

[TC_ROOTFS] = TESTSUITE_ROOTFS "test-whitelist/deny-all",
[TC_INIT_MODULE_RETCODES] = "",
},
.expected_fail = true,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not related to your work: we should get a exit-status field, since expected_fail effectively masks any failure - crash, sanitizers, etc.

Comment thread man/modprobe.d.5.scd
modules are denied. If *whitelist-enable* is given but no
*whitelist* entries exist, every module is denied. Without
*whitelist-enable*, no whitelist is enforced regardless of any
*whitelist* entries present, and all modules may load as usual.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's shorten this up a bit - my somewhat ADHD brain stopped reading past "configuration file" the first time.

Enables whitelist enforcement, where only modules listed via
*whitelist* commands are permitted to load, and all other
modules are denied.

@buczek

buczek commented Aug 8, 2026

Copy link
Copy Markdown

Was LLM/AI also used to replying to the review questions? They seems overly verbose and somewhat cautions not to make a statement.
[...]

It was not. Natural and limited intelligence and sorry for being too verbose. I used AI as a spell checker, though, because I tend to make a lot of typos, use wrong wording and overlook careless mistakes after editing my text over and over. https://claude.ai/share/7f18f71d-8fdc-43ea-9335-2bdbcf5e46ee

Let me see if I understood correctly, the usual/recommended workflow is:

* construct a list from lsmod - PR should include a patch to make that process easier
* enable test mode, gather logs/data, analyse and amend whitelist config - love the use of NOTICE (we don't use it yet), but we could use a phrase (like the original patch) to make process easier
* no whitelisting - active or test-mode is present in initrd
* for any issues - driver not loading, need keyboard, etc - sysadmin is involved

This is just what we did. Not sure if that is the way to go in other environments.

Overall I like the idea, although it brings a few questions - not relevant for kmod, but something to consider potentially in your org/setup.

* does the initrd contain full-blown kernel module set - aka people can bypass the whitelist all together, the module isn't listed during test-mode phase.

Our initrd doesn't contain any dynamic kernel modules or kmod. All modules required to read the root filesystem are static. So people can't bypass the whitelist by having hardware plugged in during boot. When the system switches to the real rootfs, which provides dynamic kernel modules, the whitelist configuration is there at the same time.

* in case of keyboard failures (infamous coffee spills), is the recovery process "remove the storage drive" (think soldered ssd/nvme) or there are sufficient backup devices

Sorry, I don't get that scenario.

Wrt weak dependencies - they cannot be out of scope. The way they work is:

* kernel module calls `request_module(foobar)`, kernel executes `modprobe -q -- foobar`
* kernel module adds `MODULE_WEAKDEP` blurb, to alert userspace  - eg. make sure the module is available in initrd/rootfs

So as a whole, I think we don't want/care about the dependency type - hard/soft/weak/etc. Similarly, I don't see the point in adding KMOD_PROBE_APPLY_ - if anything, that would defeat the purpose of the option.

Okay, thanks for the opinion. I need that, because we never managed dependencies manually so I have no experience on my own with all that. We just configure our kernels with a lot of dynamic modules so that we don't need to compile a new kernel or reboot when we want to play with a new feature, then make modules_install. Aside from a few modules which had security problems and were blacklisted before we had the whitelist feature and a few options for some modules, our modprobe.d has nothing. I had to look up "soft" and "hard" and "weak" dependencies when it was mentioned here.

That said, I don't mind being proven wrong 😄

Left a few small inline comments.

Let's rebase & squash this up (1-2 patches) and pump the commit message to include, some brief about:

* the why

* how-to-use recommendation

Thanks! I will look into your comments and rebase. I hope I find time next week. Can't promise, tough.

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.

Whitelist support

5 participants