CVE-2026-45257:FreeBSD kTLS-RX 就地 AES-GCM 解密通过 sendfile(2) EXTPG Mbufs 实现本地提权至 Root
2026-6-10 21:2:0 Author: seclists.org(查看原文) 阅读量:0 收藏

oss-sec logo

oss-sec mailing list archives


From: bumsrakete <bumsrakede () proton me>
Date: Wed, 10 Jun 2026 19:19:28 +0000

## Summary

An unprivileged local user on a default FreeBSD >= 13.0 system (any
PMAP_HAS_DMAP architecture: amd64, arm64, riscv) can write
attacker-influenced bytes into the page-cache page of any file they can
*read*. The write reaches the backing physical page through the kernel
direct map (DMAP) and never traverses the VFS layer, so it bypasses file
permissions, mount options, and `chflags schg`. This yields a reliable
local privilege escalation (shellcode injection into a SUID-root binary)
and persistent on-disk corruption on UFS.

It is the FreeBSD analogue of Linux's Dirty Pipe. Tracked as
CVE-2026-45257 / FreeBSD-SA-26:26.kTLS.

## Website (Of course, it's a LPE bug!)
https://bumsrake.de

## Merchandise
Sold out! Sorry! :(

## Affected versions

Vulnerable (verified or by inspection):
  - FreeBSD 13.0, 13.1, 13.2, 13.3, 13.4
  - FreeBSD 14.0, 14.1, 14.2
  - FreeBSD 15.0-RELEASE (verified on 15.0-RELEASE-p5/amd64)

Not affected:
  - FreeBSD 12.x and earlier

Preconditions are the stock GENERIC defaults: kern.ipc.mb_use_ext_pgs=1
(the boot-time default on every PMAP_HAS_DMAP arch) and a kernel built
with MK_KERN_TLS (default). No extra module, sysctl, hardware, or
privileged group is required. The vulnerable path was introduced around
2020 (commit 3c0e56850511) and first shipped in 13.0 (April 2021).

## Root cause

The bug is page-cache corruption via an attacker-influenced in-kernel
AES-GCM decrypt running in place over M_EXTPG mbufs produced by
sendfile(2). Three individually-correct subsystems compose unsafely:

  (1) sendfile(2) produces vnode-backed EXTPG mbufs.

      sys/kern/kern_sendfile.c:963
          m0 = mb_alloc_ext_pgs(M_WAITOK, sendfile_free_mext_pg, M_RDONLY);

      m_epg_pa[] then holds the physical addresses of the file's actual
      page-cache pages.

  (2) TCP_RXTLS_ENABLE performs no privilege check.

      sys/netinet/tcp_usrreq.c:2222
          case TCP_RXTLS_ENABLE:
              INP_WUNLOCK(inp);
              error = ktls_copyin_tls_enable(sopt, &tls);
              ...
              error = ktls_enable_rx(so, &tls);

      Any unprivileged user can enable software kTLS RX on a TCP socket
      they own and supply the AES-128-GCM key, salt, and rec_seq of their
      choice.

  (3) The decrypt runs in place against the page-cache page.

      sys/opencrypto/criov.c:273
          return (PHYS_TO_DMAP(m->m_epg_pa[i] + pgoff + skip));

      sys/crypto/aesni/aesni.c:599-605 (AES_GCM_decrypt, in==out)
      The "output buffer" is a DMAP pointer at the file's page-cache page;
      the plaintext is written there.

Because plaintext = ciphertext XOR keystream(K, IV), and both the
ciphertext (the file's existing bytes, delivered by sendfile) and K/IV
(the attacker's) are known, the attacker fully controls every byte
written into the page.

## The three incomplete guards

The kernel has three mechanisms that would normally prevent an EXTPG
mbuf from reaching an in-place decrypt; each is bypassable here:

  Guard 1 - mb_unmapped_compress (uipc_sockbuf.c:153, :1441):
    copies EXTPG bytes into a flat mbuf (kern_mbuf.c:859-897), but is
    gated on m_len <= MLEN (~224 on amd64). Sending records with a
    240-byte payload walks past it.

  Guard 2 - mb_unmapped_to_ext (ip_output.c:746): converts EXTPG chains
    when the outbound ifp lacks IFCAP_MEXTPG (true for loopback). But
    _mb_unmapped_to_ext (kern_mbuf.c:940-1077) does not copy bytes; it
    allocates an sf_buf per page, and on these architectures
    sf_buf_kva == PHYS_TO_DMAP(pa). The "mapped" mbuf still points at the
    same physical page.

  Guard 3 - sb_mark_notready (uipc_ktls.c:1183-1207): moves queued data
    from sb_mb into the kTLS decrypt queue sb_mtls with no M_EXTPG check
    at all.

## Exploitation

A rather stable (who would have thought) exploit (bumsrakete.c) is attached.

Flow: the attacker sendfile(2)s the target file into a TCP socket looped
back to itself (lo0), with TCP_RXTLS_ENABLE configured using its own
key/IV. lo0 lacks IFCAP_MEXTPG, so Guard 2 remaps (not copies) the EXTPG
onto the same physical page; the kTLS RX path then decrypts in place into
the page cache.

To produce a record whose on-wire ciphertext equals the file's current
bytes (so GMAC validates) while the decrypt yields chosen plaintext:

    compute_ks(key, salt, iv8, RECORD_W, ks);   /* AES-CTR keystream */
    for (i = 0; i < RECORD_W; i++)
        pt[i] = file_bytes[i] ^ ks[i];          /* so ct == file_bytes */
    gcm_encrypt(key, iv12, aad, sizeof aad,
                pt, RECORD_W, ct, tag);          /* valid tag for wire */

The PoC injects a 36-byte setuid(0)+execve("/bin/sh") shellcode into the
entry of /usr/bin/su (36 records) or any other suid binary, executes it
for the privilege gain, then restores the original bytes.
End-to-end LPE wall time is ~1.5s.

The target's schg,uarch flags do NOT prevent the overwrite and the
corruption persists to disk (UFS). The chflags schg bypass is a nice
bonus.

## Impact

- Local privilege escalation to root (default, reliable, no race).
- Arbitrary modification of any file the attacker can read, bypassing
  permissions, immutable flags, and read-only intent.
- Affects any multi-tenant FreeBSD deployment (jails, hosting,
  containers) with the default capability set.

## Mitigation

The vendor fix is FreeBSD-SA-26:26.kTLS. Subscribe to
freebsd-security-notifications@ and apply when available.

## Timeline

2026-05-13  Reported to secteam () FreeBSD org
2026-06-09  Advisory and patch published; this disclosure; merchandise sale

## Credit

Discovered, analyzed, and reported by Bumsrakete.
Responsibly disclosed to secteam () FreeBSD org.

## References

- CVE-2026-45257
- FreeBSD-SA-26:26.kTLS

Attachment: bumsrakete.c
Description:


Current thread:


文章来源: https://seclists.org/oss-sec/2026/q2/881
如有侵权请联系:admin#unsafe.sh