Skip to main content

TECH VEDA

Corporate on-site training - Submit proposal Pick your modulesSharpen your kernel skills: deep dives, drivers, Yocto, CVEs, careers — updated daily. Read the blog →
Fix Guides

Invalid Module Format on insmod: Which Kernel Check Rejected Your Module?

Invalid module format from insmod means the kernel returned ENOEXEC. Seven causes, the dmesg line that identifies each, and the fix for every one.

Invalid Module Format on insmod: Which Kernel Check Rejected Your Module?

On an embedded board, Invalid module format most often means the module was built against a kernel tree whose release string or configuration differs from the kernel that is running. The tool’s message carries only an error number. The kernel log usually names the exact check that rejected the file, so the first thing to do is run dmesg immediately after the failed load and read the last line.

The message

insmod: ERROR: could not insert module mydriver.ko: Invalid module format

The text Invalid module format is not printed by the kernel. It comes from mod_strerror() in tools/insmod.c of kmod, which translates the error number ENOEXEC returned by the finit_module() or init_module() system call. The kernel’s module loader returns -ENOEXEC from many places in load_module() and the functions it calls, in kernel/module/main.c, so the message says only that the loader refused the file. Other tools print the same error number in different words:

modprobe: ERROR: could not insert 'mydriver': Exec format error
insmod: can't insert 'mydriver.ko': invalid module format

The first line is kmod’s modprobe, which passes ENOEXEC to strerror(). The second is the BusyBox insmod applet, whose moderror() table uses lower case. The diagnosis below applies to all three forms.

Quick diagnosis: which Invalid module format cause you have

Load the module once more and read the kernel log:

root@imx8mp-evk:~# insmod mydriver.ko
root@imx8mp-evk:~# dmesg | tail
CauseHow to confirmFix
1. Version magic differsdmesg shows version magic '...' should be '...'Rebuild against the running kernel’s build tree and configuration
2. module_layout checksum differsdmesg shows disagrees about version of symbol module_layoutRebuild against the tree and Module.symvers of the running kernel
3. Wrong architecture, compressed or damaged filereadelf -h mydriver.ko on the build host; dmesg shows an Invalid ELF header or Invalid architecture lineCross-compile for the board, decompress, or copy the file again
4. struct module size differsdmesg shows section size must match the kernel's built struct module size at run timeRebuild with the running kernel’s configuration
5. Module carries no symbol versionsdmesg shows nothing; readelf -S mydriver.ko lists no __versions sectionBuild against a tree configured with CONFIG_MODVERSIONS, as the running kernel is
6. Symbol table strippeddmesg shows module has no symbols (stripped?)Install the unstripped file, or strip with --strip-debug only
7. Driver already built into the kerneldmesg shows exports duplicate symbolDo not load the second copy, or build the driver as a module only

Cause 1: the version magic differs

Every module carries a vermagic string in its .modinfo section. check_modinfo() compares it with the kernel’s own string and, on a mismatch, returns -ENOEXEC and prints this line (the kernel’s format from the source, with example values):

mydriver: version magic '7.3.0 SMP preempt mod_unload aarch64' should be '7.3.0 SMP preempt_rt mod_unload aarch64'

The string is assembled in include/linux/vermagic.h from the kernel release, then one word each for CONFIG_SMP, the preemption model (preempt or preempt_rt), CONFIG_MODULE_UNLOAD (mod_unload), CONFIG_MODVERSIONS (modversions), an architecture word, and a RANDSTRUCT_ seed hash when structure layout randomisation is enabled. same_magic() compares with strcmp(), so the strings must be identical, including any suffix after the version number. One exception: when the module carries symbol checksums, the release is skipped and only the remaining words are compared.

Print the module’s string and the running release; the kernel log line shows the full expected string:

root@imx8mp-evk:~# modinfo -F vermagic mydriver.ko
root@imx8mp-evk:~# uname -r

This is the most frequent reason for Invalid module format on a BSP. Rebuild the module against the build tree that produced the running kernel: the same source, .config and local version suffix. The word that differs between the two strings names the option to correct. If a string contains RANDSTRUCT_, only the build that generated that seed can produce a matching module.

Cause 2: the module_layout checksum differs

On a kernel built with CONFIG_MODVERSIONS, check_modstruct_version() runs before the version magic comparison. It looks up one exported symbol, module_layout, and compares its checksum with the one recorded in the module. On a mismatch check_version() in kernel/module/version.c prints:

