[Devel] [PATCH hci-8.1 v2 0/2] mm, binfmt_elf: two fixes also posted to mainline
Konstantin Khorenko
khorenko at virtuozzo.com
Wed Nov 4 21:05:39 MSK 2026
Two independent fixes for bugs that mainline has as well. Both are
posted to mainline; the backport notes name what differs in this tree.
The MADV_DOEXEC series apply on top of this one, in this order:
- mm: keep DMA-pinned MADV_DOEXEC memory working across exec
- mm, exec: fix the MADV_DOEXEC code we carry from Oracle
- mm: allow MADV_DOEXEC on VFIO BAR mappings, which relies on patch 1
- selftests/mm: broader MADV_DOEXEC coverage
Mainline
========
- Patch 1 is patch 1/2 of "mm/huge_memory: fix the copy of special
PMDs at fork", v3:
https://lore.kernel.org/r/20261014-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v3-0-85eaec8417f6@virtuozzo.com
Sashiko review:
https://sashiko.dev/#/patchset/20261014-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v3-0-85eaec8417f6@virtuozzo.com
The Sashiko review of v1 found the ppc64 issue that patch 2/2 there
fixes:
https://sashiko.dev/#/patchset/20261014-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v1-1-d225c60bc316@virtuozzo.com
- Patch 2 is "binfmt_elf: return the real error when program headers
cannot be loaded", v1:
https://lore.kernel.org/r/20261014-b4-prep-vstor-149847-binfmt_elf-enomem-load-elf-phdrs-v1-1-f39c74d55e42@virtuozzo.com
Sashiko review:
https://sashiko.dev/#/patchset/20261014-b4-prep-vstor-149847-binfmt_elf-enomem-load-elf-phdrs-v1-1-f39c74d55e42@virtuozzo.com
Kees Cook asked for a patch that changes the errno and nothing else:
https://lore.kernel.org/r/202610142140.D483AE26DF@keescook
This version does that; the mainline v2 is not posted yet.
Patch 1: copy_huge_pmd() recheck
================================
fork copies a special (PFN) huge PMD from a value read without the page
table lock. vfio-pci zaps its BAR mappings with unmap_mapping_range(),
which takes no mmap lock, when device memory is disabled or the device
is reset. A fork that races with that zap leaves the child with a BAR
mapping the zap removed: the child keeps reaching MMIO that vfio-pci has
disabled instead of getting SIGBUS. The series "mm: allow MADV_DOEXEC on
VFIO BAR mappings" copies these PMDs on every live-update exec.
In mainline this patch is now the first of two. The second deposits a
page table for the copied PMD on ppc64 in hash mode; it is not needed
here, as this tree has no huge pfnmap support on ppc64.
Patch 2: the real error from load_elf_phdrs()
=============================================
load_elf_phdrs() returns NULL on any failure, and load_elf_binary()
turns that into a fixed error: -ENOEXEC for the executable, -ELIBBAD
for its interpreter. The real cause is lost:
cause really execve() returns
------------------------------------- ---------- ----------------
bad e_phentsize, e_phnum 0 or too big bad file ENOEXEC (right)
file ends before the header table bad file ENOEXEC (right)
kmalloc() of the table fails ENOMEM ENOEXEC (wrong)
kernel_read() fails EIO/ENOMEM ENOEXEC (wrong)
For the interpreter every row gives ELIBBAD.
ENOEXEC says the file is not an executable, which is a property of the
file, not a transient failure:
- glibc's execvp() and execlp() take ENOEXEC as "not a binary" and run
the ELF file with /bin/sh, which reports a binary it cannot execute
instead of the ENOMEM or EIO.
- search_binary_handler() tries the next binary format instead of
returning the error.
- For the interpreter the caller gets ELIBBAD, "Accessing a corrupted
shared library", about an ld.so that is fine.
When it happens here: this tree lacks the v6.17 change that lets the
table grow past ELF_MIN_ALIGN, so the allocation fails in practice only
under fault injection; the read fails with an I/O error, or with
-ENOMEM when the page cache cannot take the pages.
Where it came from:
- Until commit 6a8d38945cf4 ("binfmt_elf: Hoist ELF program header
loading to a function") load_elf_binary() returned -ENOMEM and the
read error. That commit documented an ERR_PTR return but returned
NULL; commit cfc46ca4fdca later fixed the comment, not the code.
- Commit a9d9ef133f44 ("binfmt_elf: load interpreter program headers
earlier") gave the interpreter's headers the same NULL check, and with
it -ELIBBAD.
Testing
=======
On a KVM guest with this series and the four MADV_DOEXEC series on top
of it, release and debug kernels:
- a fork-vs-revoke reproducer on a vfio-pci BAR (QXL in no-IOMMU mode):
no stale child mapping; on mainline the same reproducer with a delay
in the window shows the bug and that the patch closes it;
- failslab sweep over one execve(): ENOMEM instead of ENOEXEC/ELIBBAD,
execvp() no longer falls back to /bin/sh; truncated tables and
e_phoff = 2^63 still give ENOEXEC/ELIBBAD;
- selftests/exec, the MADV_DOEXEC selftests, gup_test, a Container
start/exec/stop.
https://virtuozzo.atlassian.net/browse/VSTOR-150144
Assisted-by: LLM
---
Changes in v2:
- Patch 2: change the errno only, as asked in mainline review. A short
read is no longer read on to get the error behind it: it gives
ENOEXEC/ELIBBAD, as before the patch. The table is read with
kernel_read() directly, as elf_read() turns a short read into EIO.
- Assisted-by moved from the patches to the cover letter.
- Link to v1: http://lore.virtuozzo.com/20261014-b4-prep-khorenko-vstor-149847-1-upstream-fixes-v1-0-7fde9ffbebe9@virtuozzo.com
---
Konstantin Khorenko (2):
mm/huge_memory: recheck a special PMD under the lock in copy_huge_pmd()
binfmt_elf: return the real error when program headers cannot be loaded
fs/binfmt_elf.c | 39 ++++++++++++++++++++++++---------------
mm/huge_memory.c | 23 ++++++++++++++++-------
2 files changed, 40 insertions(+), 22 deletions(-)
---
base-commit: defa968cbe8c38f1ff0231042dee07f00d27b2c9
change-id: 20261014-b4-prep-khorenko-vstor-149847-1-upstream-fixes-4bb22a75a079
Best regards,
--
Konstantin Khorenko,
Virtuozzo Linux Kernel Team
More information about the Devel
mailing list