I have a simple kernel object that I built for probing around at kernel memory.
If I build it on my 64-bit Ubuntu (3.2) machine it works fine on that machine. But it won't insmod on my 64-bit Ubuntu (3.9) machine. And vice versa. It gives me a "-1 Invalid module format" error if I try to run it on a Kernel rev other than the one I'd built it on.
I thought insmod linked it dynamically against the exported symbol table and the exported symbol table does not change between kernel revisions. (It gets appended.)
Can someone tell me how I can build a kernel module (.ko) that is compatible with future (or past) Linux kernels without having to be rebuilt on that kernel?
Here's my make file:
ccflags-y = -g
obj-m += access_mem.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Joe, Ubuntu (3.2) maybe using kernel version x.y.z but Ubuntu (3.9) maybe using kernel version x.y.z1. If kernel versions differ you must need to build/compile your driver against that particular kernel version. If the kernel versions are same then no need to build your driver. Important point is that every driver module is been compiled or built linking with version.ko module (which actually embeds the information about the kernel version the driver module built against), while loading kernel module it checks for this information and kernel version, if different then throws "-1 Invalid module format" or if matched then kernel module is loaded successfully. To develop kernel module which is future or backward compatible you need to know on which kernel version which API's or functions signature have been changed for ex: ioctl signature changed from kernel version 2.3.36 onwards, so your code should be as below
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
static long minor_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
static int minor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
#endif
If developed in such a way then your kernel module is future or backward compatible. Compatibility is only adaptation of API's or function signature etc.. changes for the kernel version by preserving the older API's or function signature etc.. in your kernel module as in the above example, but still you need to build/compile your kernel module against the kernel version on which you are trying to load.
I'm not an expert on the subject but I'm pretty sure that you must build your driver against each version of the kernel. As for the symbols staying the same between kernel versions, I'm quite certain that is not true after reading https://www.kernel.org/doc/Documentation/stable_api_nonsense.txt.
Related
On an x86_64 host I have cross-compiled a Linux kernel for an ARM target out-of tree. So I have two directories:
~/kernel_git_repo/ - contains kernel source only
~/kernel_buld_dir/ - contains the .config file and built kernel objects
In a third directory
~/external_module - sources for an external kernel module
I have the source code for an external module, with a Makefile.
The "usual" command for an in-tree built kernel would be:
make -C <path-to-compiled-src-code> M=$(PWD) modules
For my out-of-tree built kernel, neither ~/kernel_git_repo/ nor ~/kernel_buld_dir/ work as <path-to-compiled-src-code>. It appears that the make command needs both the kernel source repo with the Kbuild infrastructure and the build directory with the .config file and the objects.
In this situation, what is the make command to use in the ~/external_module/Makefile for building the module?
You're right, it's essentially the same,
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) modules
except
KDIR=/path/to/kernel/source
I'm using Ubuntu 14.04 LTS and kernel version 3.13.11.4. I'm trying to load patched KVM modules kvm and kvm-intel and I'm getting the following errors
kvm: module verification failed: signature and/or required key missing - tainting kernel
and kvm: module has bad taint, not creating trace events.
The source used is the same source that created the image that I am currently running. I've check the symbols and made sure to the error isn't cause by not including EXPORT_SYMBOL_GPL() in the patched files where I exported functions.
I've also seen some stuff about different kernel versions causing this error but I built the kernel that I'm booted in with the same source that I used to create the patched kvm modules. Everything compile without an warning. Any help is appreciated!
Instead of re-configuring the kernel, this error (module verification failed) could be resolved by just adding one line CONFIG_MODULE_SIG=n to the top of the Makefile for the module itself:
CONFIG_MODULE_SIG=n
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
Go to the kernel source directory and do (for e.g):
./scripts/sign-file sha512 ./signing_key.priv ./signing_key.x509 /lib/modules/3.10.1/kernel/drivers/char/my_module.ko
for kernel 4.4.*, keys location should be as follows:
./scripts/sign-file sha512 ./certs/signing_key.pem ./certs/signing_key.x509 path/to/your/kernel/module.ko
Check what is the digest algorithm your kernel is using by opening .config and reading it in CONFIG_MODULE_SIG config values.
CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_ALL=y CONFIG_MODULE_SIG_SHA512=y CONFIG_MODULE_SIG_HASH="sha512"
It seems like the vendor of your system has enabled kernel module signature verification on your kernel which means it won't load any module that the vendor hasn't signed. In other words, your patched module isn't signed (properly) and the kernel will refuse to load it.
The point of this is supposed to prevent malware and rootkits from loading malicious kernel modules.
I suggest you contact your vendor. There may be an option somewhere on your platform to disable signature checking. Otherwise, your vendor may be able to sign the module for you. You might even have the key and the details of the signature verification algorithm and can sign it yourself.
Without knowing what platform you're running on, it's hard to give more specific suggestions.
In general, if you are building a custom kernel and using make oldconfig. This copies the exiting config-* file from /boot. Now a days most of the kernel modules required to be signed by the linux vendor. So edit the .config and disable CONFIG_MODULE_SIG_ALL and CONFIG_MODULE_SIG, before compiling the kernel.
CONFIG_MODULE_SIG=n
CONFIG_MODULE_SIG_ALL=n
# CONFIG_MODULE_SIG_FORCE is not set
# CONFIG_MODULE_SIG_SHA1 is not set
# CONFIG_MODULE_SIG_SHA224 is not set
# CONFIG_MODULE_SIG_SHA256 is not set
# CONFIG_MODULE_SIG_SHA384 is not set
I am new in kernel programming.
For implementing my project work, I have downloaded the latest stable kernel (v4.3) from kernel.org.
Just for checking I have copied a few files from the kernel directories into my project directory. Made changes to it and inserted a few more code to it.
Then I compiled on SLES11 Linux kernel using
make -C /lib/modules/$(uname -r)/build M=$PWD modules
I have used the below makefile
obj-m := my_module.o
my_module-objs := module_main.0 other_module1.o other_module2.o other_module3.o
It compiled successfully.
But when I tried to insert into the kernel using
insmod my_sample.ko
It showed the following
disagrees about version of symbol symbol_name
You need to build your kernel module against the same version kernel you are going to run. Thus if you have kernel 4.3 sources that you have downloaded you need to compile that version of the kernel and boot with that running before trying to load your kernel.
You have two solutions then:
Download the kernel sources for the kernel you are currently running (you can install those with zypper install kernel-source on SLES or an equivalent command on other distributions.)
Compile and install the 4.3 kernel in to your operating system. If you need help with this then ask a separate question (and it probably belongs on superuser not here). Note that if kernel and glibc are tightly coupled, and it is possible that you can't run a new kernel if you have a very old C library.
The problem here is that your Kernel module is using the exported symbols of other kernel modules which in this case appears to be the linux InfiniBand RDMA stack's exported methods or symbols.
To solve the symbol version problems, copy the Module.symvers file from the
/usr/src/ofa-kernel
directory and paste it to your current working directory. Then you make your modules again. Now the insmod should work perfectly fine.
NOTE: The Module.symvers file contains information of all the kernel
module exported symbol. So by copying it to your working directory,
you are helping kbuild to know more about the used exported symbols.
And if you don't find Module.symvers or it is empty, then create one using create_Module.symvers.sh
make -C /lib/modules/$(uname -r)/build M=$PWD modules,
"$(uname -r)" shows that you are compiling against the kernel version you are running now so you should be able to insmod the module in the current kernel if you haven't changed the headers.
From your text,
"Just for checking I have copied a few files from the kernel directories into my project directory. Made changes to it and inserted a few more code to it."
If you have made modifications to the kernel source then you may need to recompile the new kernel and boot with the new updated kernel. Then you should be able to compile your kernel module with the modified headers.
Looks like you built agAinst right kernel.something to do with how your kernel is compiled. (See Config_conversions). Try --force
I build embedded machines that run an RT_PREMPT version of Linux. It's an Ubuntu 10.04 installation running an Linux 2.6 kernel. Yes, it's an old kernel, but I'm stuck with it for awhile.
When I compiled the kernel, I used gcc version 4.4. On this system, there is a kernel module I have been compiling successfully for three years.
From my Makefile...
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) \
modules
My current project requires support for c++14, so I updated gcc and g++ to version 5.1.0 by building from source. All my user-mode software compiles, but when I went to build an updated version of my kernel module, I get the following error right away:
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-54-generic'
CC [M] /home/tbj/srcroot/ctsengine-hg/CtsRt/ctsrt_main.o
In file included from include/linux/compiler.h:40:0,
from include/linux/stddef.h:4,
from include/linux/list.h:4,
from include/linux/module.h:9,
from /home/tbj/srcroot/ctsengine-hg/CtsRt/ctsrt_main.c:31:
include/linux/compiler-gcc.h:86:30: fatal error: linux/compiler-gcc5.h: No such file or directory
In short:
fatal error: linux/compiler-gcc5.h: No such file or directory
If I use gcc 4.4 again (I left it installed on my computer in a different directory), it compiles and runs perfectly.
Obviously, I'm missing something. Is it not possible to compile a kernel module with a newer version of the compiler than what the operating system was compiled with? That seems unlikely to me. Is there a configuration step I'm missing? Is there a system variable I need to update? Are there extra headers I'm supposed to download? I ran apt to update build-essential, but it was up to date. I have the source and headers for the kernel on my system. I'm not sure what else I would download.
Any insights to this problem are greatly appreciated. Thank you in advance.
Your kernel version is too old and it is missing linux/compiler-gcc5.h.
The header is included from linux/compiler-gcc.h and its name is generated by preprocessor macro based on current compiler version:
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
This header was introduced around version 3.18.
You might try to get this file from a newer kernel source and put in into include/linux.
Open a terminal and type:
$ ls -r /usr/src/linux-headers-$(uname -r)/include/linux/ | \
grep -P "compiler-gcc\d.h" | \
head -n 1
this will hopefully output the latest gcc header suitable for your linux kernel.
In my case it is compiler-gcc4.h. Now you can link this file to compiler-gcc5.h in the following way:
$ sudo ln -s /usr/src/linux-headers-$(uname -r)/include/linux/compiler-gcc4.h \
/usr/src/linux-headers-$(uname -r)/include/linux/compiler-gcc5.h
I have a 64-bit 3.9 kernel. Actually I applied a patch and rebuilt the entire kernel on a different (32-bit) Ubuntu machine then I brought the *.deb files over and used the "dpkg -i" procedure to install the patched up kernel to my Ubuntu 12.04. It's a minor patch, doesn't change much and everything works except...
I did a "apt-get install module-assistant build-essentials linux-headers-$(uname -r)". I can see the usr/include/src/linux-headers-3.9.0-custom. It's all there.
My Makefile says
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
But I inevitably get:
usr/include/src/linux-headers-3.9.0-custom/scripts/recordmcount: 1: usr/include/src/linux-headers-3.9.0-custom/scripts/recordmcount: Syntax error: word unexpected (expecting ")")
when I try to do the build. This same source code builds sucessfully when I attempt it on my Ubuntu 32-bit 3.2 Kernel system.
This was an issue of cross-compiling. I used a 32-bit Ubuntu system to build a 64-bit kernel and it's been nothing but headaches. Apparently the scripts etc still get built as 32-bit. (They'd have to since my 32-bit system needed to use them to build the kernel.) But then if bring that /usr/src/linux-headers-x.x.x dir over to my 64-bit system I can't use it to build any kernel modules because its /scripts dir is 32-bit.
I rebuilt recordmcount on the 64-bit machine and that worked. But then there was another script that was incompatible with 64-bits, that wasn't as easy to build without rebuilding the entire kernel.
Anyway, if you cross compile you don't get a /usr/src/linux-header-x.x.x/scripts dir that's usable on your target system.