What are Module Macros, Kernel Headers

Prev_Lec

Next_Lec

Linux Kernel Module – What are Module Macros, Kernel Headers and the modinfo Command

What are Module Macros, Kernel Headers and the modinfo Command
⚙️ Kernel 6.x Updated
🆓 Free Course
🎯 Beginner Friendly

Topics Covered
Kernel Headers
MODULE_LICENSE
MODULE_AUTHOR
MODULE_DESCRIPTION
MODULE_VERSION
modinfo command
linux-headers package
build symlink

In the previous part we saw the overall structure of a Linux Kernel Module (LKM). Now let us go deeper and understand two important things — where the kernel gets its header files from during compilation, and what those MODULE_FOO() lines at the top of every module actually do.

These are small things but they matter a lot when you write real modules or when you are debugging a build failure. Let us take it step by step.

Where Do Kernel Headers Come From?

When you write a kernel module, you include header files like #include <linux/module.h> or #include <linux/init.h>. These are NOT the same as normal C library headers. They come from the kernel source tree itself.

But the complete kernel source is huge — several gigabytes. You do not need all of it just to compile a module. You only need a limited portion — the headers and Makefiles. That is exactly what the linux-headers package gives you.

On Ubuntu or Debian systems you can install it like this:

sudo apt install linux-headers-$(uname -r)

Once installed, check what is available under your module directory:

ls -l /lib/modules/$(uname -r)/

You will see something like this (kernel 6.x example on Ubuntu 24.04):

lrwxrwxrwx 1 root root   42 Jan 10 09:00 build -> /usr/src/linux-headers-6.8.0-51-generic/
drwxr-xr-x 2 root root 4096 Jan 10 09:00 initrd/
drwxr-xr-x 3 root root 4096 Jan 10 09:00 kernel/
drwxr-xr-x 2 root root 4096 Jan 10 09:00 modules.dep
...

The important thing here is the build symlink. It points to the kernel headers directory under /usr/src/. This is what your Makefile uses to locate header files during compilation.

How the Compiler Finds Kernel Headers
Your Module Source Makefile uses KDIR
#include <linux/module.h> /lib/modules/$(uname -r)/build
GCC resolves to → /usr/src/linux-headers-6.x.x/include/linux/module.h

So when you write #include <linux/init.h>, the compiler follows the build symlink and finds the actual header file inside /usr/src/linux-headers-<version>/include/linux/init.h.

You can verify this yourself:

ls /usr/src/linux-headers-$(uname -r)/include/linux/init.h

What Are Module Macros?

Every kernel module has a set of metadata macros at the top. These look like function calls but they are actually macros that embed information directly into the compiled .ko file. This metadata can be read without loading the module.

Think of it like an ID card for your kernel module. Anyone can read the card without actually “using” the module.

Module Metadata — The ID Card of a .ko File
Macro What it stores Example
MODULE_AUTHOR() Who wrote this module "Ravi Kumar <ravi@example.com>"
MODULE_DESCRIPTION() What this module does "Demo GPIO driver for RPi"
MODULE_LICENSE() Under which license "GPL"
MODULE_VERSION() Version string "1.0"

Here is how they look inside a real module source file:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

MODULE_AUTHOR("Ravi Kumar <ravi@example.com>");
MODULE_DESCRIPTION("A simple demo kernel module");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");

Understanding Each Macro
MODULE_AUTHOR()

This is a simple string that names the person or team who wrote the module. You can have more than one MODULE_AUTHOR() line if there are multiple contributors. It has no effect on how the module runs — it is purely informational.

MODULE_AUTHOR("Alice <alice@linux.org>");
MODULE_AUTHOR("Bob <bob@linux.org>");
MODULE_DESCRIPTION() — Important in Kernel 6.x!

A short one-line description of what your module does. This was optional in older kernels, but starting from kernel 6.10, the kernel build system generates a warning if you skip it. In kernel 6.15 and later, it is a hard build error — your module will not compile without it.

Best practice: always include it, even if you are building for an older kernel.

MODULE_DESCRIPTION("Simple character device driver demo");
⚠️ Kernel 6.x Note: From kernel 6.10 onwards, missing MODULE_DESCRIPTION() produces a build warning. From kernel 6.15 onwards it is a build error. Always include it.
MODULE_LICENSE() — Mandatory!

This is the most important macro from the kernel’s point of view. The kernel uses this to decide whether your module has access to GPL-only kernel symbols.

If you omit it, the build will fail — the kernel build tool called modpost enforces this.

The two most common values:

MODULE_LICENSE — What It Means
License String Access to GPL symbols Kernel taint flag
"GPL" ✅ Full access No taint — kernel remains clean
"GPL v2" ✅ Full access No taint
"Proprietary" ❌ No GPL symbols ⚠️ Kernel gets TAINT_PROPRIETARY_MODULE flag