mydriver: disagrees about version of symbol module_layout

module_layout() is an empty function whose prototype names struct module, struct modversion_info, struct kernel_param, struct kernel_symbol and struct tracepoint. Its checksum changes when any of those definitions changes, so the line appears when the build tree and the running kernel differ in source or configuration. Because this check runs first, such a module never reaches the version magic comparison.

The kernel prints the two checksum values only at debug level. With CONFIG_DYNAMIC_DEBUG and debugfs mounted, enable that line and load again:

root@imx8mp-evk:~# echo 'file kernel/module/version.c +p' > /sys/kernel/debug/dynamic_debug/control
root@imx8mp-evk:~# insmod mydriver.ko
root@imx8mp-evk:~# dmesg | tail

Rebuild against the tree and the Module.symvers file from the kernel build that produced the running image. If the line names any other symbol, the load fails later with a different error number and kmod prints Invalid parameters, not Invalid module format.

Cause 3: wrong architecture, compressed or damaged file

Before any version check, elf_validity_ehdr() confirms that the file is a relocatable ELF object for the kernel’s architecture. Its message formats are:

Invalid ELF header len %lu
Invalid ELF header magic: != %s
Invalid ELF header type: %u != %u
Invalid architecture in ELF header: %u

The number in the last line is the ELF machine value from include/uapi/linux/elf-em.h: 62 is x86-64, 40 is 32-bit ARM, 183 is AArch64 and 243 is RISC-V. A value of 62 on an ARM board means the module was compiled for an x86-64 build host, usually because ARCH and CROSS_COMPILE were not passed to make. A magic failure means the first four bytes are not an ELF header, which is what the kernel sees when a compressed .ko.gz, .ko.xz or .ko.zst file reaches it without being decompressed, or when a transfer was incomplete. Confirm on the build host, and compare the checksum with the copy on the board:

raghu@techveda.org:~$ readelf -h mydriver.ko
raghu@techveda.org:~$ sha256sum mydriver.ko

The Type field must be REL and the Machine field must match the board. Rebuild with the cross toolchain, decompress the file, or copy it again.

Cause 4: the struct module size differs

Each module contains one instance of struct module in its .gnu.linkonce.this_module section, compiled from the headers of the build tree. In the 6.6 series and later, elf_validity_cache_index_mod() compares the size of that section with the kernel’s own sizeof(struct module) and prints:

module mydriver: .gnu.linkonce.this_module section size must match the kernel's built struct module size at run time

struct module in include/linux/module.h has many fields inside #ifdef blocks, among them CONFIG_TRACEPOINTS, CONFIG_KALLSYMS and CONFIG_MODULE_SIG. A build tree with a different setting for such an option can produce a different size. This test runs before both version checks, so on these kernels it can be the only line printed for a configuration mismatch. Compare the two configurations, where running.config is the decompressed /proc/config.gz from the board:

raghu@techveda.org:~$ linux/scripts/diffconfig running.config linux/.config

The fix is the same as for cause 1.

Cause 5: the module carries no symbol versions

This cause returns Invalid module format and prints nothing in the kernel log. When the kernel exports checksums and the module has no __versions section, check_version() calls try_to_force_load(). Unless the kernel was built with CONFIG_MODULE_FORCE_LOAD, which is default n, that function returns -ENOEXEC without a message. A module with no vermagic field takes the same silent path. Confirm with:

raghu@techveda.org:~$ readelf -S mydriver.ko | grep version
root@imx8mp-evk:~# zcat /proc/config.gz | grep MODVERSIONS

If the board reports CONFIG_MODVERSIONS=y and the module shows neither __versions nor __version_ext_crcs, the build tree was configured without module versioning. Rebuild against a tree with the running kernel’s configuration.

Warning: the same function is why insmod --force and modprobe --force still fail on a kernel without CONFIG_MODULE_FORCE_LOAD. Where forced loading is enabled, it bypasses the checks that protect kernel memory from a module with a different structure layout, and it taints the kernel. A forced module can crash the system or corrupt data. Do not use it on a product or on a board holding data you need.

Cause 6: the symbol table was stripped

The loader resolves the module’s imports through its ELF symbol table. If the file has no symbol table section, the kernel prints:

mydriver: module has no symbols (stripped?)

The usual source is an image build or packaging script that strips more than debug information. Kbuild’s own install step, enabled with INSTALL_MOD_STRIP=1, uses --strip-debug. Confirm on the build host:

