Skip to content

Case 175: kABI CRC Changed

Field Value
Verdict ๐Ÿ”ด BREAKING
Category Breaking
Platforms Linux
Flags ABI break
Detected ChangeKinds kabi_crc_changed
Source files examples/case175_kabi_crc_changed/

Category: Linux Kernel Module ABI (kABI) | Verdict: ๐Ÿ”ด BREAKING

Verdict and consumer impact

ext4_iget keeps its symbol name, module, export type, and namespace โ€” every field a naive symbol-presence diff would look at is identical between v1 and v2. Only its CRC changed. The CRC is not a version number a maintainer sets; it is a hash genksyms computes at build time from the symbol's type signature โ€” its return type, parameter types, and (transitively) every type they reference. A CRC change means a type behind ext4_iget changed, even though the function itself may look untouched. With CONFIG_MODVERSIONS enabled (the default on distro kernels), every out-of-tree module embeds the CRC of each symbol it imports at build time; insmod/modprobe reject a module whose embedded CRC disagrees with the running kernel's, with disagrees about version of symbol ext4_iget โ€” a hard load failure for a symbol that unambiguously still exists.

Old/new diff

v1.symvers v2.symvers
0x8f3a2c11 ext4_iget fs/ext4/ext4 EXPORT_SYMBOL_GPL EXT4 0xd41d8cd9 ext4_iget fs/ext4/ext4 EXPORT_SYMBOL_GPL EXT4

(both files also carry an unrelated, unchanged ext4_mark_iloc_dirty line โ€” abicheck correctly leaves it out of the finding.)

abicheck command

abicheck compare v1.symvers v2.symvers

Expected abicheck finding

Verdict: BREAKING (exit 4)

- kabi_crc_changed: Kernel symbol CRC changed: ext4_iget (0x8f3a2c11 -> 0xd41d8cd9)
  -- modversions will reject the module
  > A kernel-exported symbol's genksyms CRC changed. Even though the symbol
    still exists, CONFIG_MODVERSIONS embeds the old CRC in out-of-tree
    modules and the loader rejects the module ('disagrees about version of
    symbol') -- the type signature behind the symbol changed.

Minimum evidence

min_evidence: L0 โ€” the two Module.symvers manifests are read directly (one <CRC>\t<Symbol>\t<Module>\t<Export Type>\t<Namespace> line per exported symbol); no kernel build and no compiler are needed.

Why abicheck catches it

abicheck parses each Module.symvers line into its five columns and diffs by symbol name across the two manifests. A CRC delta with every other column identical is exactly kabi_crc_changed โ€” the tool never needs to know which type changed, only that the hash summarizing "everything ext4_iget's signature transitively touches" no longer matches.

Real-world deployment scenario

This is what a CI job diffing two kernel build trees' Module.symvers across a kernel update sees โ€” e.g. a distro's kABI-stability gate (RHEL-style kABI whitelists) checked before publishing a kernel update, or an out-of-tree driver vendor verifying their module still loads against an upcoming kernel release before shipping it. A plain nm/symbol-presence diff of the running kernel would report no change at all; only reading the CRC column catches the break before a customer's insmod fails in the field.

Safe redesign

Treat any change to a struct or typedef reachable from an EXPORT_SYMBOL* function's signature as a kABI break, even when the function itself is untouched โ€” the CRC is transitive. If a field genuinely must change, add a new exported accessor rather than changing the layout an existing one depends on, and gate merges on Module.symvers diffing (not just symbol-presence checks) for any kernel ABI series with a stability guarantee.

Cross-tool comparison

abidiff/abi-compliance-checker diff DWARF-carrying compiled binaries (.so/kernel modules with debug info); neither reads Module.symvers directly, so there is no equivalent invocation of either tool for this fixture pair.

References


Source files

  • v1.symvers
  • v2.symvers

See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.