Other valid strings: "Dual BSD/GPL", "Dual MIT/GPL", "Dual MPL/GPL".

For learning and open-source development, always use "GPL".

MODULE_LICENSE("GPL");
MODULE_VERSION()

A simple version string for your module. There is no fixed format — use whatever makes sense for your project. It is optional but good practice.

MODULE_VERSION("2.1.0");

Reading Module Metadata with modinfo

All this metadata that the macros embed into the .ko file can be read using the modinfo command — even without loading the module into the kernel. This is very useful for system administrators to audit what is running on a machine.

Suppose you compiled a module called hello.ko. Running modinfo on it gives:

modinfo hello.ko

Output will look like:

filename:       /path/to/hello.ko
license:        GPL
description:    A simple demo kernel module
author:         Ravi Kumar <ravi@example.com>
version:        1.0
srcversion:     A1B2C3D4E5F
depends:
name:           hello
vermagic:       6.8.0-51-generic SMP preempt mod_unload

Notice the vermagic field — this is the kernel version the module was built for. If you try to load a module built for a different kernel version, it will fail with a version mismatch error. This protects the system from loading incompatible modules.

You can also run modinfo on already-installed system modules:

# Read metadata of the bluetooth module
modinfo bluetooth

# Read only the license field
modinfo -F license bluetooth

# Read only the description
modinfo -F description bluetooth

In products and enterprise environments, teams often run modinfo with grep on all installed modules to audit licenses — this helps legal teams ensure GPL compliance across a product.

A Complete Module Template with All Macros

Here is a clean template that follows all the best practices for kernel 6.x. Notice the SPDX identifier at the top — this is the preferred way to express file licensing in modern kernel code:

// SPDX-License-Identifier: GPL-2.0
/*
 * hello_mod.c - A simple Hello World kernel module
 * Updated for Linux Kernel 6.x
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

MODULE_AUTHOR("Your Name <your@email.com>");
MODULE_DESCRIPTION("Hello World - Demo LKM for Linux 6.x");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");

static int __init hello_init(void)
{
    pr_info("hello_mod: module loaded successfully\n");
    return 0;
}

static void __exit hello_exit(void)
{
    pr_info("hello_mod: module removed\n");
}

module_init(hello_init);
module_exit(hello_exit);
💡 Note: The SPDX identifier line (// SPDX-License-Identifier: GPL-2.0) and MODULE_LICENSE("GPL") serve different purposes. SPDX is for file-level license tracking tools. MODULE_LICENSE() is what the kernel actually checks at runtime. You need both.

Interview Questions
Q1. What is the purpose of MODULE_LICENSE() in a kernel module?

Answer: MODULE_LICENSE() tells the kernel what license this module is released under. It is mandatory — the build will fail without it. If the license is not a GPL-compatible string, the kernel sets a taint flag when the module is loaded, indicating the kernel is running with proprietary code. GPL-licensed modules get full access to all exported kernel symbols including those exported with EXPORT_SYMBOL_GPL().

Q2. What happens if you load a module that was compiled for a different kernel version?

Answer: The kernel checks the vermagic field embedded in the .ko file. If it does not match the running kernel, the module load fails with an error like ERROR: could not insert module: Invalid module format. This prevents binary incompatibility and system crashes from mismatched ABIs.

Q3. Where does the compiler find kernel header files when building an out-of-tree module?

Answer: The Makefile points to KDIR = /lib/modules/$(uname -r)/build. This is a symbolic link that points to the installed kernel headers directory, typically /usr/src/linux-headers-<version>/. The compiler resolves all #include <linux/...> paths from within this directory.

Q4. Can you have multiple MODULE_AUTHOR() lines in one module?

Answer: Yes. You can repeat MODULE_AUTHOR() as many times as needed. Each call adds another author: entry to the module’s .modinfo section. All entries are visible in the modinfo output.

Q5. What changed with MODULE_DESCRIPTION() in kernel 6.x?

Answer: In older kernels and up to kernel 6.9, MODULE_DESCRIPTION() was optional. From kernel 6.10 onwards, the kernel build system (modpost) generates a warning if it is missing when you build with make W=1. From kernel 6.15 onwards, a missing MODULE_DESCRIPTION() is a hard build error — the module will not compile at all. Best practice is to always include it.

Next: Entry Points, Exit Points and the 0/-E Convention

In the next tutorial we will understand module_init(), module_exit(), the __init and __exit macros, and the important 0/-E return convention used in the Linux kernel.

Prev_Lec

Next_Lec →

 

Leave a Reply

Your email address will not be published. Required fields are marked *