[RFC PATCH 0/9] Introducing the Loadpol LSM
Simon THOBY
git at nightmared.fr
Wed May 21 14:01:04 UTC 2025
This RFC patch series aims at discussing the interest of a mechanism
that could restrict which modules are loaded at runtime.
Motivation
==========
In my experience, there is three main classes of kernel users.
On the one hand, some entities (companies or individuals) determine the exact set
of features they need, and recompile the kernel to match these needs (this is true
e.g. of cloud vendors, many security products, appliances, etc.). These users
can finely choose which kernel modules are available on their kernels, because
they know beforehand the exact use case, and they (mostly) control the software
and hardware stack.
On the other end of that spectrum, many entities use off-the-shelf distributions
with little to no further hardening (I believe this is the case of >90% of companies).
They don't really care about the presence of modules they may not need,
so all is well.
Finally, somewhere in the middle there are entitites that want to have some
control over what kernel modules are allowed on a system, but without the bandwith
of building and distributing internally their own kernel (because it would require
a dedicated team to keep ahead of the frequent updates, and because the added
value of that team is hard to justify). These entities will often use
off-the-shelf distributions, but they often miss the appropriate knobs to
be able to tweak the system in order to reach their desired security
level. In the particular case of kernel modules, Linux is very binary on
that point: either you allow the loading of any signed kernel module
(kernel.modules_disabled=0) or you completely disallow the loading of modules
(kernel.modules_disabled=1).
Note: there is also secure_insmod for SELinux, but it is a binary option too.
However these users do not want to trust all the kernel modules present
in the distribution packages (to reduce the attack surface, and/or for compliance
reasons).
They want to collate a list of kernel modules required to support their hardware
and software needs, and then to distribute a policy allowing these exact modules,
and blocking the rest.
One big example that comes to my mind is security software, because these finicky
beasts often come with a kernel module that can only be loaded once the
corresponding userland part has started, so very late in the boot process.
In addition, this type of module must be unloaded/reloaded when performing updates.
This is why loading all these modules at boot and then disabling the load of
further modules (via the kernel.modules_disabled sysctl) is not
sufficient.
Implementation
==============
This patch RFC builds a small LSM that can be configured at runtime (in
a practical setup, it would be loaded inside the - signed and verified -
initramfs), and locked to disallow further modifications of the policy.
This is loosely based on the policy mechanism of the IMA subsystem,
which was a great source of inspiration.
A new LSM hook is introduced to decide on a module load if the module
should be allowed or not). When called, the LSM iterates over its policy
and allow the module if a match associated with the ALLOW action is found.
A securityfs file is created to read the policy (using `seq_file` iterators) and update it.
The policy itself is very simple (two keywords to match modules, one
keyword to determine the action to take, and that's about it).
Finally, a sysctl entry exists to lock the policy in its current state.
Questions
=========
Do you believe that such a mechanism would be valuable?
And if not, do you have an idea of alternatives that users could combine to
achieve the same results?
On an implementation detail, to determine if a module load request comes from
the kernel (instead of a user-initiated load), I currently do something
like `if (current->parent->flags & PF_WQ_WORKER))`. Is that a proper way
to determine that the current load is the consequence of a call to
`request_module`, and is that not overly broad (could this match
requests that are - in the end - user-initiated)?
Thank you for your consideration,
Have a nice day,
Simon
Simon THOBY (9):
LSM: Introduce a new hook: security_kernel_module_load
Introduce a new LSM: loadpol
Loadpol LSM: filter kernel module request according to the policy
Loadpol LSM: add a file in securityfs to read/modify the policy
Loadpol LSM: add a sysctl to lock the policy
Loadpol LSM: emit an audit log
module: expose the list of blacklisted modules
Loadpol LSM: include the blacklisted kernel modules in the policy
Loadpol LSM: add a minimal documentation
Documentation/admin-guide/LSM/Loadpol.rst | 81 ++++++
Documentation/admin-guide/LSM/index.rst | 1 +
include/linux/lsm_count.h | 7 +
include/linux/lsm_hook_defs.h | 1 +
include/linux/module.h | 4 +
include/linux/security.h | 6 +
include/uapi/linux/audit.h | 1 +
include/uapi/linux/lsm.h | 1 +
kernel/module/main.c | 9 +
security/Kconfig | 1 +
security/Makefile | 1 +
security/loadpol/Kconfig | 12 +
security/loadpol/Makefile | 1 +
security/loadpol/loadpol.c | 76 ++++++
security/loadpol/loadpol.h | 43 +++
security/loadpol/loadpol_fs.c | 139 ++++++++++
security/loadpol/loadpol_policy.c | 311 ++++++++++++++++++++++
security/security.c | 14 +
18 files changed, 709 insertions(+)
create mode 100644 Documentation/admin-guide/LSM/Loadpol.rst
create mode 100644 security/loadpol/Kconfig
create mode 100644 security/loadpol/Makefile
create mode 100644 security/loadpol/loadpol.c
create mode 100644 security/loadpol/loadpol.h
create mode 100644 security/loadpol/loadpol_fs.c
create mode 100644 security/loadpol/loadpol_policy.c
--
2.49.0
More information about the Linux-security-module-archive
mailing list