KernelScan.io

CRITICAL

tls sk_msg Chain OOB

CVE-2026-64047

CVSS 9.8 / 10.0 NVD

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

KernelScan AI7.8HIGH

01

In the Linux kernel, the following vulnerability has been resolved: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg ring When an sk_msg scatterlist ring wraps (sg.end < sg.start), tls_push_record() chains the tail portion of the ring to the head using sg_chain(). An extra entry in the sg array is reserved for this: struct sk_msg_sg { [...] /* The extra two elements: * 1) used for chaining the front and sections when the list becomes * partitioned (e.g. end < start). The crypto APIs require the * chaining; * 2) to chain tailer SG entries after the message. */ struct scatterlist data[MAX_MSG_FRAGS + 2]; The current code uses MAX_SKB_FRAGS + 1 as the ring size: sg_chain(&msg_pl->sg.data[msg_pl->sg.start], MAX_SKB_FRAGS - msg_pl->sg.start + 1, msg_pl->sg.data); This places the chain pointer at sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = data[start + (MAX_SKB_FRAGS - start + 1) - 1] = data[MAX_SKB_FRAGS] instead of the true last entry. This is likely due to a "race" of the commit under Fixes landing close to commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested by Sabrina).

02

Engine v0.4.0

Risk summary

A local user with access to TLS-over-sockmap sockets can trigger an off-by-one error in the scatterlist chain construction when the sk_msg ring wraps around. This can corrupt adjacent kernel heap memory, potentially enabling privilege escalation or denial of service. The bug is reachable by any process that can create and use TLS sockets with BPF sockmap redirection.

Affectednet/tls/tls_sw.c (TLS software crypto send path)

Vulnerability analysis

The root cause is an off-by-one error in the sg_chain() call inside tls_push_record() when the sk_msg scatterlist ring wraps (sg.end < sg.start). The original code computes the chain length as MAX_SKB_FRAGS - msg_pl->sg.start + 1 and passes &msg_pl->sg.data[msg_pl->sg.start] as the source array. This arithmetic places the chain pointer at data[MAX_SKB_FRAGS] rather than at the true last reserved chaining slot (data[MAX_MSG_FRAGS + 1]), because MAX_SKB_FRAGS != MAX_MSG_FRAGS and the offset arithmetic is wrong. The result is that sg_chain() writes the chain link one entry past the intended boundary, potentially corrupting adjacent memory in the sk_msg_sg structure or beyond. The fix replaces the hand-computed offset with sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), msg_pl->sg.data), which correctly uses the full array size and eliminates the off-by-one. The attack surface requires a local process to set up a BPF sockmap with TLS and send data that causes the ring to wrap, which is achievable by an unprivileged user with CAP_NET_ADMIN in a user namespace or a low-privileged local user depending on configuration.

03

BranchIntroducedFixed inPatch commit
6.18—6.18.342fb0dc7e0099
mainline—7.1—
6.1—6.1.175131ef12057d9
7.0—7.0.11285943c6e7ca
5.15—5.15.20984158c299715
5.10—5.10.25847110c3a9ac2
6.6—6.6.14266339b71f105
5.45.4.145.573963a375885
6.12—6.12.92eca989eab4b2