From: chanyoung <ppoo1220@gmail.com>
To: netdev@vger.kernel.org
Cc: John Fastabend <john.fastabend@gmail.com>,
Jakub Kicinski <kuba@kernel.org>,
Sabrina Dubroca <sd@queasysnail.net>,
David Howells <dhowells@redhat.com>,
Shuah Khan <shuah@kernel.org>,
linux-kselftest@vger.kernel.org, chanyoung <ppoo1220@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH net 1/2] tls: don't over-fill the plaintext sk_msg ring in tls_sw_sendmsg_splice()
Date: Sun, 26 Jul 2026 19:55:55 +0900 [thread overview]
Message-ID: <20260726105556.2719227-2-ppoo1220@gmail.com> (raw)
In-Reply-To: <20260726105556.2719227-1-ppoo1220@gmail.com>
tls_sw_sendmsg_splice() appends pages to the open record's plaintext
sk_msg ring with sk_msg_page_add(), which performs no fullness check of
its own, and the loop only tests sk_msg_full() at the bottom of its
do-while.
If the ring is already full when the function is entered, the first
sk_msg_page_add() writes the reserved slot and sk_msg_iter_next() wraps
sg.end around to sg.start. sk_msg_iter_dist() then returns 0, so
sk_msg_full() reports the ring as empty, the loop keeps running, and each
further add overwrites a live entry without putting its page reference
while sg.size keeps growing. sg.size is then larger than the data
reachable by walking the logical [sg.start, sg.end) ring.
tls_push_record() marks the end of the scatterlist at the logical last
entry but passes the inflated msg_pl->sg.size to tls_do_encryption() as
cryptlen, so the AEAD scatterwalk runs past the end-marked entry and
dereferences the NULL returned by sg_next():
BUG: kernel NULL pointer dereference, address: 0000000000000008
CPU: 1 UID: 1000 PID: 204 Comm: exploit Not tainted 7.2.0-rc4+ #1 PREEMPTLAZY
RIP: 0010:memcpy_from_scatterwalk+0x32/0xc0
Call Trace:
<TASK>
skcipher_walk_next+0x1d1/0x2c0
gcm_encrypt_aesni_avx+0x1e9/0x220
bpf_exec_tx_verdict+0x3bb/0x860
tls_sw_sendmsg+0xa1a/0xca0
__sys_sendto+0x1da/0x1f0
do_syscall_64+0xdc/0x520
entry_SYSCALL_64_after_hwframe+0x76/0x7e
</TASK>
An unprivileged user can reach this on a plain loopback TCP socket with
the "tls" ULP attached. A full but unpushed plaintext ring survives
across a syscall through the copy path: sk_msg_clone() returns 0 rather
than -ENOSPC for the frag that makes the ring exactly full, because its
guard is "if (i == src->sg.end && len)" and len reaches 0 as that frag is
added, so full_record is never set and MSG_MORE keeps eor clear. Since
record_room is a byte count, a frag-exhausted ring that holds only a few
hundred bytes still admits the next splice(), which then re-enters
tls_sw_sendmsg_splice() on a full ring.
The caller already handles a ring that becomes full during the splice by
testing sk_msg_full() afterwards and setting full_record to push the
record, so the loop condition only needs to be evaluated before the first
sk_msg_page_add() rather than after it. Turn the do-while into a while
loop: when the ring is full on entry the function returns without adding
anything, the caller pushes the record, and the next iteration of the
caller's loop starts from a fresh, empty ring.
Cc: stable@vger.kernel.org
Fixes: fe1e81d4f73b ("tls/sw: Support MSG_SPLICE_PAGES")
Signed-off-by: Chanyoung Park <ppoo1220@gmail.com>
---
net/tls/tls_sw.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index d4afc90fd79..0c413d05bb1 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -738,7 +738,7 @@ static int tls_sw_sendmsg_splice(struct sock *sk, struct msghdr *msg,
{
struct page *page = NULL, **pages = &page;
- do {
+ while (try_to_copy && !sk_msg_full(msg_pl)) {
ssize_t part;
size_t off;
@@ -758,7 +758,7 @@ static int tls_sw_sendmsg_splice(struct sock *sk, struct msghdr *msg,
sk_mem_charge(sk, part);
*copied += part;
try_to_copy -= part;
- } while (try_to_copy && !sk_msg_full(msg_pl));
+ }
return 0;
}
--
2.43.0
next prev parent reply other threads:[~2026-07-26 10:56 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-26 10:55 [PATCH net 0/2] tls: fix plaintext sk_msg ring over-fill in tls_sw_sendmsg_splice() chanyoung
2026-07-26 10:55 ` chanyoung [this message]
2026-07-27 10:30 ` [PATCH net 1/2] tls: don't over-fill the plaintext sk_msg ring " Sabrina Dubroca
2026-07-27 12:58 ` chanyoung
2026-07-26 10:55 ` [PATCH net 2/2] selftests: tls: add a test for splicing onto a full plaintext record chanyoung
2026-07-27 11:55 ` Sabrina Dubroca
2026-07-27 12:59 ` chanyoung
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260726105556.2719227-2-ppoo1220@gmail.com \
--to=ppoo1220@gmail.com \
--cc=dhowells@redhat.com \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=sd@queasysnail.net \
--cc=shuah@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.