Add whitelist feature - #449
Conversation
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>
|
Hi @paulmenzel a few high-level notes:
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 Thanks o/ |
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.
Original author here. This was initially intended for our internal distribution only. Accordingly, there was no public discussion. Here is the original history:
Best
|
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. |
|
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. |
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.
|
@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 @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. |
@buczek, awesome that you found time to wok on this.I pushed your changes, and invited you as a collaborator. |
|
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. |
|
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:
I suspect some of these might be covered in the patches already. If so, feel free to ignore ;-) |
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/ |
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.
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.
Yes, of course. Can someone decide, please?
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.
The lists don't apply to hard dependencies and I regard weak dependencies as out of scope (see my previous reply). For us, that would definitely be fine. Is somebody requesting a change?
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.
Thanks for your thoughts! |
|
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. |
Resolves: #444