1. Introduction
Linux Kernel modules provide a way to expand the existing kernel functionality without having to rewrite, reconfigure, or recompile the kernel code. While we can use the modprobe tool as provided by the kmod package, there are sometimes additional settings required for a particular module to be loaded.
In this tutorial, we explain how to handle the Operation not permitted error when using modprobe. First, we briefly go over kernel permissions in general. Next, we explore the classic modprobe command. Finally, we turn to fixing a permissions error when loading modules.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments unless otherwise specified.
2. Permissions and the Kernel
The Linux kernel usually resides in the /boot directory. As with other files there, the kernel files owner is root:
$ ls -lh /boot
[...]
-rw-r--r-- 1 root root 333K Apr 04 03:03 config-6.66.0-100-amd64
-rw-r--r-- 1 root root 33M Apr 04 03:03 initrd.img-6.66.0-100-amd64
-rw-r--r-- 1 root root 83 Apr 04 03:03 System.map-6.66.0-100-amd64
-rw-r--r-- 1 root root 6.6M Apr 04 03:03 vmlinuz-6.66.0-100-amd64
Here, ls with its [-l]ong listing format shows us four related files:
- config-* – kernel configuration file
- initrd.img-* – temporary root filesystem
- System.map-* – kernel symbols and addresses
- vmlinuz-* – the current Linux kernel
In fact, root is the only user that has permissions to write to the kernel file.
However, we can see a list of currently loaded kernel modules with a regular user via the /proc/modules file in the /proc pseudo-filesystem or directly with lsmod:
$ lsmod
Module Size Used by
binfmt_misc 24576 1
squashfs 69632 3
loop 40960 6
[...]
On the other hand, we can only load kernel modules as root.
3. modprobe
The main functions of the modprobe tool are loading and unloading kernel modules. The latter mainly resides in /lib/modules/$(uname -r).
3.1. modprobe.d
Notably, the /modprobe.d configuration directory in /lib, /etc, or /run contains module settings files containing different possible commands:
- alias – create alternative module names
- blacklist – ignore given module aliases
- install – replaces a regular module loading with a shell command
- options – add options to a given module
- remove – same as install, but for unloading
- softdep – set optional module dependencies
Each command should be on a separate line. To show the current configuration, we use –showconfig or -c. Moreover, we can specify an alternative configuration path with the –config or -C option.
Since commands can get quite complex, using the –dry-run or -n flag to perform a test of a given operation can be helpful.
3.2. Loading Kernel Modules
To load a module, we just pass its name or alias to the modprobe command:
$ modprobe MODULE
Since loading may require parameters, only one module identifier can be specified. In addition, we can ensure a module isn’t already loaded, and modprobe actually performed an operation by including the –first-time flag.
Moreover, we can load all modules via –all or -a. Finally, we use any of the –force* switches to give modules the best chance to load at a possible stability cost.
3.3. Unloading Kernel Modules
Removing a module should work by just inserting the –remove or -r flag:
$ modprobe --remove MODULE1 [...] MODULEn
In this case, we can specify multiple identifiers in the same command. Still, unloading is rarely done outside of testing, debugging, and troubleshooting. Further, some kernels don’t support the operation.
3.4. Errors
As long as we have module loading and unloading support, the main errors when we try to –remove a module are the self-explanatory Module X is in use or No such module:
$ modprobe --force --remove X
modprobe: FATAL: Module X is in use.
Most other errors have to do with the default modprobe action of loading modules:
$ modprobe X
modprobe: ERROR: could not insert X: Exec format error
Still, there are other common examples, like Invalid module format. Unknown symbol in module or unknown parameter. The rest are standard errno.h errors.
Finally, when using modprobe in a non-interactive session, we can append the –syslog or -s flag to send errors to syslog as a LOG_DAEMON with the LOG_NOTICE priority.
4. Fix modprobe Error Operation not permitted
Initially, getting a permissions issue might imply a lack of privileges. However, this might not be the case with the Operation not permitted error that modprobe sometimes returns:
$ modprobe MODULE
modprobe: ERROR: could not insert 'MODULE': Operation not permitted
In fact, we can use grep to filter the output of dmesg and get a hint to the root cause of this problem:
$ dmesg | grep modprobe
Lockdown: modprobe: Loading of unsigned module is restricted; see man kernel_lockdown.7
As it turns out, kernel lockdown is a feature that prevents unsigned code from loading as part of the kernel facilities. Since this includes modules, trying to load one that isn’t signed produces the problem.
To fix it, we can work around the lockdown via the sysrq mechanism by changing two related values through the /proc pseudo-filesystem:
$ echo 1 > /proc/sys/kernel/sysrq
$ echo x > /proc/sysrq-trigger
Of course, we need superuser privileges to perform both operations. After this, we should be able to load unsigned modules without errors.
5. Summary
In this article, we looked at kernel permissions, the modprobe command, as well as a particular error when trying to load a module.
In conclusion, a permissions issue when using modprobe might not always mean a lack of privileges and can sometimes stem from an internal lockdown, which we can still overcome.