[BUG] module: non-power-of-two sh_addralign is accepted and not honored

Started by Puranam, Ananta Srikar on Nov 7, 2026

open the first message on its own page

Message details and related content
Hi,

I'm Ananta Srikar Puranam, a PhD student at Washington State University.
I'm reporting this bug on behalf of my team: Dr. Swarn Priya and
Dr. Basavesh Ammanaghatta Shivakumar (both Cc'd).

The module loader accepts an allocated ELF section whose sh_addralign is
not zero, one, or a power of two, and then places the section at an
address that does not satisfy the declared alignment.  ELF requires
sh_addralign to be 0, 1, or a positive power of two, but nothing in the
section-header validation checks it.

Trigger
=======

A matched pair built from one minimal external module whose only data
is an 8-byte-aligned u64 in .data:

  control.ko  .data sh_addralign = 8   (as built)
  invalid.ko  .data sh_addralign = 5   (only that header field changed;
                                        the files differ in one byte)

The module's init function prints the live address of the object and
its remainder modulo 5 and modulo 8.

Observed (current mainline, x86_64)
===================================

  control (sh_addralign=8):
    module_align_repro: address=ffffffffc03f6010 remainder_mod_5=2
                        remainder_mod_8=0 value=7
  invalid (sh_addralign=5):
    insmod exit status: 0
    module_align_repro: address=ffffffffc03f6010 remainder_mod_5=2
                        remainder_mod_8=0 value=7

(each message is one line in dmesg; wrapped here)

The invalid module loads, and its section address is not a multiple of
the declared alignment.  There is no oops, warning, or other kernel
message.

Tested
======

  - Mainline a91337fb5e8e ("Merge tag 'configfs-7.4-rc2' ..."),
    7.4.0-rc1-00590-ga91337fb5e8e, x86_64 under KVM:
      invalid twin accepted with the alignment not honored in 3/3 loads;
      control loaded 8-byte aligned in 3/3
  - Earlier validation on the same commit (separate build and guest):
    invalid twin accepted at ffffffffa0201010, remainder 4 modulo 5.

Cause
=====

The section layout in module_get_offset_and_type() does:

        offset = ALIGN(mod->mem[type].size, sechdr->sh_addralign ?: 1);

ALIGN() is mask-based and assumes a power of two:
((x) + (a - 1)) & ~(a - 1).  For a = 5 this is (x + 4) & ~4, which only
clears bit 2, so the result is not, in general, a multiple of 5.
elf_validity_cache_sechdrs() validates section types, offsets and
sizes, but never checks sh_addralign, so the value reaches ALIGN()
unchecked.

The same unchecked value is also used for the per-cpu section
(percpu_modalloc()), the kallsyms layout (kernel/module/kallsyms.c), and
codetag sections.  I have only exercised the ordinary .data layout path.

This behavior is already present in the initial git import,
1da177e4c3f4 ("Linux-2.6.12-rc2").

Impact
======

Triggering requires CONFIG_MODULES=y and permission to load a module
(CAP_SYS_MODULE).  I observed a successful load with an alignment the
loader does not honor, not a crash, memory corruption, or an
unprivileged boundary crossing.  Per
Documentation/process/threat-model.rst I am treating this as an ELF
validation and loader correctness bug, not a vulnerability.  Standard
toolchains do not emit such values; the input is a malformed module.

Setup
=====

  Host:       Ubuntu 26.04.1 LTS, x86_64
  Toolchain:  Ubuntu GCC 15.2.0 / GNU ld 2.46 (built with O=)
  Config:     x86_64_defconfig plus kernel/configs/kvm_guest.config,
              resolved with olddefconfig; no other changes
              (full .config available)
  Module:     out-of-tree, built with M= against the same build tree;
              the invalid twin is the built .ko with only .data's
              sh_addralign rewritten from 8 to 5
  QEMU:       qemu-system-x86_64 10.2.1 with KVM, -smp 16 -m 8G
  Guest:      Ubuntu 26.04 amd64 rootfs (debootstrap); modules loaded
              with insmod over SSH

The source reproducer (module and header-patching script) is available
privately on request.  Per Documentation/process/security-bugs.rst I
have not posted it to the list.

Fix
===

A proposed patch rejects a nonzero sh_addralign that is not a power of
two in elf_validity_cache_sechdrs(), before any layout or allocation,
with -ENOEXEC and:

  Invalid ELF section alignment 5 in section 9

On a91337fb5e8e with the patch applied (x86_64 KVM), the control still
loaded and the invalid twin was rejected with ENOEXEC, with no oops or
warning.  I will send it as a separate patch.

Tool transparency
=================

The root-cause analysis, original reproducer and proposed fix were
prepared with the help of an AI coding assistant (OpenAI Codex).  The
QEMU/KVM reproduction environment and the reproducer used for the
results above were set up with Anthropic's Claude Code.  I re-ran the
reproduction myself and have checked the statements in this report.

Thanks,
Srikar
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help