7

I want to build a kernel module that will be compatible with all the kernel’s releases. For example, if I build a kernel module on kernel 3.2.0-29 and try to load it on 3.2.0-86, I get the following error:

modprobe my_driver

FATAL: Error inserting my_driver (/lib/modules/3.2.0-86-generic/kernel/fs/my_drv/my_drv.ko): Invalid module format

[ In the log messeges: my_drv: disagrees about version of symbol module_layout ]

How can I build a kernel module on 3.2.0-29 that will be good for all 3.2.0 releases.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
kobi
  • 313
  • 1
  • 3
  • 10
  • "-29" and "-86" aren't part of the kernel version. Perhaps you should mention which distro you're talking about. – Ignacio Vazquez-Abrams May 08 '16 at 09:51
  • in the example, i'm talking about Ubuntu 12.04 LTS. – kobi May 08 '16 at 10:02
  • Even if you managed to disable the version checking, you would have to avoid all APIs that might change (which is all of them). – CL. May 08 '16 at 11:01
  • Does "modprobe -f my_driver" (note the -f) make any difference? – Giuseppe Gorgoglione May 08 '16 at 11:32
  • no, same error. I think that the solution is in the way that i build the kernel moudle. but I can't find any useful info about it. – kobi May 08 '16 at 11:43
  • It make no sense to build a kernel moudle for each kernel version (3.2.0-29,3.2.0-83,3.2.0-86..) it's also hard for a customer to upgrade his kernel moudle in any kernel upgrade. – kobi May 08 '16 at 11:50
  • 1
    Your question is poorly phrased. You mention building a module for kernel version 3.2.0-29. That's kernel version 3, patchlevel 2, sublevel 0, and extraversion 29. And you only want to support different *extraversions*. You shouldn't have to worry about any changing APIs. – sawdust May 09 '16 at 01:29
  • I want to use the same kernel moudle for all the extraversions. But as you can see above, i'm getting an error. – kobi May 09 '16 at 06:37

3 Answers3

6

In short: you hardly can write useful kernel module, which can be loaded to kernels of relatively wide range of versions.

When you build the module against kernel compiled with CONFIG_MODVERSIONS (like in your case), for every symbol, exported from the kernel, CRC for this symbol is stored in module's file. CRC is some sort of control sum, which takes into account, among other things, layout of types, used for function's parameters. For example, if layout of a hypothetical struct A differs in two kernels, CRC for function f(struct A *a) in these kernels differs too.

When a module is loaded into running kernel, CRC for all functions in the module are compared with ones for the kernel. If they differ, the kernel refuses to load the module. To read more about this mechanism see the kernel's documentation (Documentation/kbuild/modules.txt).

So, for make a module loadable into two different kernels, you are restricted only with functions whose parameters have same layout in both kernels. In particular, if layout of type struct module differs, no single module can be loaded for both kernels.


There are several approaches to deliver a driver suitable for several kernels. The simplest way is to deliver the driver's sources and add them to dkms. Such a way, if running kernel doesn't have the driver built, the driver will be compiled automatically using its sources.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • Thank you for your answer. In my case, I can't give my source code to the customers. There are other approaches ? – kobi May 10 '16 at 07:27
  • If you don't want to distribute sources, you should distribute (binary) driver per every kernel version(and configuration) you want to support. Linux kernel has no even stable API, and its ABI may change even on minor bug fixes. – Tsyvarev May 10 '16 at 07:37
  • You may also think about distributing driver partially in sources and partially in binary blob files. Assuming binary files do not use kernel API, they may be compatible with wide range of kernel versions. Documentation [Documentation/kbuild/modules.txt](http://www.mjmwired.net/kernel/Documentation/kbuild/modules.txt) also describes building modules with binary blob files. – Tsyvarev May 10 '16 at 07:43
  • For some security-sensitive structure (e.g. `struct task_struct`, `struct mm_struct`), the order of its member fields is randomized (determined by a random seed). This feature is known as `randstruct`, see https://lwn.net/Articles/722293/. – youfu Jun 28 '23 at 11:47
2

The Linux kernel module API is unstable as design choice

This is explicitly explained in the source tree at Documentation/stable_api_nonsense.txt. The summary reads:

Executive Summary
-----------------
You think you want a stable kernel interface, but you really do not, and
you don't even know it.  What you want is a stable running driver, and
you get that only if your driver is in the main kernel tree.  You also
get lots of other good benefits if your driver is in the main kernel
tree, all of which has made Linux into such a strong, stable, and mature
operating system which is the reason you are using it in the first
place.

But an important clarification is:

  The kernel to userspace interface is the one that application programs use,
  the syscall interface.  That interface is **very** stable over time, and
  will not break.  I have old programs that were built on a pre 0.9something
  kernel that still work just fine on the latest 2.6 kernel release.
  That interface is the one that users and application programmers can count
  on being stable.

But worry not! Our friendly Linux developers explain the solution right in the same document:

What to do
----------

So, if you have a Linux kernel driver that is not in the main kernel
tree, what are you, a developer, supposed to do?  Releasing a binary
driver for every different kernel version for every distribution is a
nightmare, and trying to keep up with an ever changing kernel interface
is also a rough job.

Simple, get your kernel driver into the main kernel tree (remember we
are talking about GPL released drivers here, if your code doesn't fall
under this category, good luck, you are on your own here, you leech
<insert link to leech comment from Andrew and Linus here>.)  If your
driver is in the tree, and a kernel interface changes, it will be fixed
up by the person who did the kernel change in the first place.  This
ensures that your driver is always buildable, and works over time, with
very little effort on your part.

Linux kernel version macro

Try using:

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)

as mentioned at Is there a macro definition to check the Linux kernel version?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
-1

Add an Environment variable to the Makefile viz. 'K_VERSION'.

Build the module against an installed kernel by passing the version as the environment variable

eg.

make K_VERSION=`uname -r`

to build against currently running kernel.

Once built, the modprobe utility can be used.

sulimo
  • 279
  • 1
  • 2
  • 6
  • Refer Linux Device Drivers, Chapter2, O'Reilly Publications – sulimo May 08 '16 at 10:28
  • This doesn't seem to answer the question that was actually asked. – davmac May 08 '16 at 10:36
  • I think that my question wasn't clear. I want to build a kernel moudle on 3.2.0-29 and give this moudle to customers with 3.2.0-* kernel (3.2.0-86 for example). – kobi May 08 '16 at 10:36
  • There is an option `--force-vermagic` , though it is said to be unsafe, refer (http://linux.die.net/lkmpg/x380.html) – sulimo May 14 '16 at 04:27