Linux Kernel Module Licensing and Version Magic
Linux kernel module licensing and version magic are two things every embedded developer runs into sooner or later. This article breaks both down from scratch — what they are, why they exist, and what happens when you get them wrong.
Hello students welocme to embedded pathashalas free embedded systems course, in this we will discuss about Linux Kernel Module Licensing and Version Magic.
- Why Licensing and Version Magic Matter
- What is Version Magic (VERMAGIC_STRING)?
- Printing VERMAGIC_STRING from a Module
- MODULE_LICENSE — Do We Really Need It?
- Valid License Strings in the Linux Kernel
- What is Kernel Tainting?
- Invalid License — What Really Happens
- GPL vs Proprietary — EXPORT_SYMBOL_GPL Enforcement
- Build Error When Proprietary Module Uses GPL Symbol
- Summary and SEO Meta
01 Why Linux Kernel Module Licensing and Version Magic Matter
so now i will explain Why Linux Kernel Module Licensing and Version Magic Matter? When you write your first kernel module and it loads cleanly, everything feels straightforward. But the moment you try loading it on a slightly different kernel, or ship it without a proper license declaration, things break in ways that are confusing at first glance.
That confusion almost always traces back to two things: version magic and module licensing. Together they form a safety layer the Linux kernel uses to answer two questions every time you run insmod:
- Was this module compiled for exactly this kernel? — answered by version magic.
- Is this module allowed to use the kernel APIs it is calling? — answered by the license.
Once you understand both, a whole category of mysterious build errors and load failures suddenly make complete sense.
02 What is Version Magic (VERMAGIC_STRING)?
let us study what is version magic in detail , Every compiled kernel module contains a special string embedded in its .modinfo ELF section called the VERMAGIC_STRING. This string is a fingerprint of the exact kernel configuration the module was built against. When you load the module, the kernel compares this fingerprint with its own. If they do not match, the module is rejected before a single line of its code runs.
Think of it like a batch code stamped on a medicine bottle. The hospital will only accept medicine manufactured for that specific batch, not a similar one from a different run.
What Goes Into the VERMAGIC_STRING?
The string is constructed at compile time from several components defined in include/linux/vermagic.h:
#define VERMAGIC_STRING \ UTS_RELEASE /* kernel version e.g. "6.8.0-106-generic" */ \ " " \ MODULE_VERMAGIC_SMP /* "SMP" if SMP kernel */ \ MODULE_VERMAGIC_PREEMPT /* preemption model */ \ MODULE_VERMAGIC_MODULE_UNLOAD /* module unload support */ \ MODULE_VERMAGIC_MODVERSIONS /* symbol versioning (CRC) */ \ MODULE_ARCH_VERMAGIC /* architecture-specific string */
A real VERMAGIC_STRING on a typical Ubuntu machine looks something like:
6.8.0-106-generic SMP preempt mod_unload modversions
Every part of that string must match the running kernel exactly. If your module was compiled on a machine running 6.8.0-90-generic and you try to load it on 6.8.0-106-generic, the kernel will refuse it with a version mismatch error — even though the two kernels are very close to each other.
How to Check VERMAGIC with modinfo
let us see how we can check version magic, In modern kernels, the vermagic string is automatically embedded into every .ko file at build time. You do not need to do anything extra. You can inspect it with the modinfo command:
Terminal — Check vermagic with modinfo
💡
vermagic line in modinfo output is the exact string the kernel will compare against its own fingerprint at load time. If you see a different kernel version in that string than what uname -r shows, do not bother trying to load it — rebuild the module first.03 Printing VERMAGIC_STRING from a Module
You can also print the vermagic string from inside a module at load time. This is useful during BSP bring-up to confirm which kernel a module was built against, especially when multiple kernel versions are floating around in a product team.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/vermagic.h> /* gives us VERMAGIC_STRING */ MODULE_LICENSE("GPL"); static int vermagic_init(void) { /* * VERMAGIC_STRING is a compile-time constant string. * We concatenate it directly into the format string — * no %s needed because it is known at compile time. */ pr_info("VERMAGIC_STRING = " VERMAGIC_STRING "\n"); return 0; } static void vermagic_exit(void) {} module_init(vermagic_init); module_exit(vermagic_exit);
obj-m := ver_magic.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
Terminal — Build and load ver_magic
04 MODULE_LICENSE — Do We Really Need It?
Here is a question beginners almost always ask: “If I just remove MODULE_LICENSE(), will the module still compile and load?” The honest answer is — it depends on which kernel you are running, and the behaviour changed significantly over the years.
Kernel 2.6 era
┌──────────────────────────────────────────────────┐
│ MODULE_LICENSE was optional │
│ Module loaded fine without it │
│ Kernel printed a warning, tainted itself │
└──────────────────────────────────────────────────┘
Kernel 4.x and newer (including 6.x)
┌──────────────────────────────────────────────────┐
│ modpost (the build-time checker) fails │
│ Build stops — .ko is NOT generated │
│ Error: "missing or invalid license" │
└──────────────────────────────────────────────────┘
So on the kernel you are most likely running today — anything 5.x or 6.x — missing MODULE_LICENSE() is a build error, not just a warning. The .ko file will not even be created.
What Does MODULE_LICENSE Actually Do?
MODULE_LICENSE() does three things for the kernel:
- Tells the kernel if your module is GPL-compatible — this controls whether it can call
EXPORT_SYMBOL_GPLsymbols. - Controls kernel tainting — a non-GPL or unknown license marks the kernel as tainted when the module loads.
- Gets embedded in
.modinfo— visible throughmodinfoand used by distribution tools to track proprietary drivers.
⚠️
MODULE_LICENSE is not your mistake — it is a kernel version difference. On old 2.6 kernels it was optional. On modern kernels it is strictly enforced at build time. If you are following an older tutorial that skips it, just add MODULE_LICENSE("GPL") and move on.05 Valid License Strings for Linux Kernel Module Licensing
The kernel does not accept arbitrary strings in MODULE_LICENSE(). It checks against a predefined list. Here are all the valid options and what each one means for your module:
| License String | GPL Compatible? | Can Use EXPORT_SYMBOL_GPL? | Taints Kernel? |
|---|---|---|---|
"GPL" |
✅ Yes | ✅ Yes | ❌ No |
"GPL v2" |
✅ Yes | ✅ Yes | ❌ No |
"GPL and additional rights" |
✅ Yes | ✅ Yes | ❌ No |
"Dual MIT/GPL" |
✅ Yes | ✅ Yes | ❌ No |
"Dual BSD/GPL" |
✅ Yes | ✅ Yes | ❌ No |
"Dual MPL/GPL" |
✅ Yes | ✅ Yes | ❌ No |
"Proprietary" |
❌ No | ❌ No | ✅ Yes — P flag |
Any unknown string (e.g. "abc") |
❌ No | ❌ No | ✅ Yes — treated as proprietary |
✅
MODULE_LICENSE("GPL"). It is the safest choice — gives you full access to kernel APIs, no tainting, and maximum compatibility.06 What is Kernel Tainting?
Kernel tainting is the kernel’s way of flagging itself when something non-standard, unsupported, or potentially unstable has happened. Once tainted, the kernel keeps running normally — but kernel developers will often ask you to reproduce a crash on a clean, untainted kernel before they investigate a bug report.
A good mental model: tainting is like putting a sticker on your car that says “modified engine — warranty void.” The car still drives. But the manufacturer will not fix it under warranty if something breaks.
What Causes Kernel Tainting?
- Loading a proprietary (non-GPL) driver
- Loading a module with an invalid or missing license
- Loading an out-of-tree module (staging drivers)
- Hardware errors like MCE (machine check exceptions)
- Forced loading of a module that failed version checks
How to Check Taint Status
Terminal — Check kernel taint flags
Important: Taint Persists Even After rmmod
This is something that catches beginners off guard. Once the kernel is tainted, removing the module does not clear the taint flag. The taint stays for the rest of the current boot session.
Also — if you remove and re-insert the module, dmesg might not print the taint warning again (because the kernel suppresses duplicate messages). But the taint is still there. Always check /proc/sys/kernel/tainted directly, not just dmesg.
💡
kernel-chktaint that decodes the taint value into human-readable flags. Run it against your kernel source to see exactly what each bit in the taint integer means. Each bit position represents a different reason for tainting.Common Taint Flag Values
| Bit Value | Flag | Reason |
|---|---|---|
1 |
P | Proprietary module loaded |
2 |
F | Module was force-loaded |
4 |
S | SMP on non-SMP hardware |
8 |
R | Module was force-unloaded |
16 |
M | Machine check exception occurred |
4096 |
OE | Out-of-tree / externally built module |
07 Invalid License — What Really Happens
Let us look at what actually happens when you use a completely made-up license string like "abc". This is one of those experiments that teaches you more than any diagram.
#include <linux/kernel.h> #include <linux/module.h> MODULE_LICENSE("abc"); /* not a valid license string */ static int test_hello_init(void) { printk(KERN_INFO "%s: in init\n", __func__); return 0; } static void test_hello_exit(void) { printk(KERN_INFO "%s: in exit\n", __func__); } module_init(test_hello_init); module_exit(test_hello_exit);
Now let us trace exactly what happens at each stage:
The compiler does not validate license strings. It treats "abc" as just another string constant and embeds it in .modinfo. The .ko file is generated without errors.
The module loads. The init function runs. But the kernel immediately prints a taint warning and marks itself tainted.
The taint flag is set. Lock debugging is disabled. The kernel logs the warning. This taint persists for the rest of the boot, even after rmmod.
Module unloads cleanly. Exit function runs. But the kernel is still tainted.
Terminal — Invalid license full session
🚫
EXPORT_SYMBOL_GPL APIs. If your module tries to call a GPL-only symbol while declaring an invalid or proprietary license, the build will fail — as we will see in the next section.08 GPL vs Proprietary — EXPORT_SYMBOL_GPL Enforcement
Now we get to the most practically important part of Linux kernel module licensing: the difference between EXPORT_SYMBOL and EXPORT_SYMBOL_GPL, and what happens when a proprietary module tries to call a GPL-only symbol.
EXPORT_SYMBOL(myadd)
Any module can call this — GPL or Proprietary
EXPORT_SYMBOL_GPL(myadd)
Only modules with MODULE_LICENSE("GPL") or compatible
✅ MODULE_LICENSE("GPL") → allowed
✅ MODULE_LICENSE("Dual MIT/GPL") → allowed
❌ MODULE_LICENSE("Proprietary") → build fails
❌ MODULE_LICENSE("abc") → build fails
The enforcement happens at build time inside a tool called modpost — not at load time. So the moment you run make, if your module declares a non-GPL license but uses a GPL-only symbol, the build stops with a clear error message.
The Two Modules — mod1 (GPL) and mod2 (Proprietary)
#include <linux/kernel.h> #include <linux/module.h> MODULE_LICENSE("GPL"); int myadd(int a, int b) { pr_info("%s: adding %d + %d = %d\n", __func__, a, b, a + b); return a + b; } EXPORT_SYMBOL_GPL(myadd); /* only GPL modules can call this */ static int mod1_init(void) { pr_info("%s: in init\n", __func__); return 0; } static void mod1_exit(void) { pr_info("%s: in exit\n", __func__); } module_init(mod1_init); module_exit(mod1_exit);
#include <linux/kernel.h> #include <linux/module.h> MODULE_LICENSE("Proprietary"); /* this will cause the build to fail */ extern int myadd(int a, int b); static int mod2_init(void) { pr_info("%s: In init\n", __func__); pr_info("%s: Add: %d\n", __func__, myadd(3, 5)); return 0; } static void mod2_exit(void) { pr_info("%s: In exit\n", __func__); } module_init(mod2_init); module_exit(mod2_exit);
09 Build Error When Proprietary Module Uses GPL Symbol
When you run make with the above two files, the compiler builds both object files fine. But then modpost runs — and it stops the build cold:
Terminal — modpost GPL enforcement error
The error message is very precise: “GPL-incompatible module mod2.ko uses GPL-only symbol ‘myadd'”. This is modpost doing its job — enforcing the license boundary at build time so that GPL-only kernel APIs cannot be accessed by proprietary code.
The Fix
You have two options depending on your situation:
- Option 1: Change mod2’s license to
"GPL"— this immediately clears the error and the build succeeds. - Option 2: In mod1, change
EXPORT_SYMBOL_GPL(myadd)toEXPORT_SYMBOL(myadd)— this makes the symbol available to everyone regardless of license. Use this only if you intend the API to be truly open to all consumers.
💡
-Wmissing-prototypes warning you see in the output is separate — it is the compiler saying that myadd() has no header file declaration visible before its definition. In kernel modules this is common for exported functions. You can silence it by adding a forward declaration or by putting the declaration in a shared header file.Quick Reference — Everything Together
| Scenario | Build Result | Load Result | Kernel Tainted? |
|---|---|---|---|
GPL module + EXPORT_SYMBOL_GPL |
✅ Success | ✅ Loads cleanly | ❌ No |
Proprietary module + EXPORT_SYMBOL |
✅ Success | ✅ Loads (with taint) | ✅ Yes — P flag |
Proprietary module + EXPORT_SYMBOL_GPL |
❌ modpost fails | — (.ko not created) | — |
| Invalid license string + no GPL symbols | ✅ Success | ✅ Loads (with taint) | ✅ Yes |
| Missing MODULE_LICENSE (modern kernel) | ❌ modpost fails | — | — |
10 Summary
Key Takeaways — Linux Kernel Module Licensing and Version Magic
- VERMAGIC_STRING is a build-time fingerprint embedded in every
.ko. It must exactly match the running kernel or the module will be rejected atinsmod. Check it withmodinfo your_module.ko. - Version mismatch errors after a kernel update are always because the softlink or module was built against the old kernel. Rebuild against
$(uname -r)and the error goes away. MODULE_LICENSE()is mandatory on modern kernels (4.x+). Missing it causes a build failure at themodpoststage — the.kois never generated.- Valid license strings include
"GPL","GPL v2","Dual MIT/GPL","Dual BSD/GPL", and"Proprietary". Anything else is treated as invalid and will taint the kernel on load. - Kernel tainting means the kernel has flagged itself as modified or non-standard. It keeps running, but developers may not help debug crashes. Check taint status with
cat /proc/sys/kernel/tainted— zero means clean. - Taint is permanent for the current boot. Removing a tainted module does not clear the flag. Only a reboot resets it.
EXPORT_SYMBOL_GPLenforces GPL licensing at build time viamodpost. A proprietary module trying to use a GPL-only symbol gets a hard build error — not a runtime error. Change the license to GPL or the export macro toEXPORT_SYMBOLto fix it.
so from this lecture i hope you understood about linux kernel module licensing and version magic infoamtion.
Meta data in linux kernel modules
Linux kernel modules (.ko) files will contain some important infomation that will help the kenrel to understand the compatibility, author infomraiton, version infoamtion and more about that kernel module and we call this infoamtion as meta data infaotmion. this meta data information is useful when you are working with third part modules
How to Find Kernel Version of a Kernel module .ko Module ?
so when you receive information from the vendor you mut first check to which kernel that particualr module was build, you can get information from modinfo
modinfo <module.ko>
key field in the modinfo is the ersion magic number
vermagic: 6.8.0-101-generic SMP preempt mod_unload
this version magic will let you know about hte kenrl version 6.8.0-101-generic, and build features SMP, peempt etc.
then you compare that information with the current system where you are trying to insert the module, if they both match then the module is compatible, if they both dont match then the module may not load.
header file for linux kernel module information:
include/linux/module.h
1. MODULE_DESCRIPTION:
MODULE_DESCRIPTION(“Simple demo kernel module”);
this is short description about what module does
2. MODULE_AUTHOR:
MODULE_AUTHOR(“EMBEDDED PATHASHALA”);
this will tell you who is the author of hte module.
3. MODULE_VERSION
MODULE_VERSION(“1.0”);
this will let you know the information about the module version
4. MODULE_LICENSE
MODULE_LICENSE(“GPL”);
this will help you in situation like kernel tainting and access to GPL only symbols.
5. MODULE_INFO
MODULE_INFO(custom, “This is custom metadata”);
Used to add custom key-value metadata
What is srcversion?
- Automatically generated unique identifier
- Based on source code checksum
- Helps identify exact module build
Free learning to all !!
Embeddedpathashala.com.
