
kpatch livepatch build for CVE-2026-99999 on AlmaLinux 8/9 GA kernels
Fixes CVE-2026-99999 (PwnEscape) on a running AlmaLinux host without a reboot, for the kernels listed below whose modules are released.
curl -fsSL https://raw.githubusercontent.com/nsrg-fmlorg/kpatch-alma-cve-2026-99999/main/scripts/livepatch.sh | sudo bash -s -- apply
The script picks the module for the running kernel (uname -r), and first
checks the distribution, Secure Boot, and the module's vermagic and
SHA-256. If the kernel has no released module or any check fails, it
changes nothing. check instead of apply only checks; status and
remove show and undo it.
.ko yourself: docs/BUILD.mdA livepatch does not survive a reboot. The real fix is a fixed kernel,
which AlmaLinux now ships for the latest minor of each major: from
4.18.0-553.177.1.el8_10 (with AlmaLinux's own patch), 5.14.0-687.59.1.el9_8
and 6.12.0-211.67.1.el10_2 on (checked 2026-10-27). On those minors,
dnf update and a reboot fix a host.
The table lists the GA kernel of every minor release, i.e. the lowest kernel version in that minor's BaseOS repository. x86_64 only; the AlmaLinux 10 x86_64_v2 variant is not covered.
Every other kernel in vault is released too (2026-10-21, and
4.18.0-553.176.1.el8_10, which came out after, on 2026-10-30): 370 in all,
listed in tools/kernels.tsv, every kernel whose source and debuginfo
are in vault, all of whose ports match AlmaLinux's patch. The one-line
command covers all of them (scripts/livepatch.sh holds each module's
SHA-256), and was tested with that command on each kernel in a VM:
all 370 passed (2026-10-21; 553.176.1 on 2026-10-30, run 40911368593).
| Minor | Kernel | Tool | Status (2026-10-20) |
|---|---|---|---|
| 8.3 | 4.18.0-240.el8 | kpatch-build | released, load-tested |
| 8.4 | 4.18.0-305.el8 | kpatch-build | released, load-tested |
| 8.5 | 4.18.0-348.el8 | kpatch-build | released, load-tested |
| 8.6 | 4.18.0-372.9.1.el8 | kpatch-build | released, load-tested |
| 8.7 | 4.18.0-425.3.1.el8 | kpatch-build | released, load-tested |
| 8.8 | 4.18.0-477.10.1.el8_8 | kpatch-build | released, load-tested |
| 8.9 | 4.18.0-513.5.1.el8_9 | kpatch-build | released, load-tested |
| 8.10 | 4.18.0-553.el8_10 | kpatch-build | released, load-tested |
| 9.0 | 5.14.0-70.13.1.el9_0 | kpatch-build (gcc 11.3.1-2.1, see below) | released, load-tested |
| 9.1 | 5.14.0-162.6.1.el9_1 | kpatch-build | released, load-tested |
| 9.2 | 5.14.0-284.11.1.el9_2 | kpatch-build | released, load-tested |
| 9.3 | 5.14.0-362.8.1.el9_3 | kpatch-build | released, load-tested |
| 9.4 | 5.14.0-427.13.1.el9_4 | kpatch-build | released, load-tested |
| 9.5 | 5.14.0-503.11.1.el9_5 | kpatch-build | released, load-tested |
| 9.6 | 5.14.0-570.12.1.el9_6 | kpatch-build | released, load-tested |
| 9.7 | 5.14.0-611.5.1.el9_7 | kpatch-build | released, load-tested |
| 9.8 | 5.14.0-687.5.1.el9_8 | kpatch-build | released, load-tested |
| 10.0 | 6.12.0-55.9.1.el10_0 | klp-build (from 10.2, own objtool) | released, load-tested |
| 10.1 | 6.12.0-124.8.1.el10_1 | klp-build (from 10.2) | released, load-tested |
| 10.2 | 6.12.0-211.7.1.el10_2 | klp-build | released, load-tested |
Only released modules can be applied with the one-line command. Each
one was loaded into its kernel in a VM with that command, from the
release (GA kernels 2026-10-20, run 39349248568; every kernel 2026-10-21, one loadtest run per minor; all 370 RESULT: PASS).
9.0's GA kernel was built with gcc 11.3.1-2, which was never published;
it is built with 11.3.1-2.1 from 9.1, whose compiler reports the same
version string, and kpatch-build's compiler check is skipped. 9.1's GA
kernel records the same 11.3.1-2 and passes the check with that same
11.3.1-2.1. Built with it, the seven objects the patch touches give the
same code as the shipped 9.0 kernel in all 610 functions: name, size,
instructions and operands, with only link-time values set aside
(tools/gcccheck.sh, 2026-10-20, run 39391060481). The same comparison
tells gcc 11.5.0 apart (one function's size differs), and finds 9.1's
GA kernel identical with the same 11.3.1-2.1.
CVE-2026-99999 lets a guest VM, or a local user, make the host kernel's checksum code overwrite an IPv4 header it has already parsed. The upstream fix is torvalds/linux 6785011f8b16, "ipv4: validate checksum_start before completing checksum".
| Path | What it is |
|---|---|
patches/<kernel>.diff | The port for that kernel |
patches/kpatch/<kernel>.diff | The same change in the form fed to kpatch-build (see below) |
patches/upstream-6785011f8b16.diff | The upstream commit |
patches/almalinux-testing/ | AlmaLinux's own patches from its testing kernels, for comparison |
tools/port.py | Regenerates a port from an unpacked kernel tree |
tools/kpatchify.py | Turns a port into its kpatch-build form |
tools/mkdiffs.sh | Makes both forms for every kernel of a minor and checks them against tools/ref/ |
tools/kernels.tsv, tools/select-kernels.py | The kernels CI builds, and which of them a run takes |
tools/klp-overlay.sh, tools/klp-overlay-lds.py, tools/klp-overlay/ | Lends 10.2's klp-build to 10.0 and 10.1 (see PROCEDURE.md) |
tools/klpsymcheck.py | Checks a klp-build module's symbols and CRCs against the shipped kernel |
tools/loadtest.sh, tools/loadtest-guest.sh, tools/csum-probe.sh, tools/csum-inject.py | Load test in a VM; csum-probe/csum-inject reproduce CVE-2026-99999 through a crafted virtio-net frame on a tap, before and after the livepatch |
build.sh | Builds one kernel's module inside almalinux:<major> |
scripts/livepatch.sh | Applies, checks and removes the module on a host; holds the released modules' SHA-256 |
scripts/build-local.sh | Runs build.sh (and the load test) outside CI |
.github/workflows/build.yml | Runs build.sh, per minor or per kernel |
.github/workflows/loadtest.yml | Runs the load test on a build run's modules, or on the releases |
.github/workflows/diffs.yml | Runs tools/mkdiffs.sh for every minor |
tools/gcccheck.sh, tools/gcccheck.py, .github/workflows/gcccheck.yml | Rebuilds the patched objects with a given gcc and compares them function by function with the shipped kernel (for 9.0, below) |
tools/doccheck.py, .github/workflows/docs.yml | Fails when a file under tools/, scripts/ or .github/workflows/ is not named in both READMEs, or a link is broken |
For 8 and 9 the module is built with kpatch-build. For 10 it is built
with the kernel's own scripts/livepatch/klp-build, because 10 enables
CONFIG_X86_KERNEL_IBT, which kpatch-build does not support. Only 10.2
ships klp-build and was built with CONFIG_KLP_BUILD=y; 10.0 and 10.1
borrow the tooling from 10.2's source without changing the kernel's own
code, and 10.0 keeps its own objtool for its objects
(PROCEDURE.md, step 2c). Every klp-build module is
checked against the shipped kernel's symbols and modversions CRCs.