raghu@techveda.org:~$ readelf -S mydriver.ko | grep SYMTAB

No output means the table is gone. Install the unstripped file, or strip it with --strip-debug only.

Cause 7: the driver is already built into the kernel

After the earlier checks pass, verify_exported_symbols() rejects a module that exports a symbol the kernel or another loaded module already exports. The format string in the source is:

%s: exports duplicate symbol %s (owned by %s)

The owner is kernel when the first copy is built in, as happens when a BSP kernel has the driver set to y and an out-of-tree copy is loaded as well. Confirm with:

root@imx8mp-evk:~# grep mydriver /lib/modules/$(uname -r)/modules.builtin

Use the built-in driver, or change the kernel option to m or n. Where such a driver should live is discussed in In-Tree vs Out-of-Tree Driver: Where Your Code Should Live.

If none of these

If Invalid module format is still unexplained, note that the loader has further -ENOEXEC exits for malformed section headers, for objects with common symbols (please compile with -fno-common) and for livepatch modules on a kernel without livepatch support. Each prints its own line. If dmesg is empty and cause 5 is excluded, write file kernel/module/main.c +p to the dynamic debug control file and repeat the load. Then capture the full dmesg output, modinfo mydriver.ko, readelf -h -S mydriver.ko, uname -a and the kernel configuration. For a vendor kernel, send these to the BSP supplier. For a mainline or stable kernel, MAINTAINERS lists linux-modules@vger.kernel.org for module support.

Versions

The version magic, disagrees about version of symbol and module has no symbols (stripped?) lines are worded identically in 5.10.274, 5.15.225, 6.1.192, 6.6.162, 6.12.117, 6.18.63, 7.3 and 7.4-rc2. The differences are these:

  • In 5.10 and 5.15 the loader is one file, kernel/module.c; use that name with dynamic debug. From 6.1 it is kernel/module/main.c and kernel/module/version.c.
  • In 5.10.274 the ELF header tests of cause 3 return -ENOEXEC without printing. The Invalid ELF header lines are present from 5.15.225.
  • The struct module size test of cause 4 is absent in 6.1.192 and present from 6.6.162.
  • The randomisation word is RANDSTRUCT_PLUGIN_ in 5.10 and 5.15, and RANDSTRUCT_ from 6.1.
  • The extended version sections __version_ext_crcs and __version_ext_names are handled in 6.18.63 and not in 6.12.117.

What was checked and what could not be verified

Every message, function name and option above was read from kernel source at the tags listed above, from kmod’s master branch (its NEWS file is headed kmod 34) and from the BusyBox master branch on its GitHub mirror. Nothing in this guide was run on hardware. The example lines are the kernel’s format strings with illustrative values, not captured output. The ranking of causes is a judgement, not a measurement. Two points remain unverified. The kernel build documentation states that make modules_prepare does not produce Module.symvers; which of these checks, if any, rejects a module built from such a tree was not established. Which stripping options remove a module’s symbol table was not tested.

Key takeaways

  • Invalid module format is kmod’s wording for ENOEXEC; the reason is in the kernel log.
  • An empty kernel log after Invalid module format points to a module without symbol versions, or to a 5.10-series kernel rejecting the ELF header.
  • Most causes share one remedy: build the module from the source, configuration and Module.symvers of the running kernel.
Was this worth your time?

Frequently asked questions

Does Invalid module format mean the kernel version is wrong?
Not necessarily. The message reports only the error number ENOEXEC. A different configuration with the same release, a module compiled for the wrong architecture, a stripped symbol table and a driver that is already built in all produce Invalid module format.

Why does dmesg show nothing after the failed insmod?
A module with no symbol versions, loaded on a kernel built with CONFIG_MODVERSIONS and without CONFIG_MODULE_FORCE_LOAD, is rejected without a message. In the 5.10 series the ELF header tests are also silent.

Will insmod –force load the module anyway?
Only on a kernel built with CONFIG_MODULE_FORCE_LOAD, which is off by default. Without that option the forced path returns ENOEXEC again. Where it is enabled, forcing bypasses the checks that protect kernel memory and taints the kernel.

References

RB
Raghu Bharadwaj

Founder, TECH VEDA — 20+ years teaching the Linux kernel, device drivers and embedded systems.

Follow on LinkedIn

Get new posts by email

Kernel, embedded Linux and AI-era engineering — a few sharp reads a month. No spam.

We email occasionally and never share your address.