FlawOpen

flawopen.com/Teardowns/cve-2026-31431-linux-algif-aead-copy-fail

● CVE-2026-31431 · CVSS 7.8 · High
FlawOpen Security Research

CVE-2026-31431: Linux Copy Fail Kernel Flaw

Copy Fail is a local privilege-escalation flaw in the Linux AF_ALG AEAD path. An in-place processing optimization confused source and destination mappings; the upstream fix restores out-of-place operation, and CISA lists the CVE in KEV.[1], [2], [5]

💡 Plain English Explainer (ELI5)

Imagine a librarian told to annotate a photocopy, but the copy machine's shortcut sends the pencil to the original book instead. The crypto path's in-place shortcut let a write intended for a destination land in a different mapped page. The kernel fix stops treating those mappings as interchangeable and processes source and destination separately.[3], [8]

Core Concepts & Subsystem Terms

AF_ALG
Linux's userspace cryptography socket interface. A local process can request supported crypto operations through this kernel API.[8], [3]
AEAD
Authenticated Encryption with Associated Data: encryption that also authenticates additional, unencrypted metadata.[8]
algif_aead
The AF_ALG socket implementation for AEAD algorithms, including the vulnerable source/destination handling path.[3]
Page cache
The kernel's in-memory cache of file contents. Writes to a mapped cache page can affect what processes read before a later disk write occurs.[8]
CWE-1288 / CWE-669
NVD lists CWE-1288 with redhat-SADP as the mapping source; Red Hat's page also lists that CWE. The Canadian Centre for Cyber Security alert classifies the issue as CWE-669. These are source-attributed classifications, not interchangeable labels.[11], [7], [5], [9], [10]

Framework mappings

Root Cause Analysis

The 2017 change 72548b093ee3 introduced an in-place optimization in the algif_aead path. In this flow, source and destination can come from different mappings. The authencesn processing path can write scratch data outside the intended output region; with the in-place scatterlist arrangement, the write can land in a page-cache page supplied through splice(). The Linux CVE notice describes the repair as reverting to out-of-place operation while retaining the associated-data copy. Treat the path as a local kernel privilege boundary issue: an attacker needs local access and the vulnerable kernel path enabled. The CVE assigns CVSS 7.8 (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H); it does not describe an unauthenticated remote entry point.[1], [3], [8], [7], [9], [10]

Step-by-Step Attack Flow

Step 1

A local process reaches the crypto socket API

A process with local access requests an AEAD operation through AF_ALG, which dispatches work to algif_aead. No remote request alone reaches this local interface.[8], [7]

Step 2

The data path uses an in-place optimization

The affected implementation arranges source and destination as though they can safely share backing pages, despite their distinct mappings in this operation.[8], [3]

Step 3

A write crosses the intended output boundary

During authencesn processing, scratch handling can write outside the intended output region. The vulnerable scatterlist arrangement can direct those bytes into a page-cache page associated with a spliced file.[8]

Step 4

The kernel restores separate source and destination handling

The fix removes the unnecessary in-place complexity in algif_aead, copies associated data directly, and returns to out-of-place processing.[1], [3]

Source Code: Flaw vs. Secure Implementation

These excerpts are taken from the upstream stable patch for crypto/algif_aead.c. The fix builds a request-specific source scatterlist, copies only the associated data into the receive scatterlist, and passes the TX scatterlist as the crypto source while the receive scatterlist remains the destination. This restores out-of-place processing. The omitted lines allocate and initialize the request scatterlist; the shown fragments are context excerpts, not a standalone compilable function.[3], [2]

Source excerpt: crypto/algif_aead.c (_aead_recvmsg)

UNPATCHED FLAW
/* Before the fix: arrange the crypto operation in-place. */
rsgl_src = areq->first_rsgl.sgl.sg;

if (ctx->enc) {
    memcpy_sglist(areq->first_rsgl.sgl.sg, tsgl_src, processed);
    af_alg_pull_tsgl(sk, processed, NULL, 0);
} else {
    memcpy_sglist(areq->first_rsgl.sgl.sg, tsgl_src, outlen);
    /* Build and chain a TX scatterlist for the authentication tag. */
    areq->tsgl_entries = af_alg_count_tsgl(sk, processed, processed - as);
    /* ... */
}

aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src,
                       areq->first_rsgl.sgl.sg, used, ctx->iv);
HARDENED SECURE PATCH
/* After the fix: retain a per-request source scatterlist. */
processed = used + ctx->aead_assoclen;
areq->tsgl_entries = af_alg_count_tsgl(sk, processed);
/* Allocate and initialize areq->tsgl, then pull the TX pages into it. */
af_alg_pull_tsgl(sk, processed, areq->tsgl);
tsgl_src = areq->tsgl;

/* Copy associated data, but keep source and destination separate. */
rsgl_src = areq->first_rsgl.sgl.sg;
memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen);
aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src,
                       areq->first_rsgl.sgl.sg, used, ctx->iv);

Engineering & System Hardening Checklist

Sources