Merge branch 'tls-fix-plaintext-sk_msg-ring-over-fill'

chanyoung says:

====================
tls: fix plaintext sk_msg ring over-fill

An unprivileged user can oops the kernel by splicing into a kTLS socket
whose open record already has a full plaintext sk_msg ring.  Reproduced on
net (53658c6f36) with a stock config, no KASAN.

Patch 2 oopses an unpatched kernel and passes with patch 1 applied.
====================

Link: https://patch.msgid.link/20260804052837.49015-1-ppoo1220@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-08-06 09:01:56 -07:00
2 changed files with 51 additions and 0 deletions

View File

@@ -832,6 +832,14 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;
/* open record may be full if we couldn't push it in the last sendmsg call */
if (sk_msg_full(msg_pl)) {
full_record = true;
sk_msg_trim(sk, msg_en,
msg_pl->sg.size + prot->overhead_size);
goto copied;
}
alloc_encrypted:
ret = tls_alloc_encrypted_msg(sk, required_size);
if (ret) {
@@ -921,6 +929,12 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
msg_pl, try_to_copy);
if (ret < 0)
goto trim_sgl;
if (sk_msg_full(msg_pl)) {
full_record = true;
sk_msg_trim(sk, msg_en,
msg_pl->sg.size + prot->overhead_size);
}
}
/* Open records defined only if successfully copied, otherwise

View File

@@ -835,6 +835,43 @@ TEST_F(tls, send_and_splice)
EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
}
TEST_F(tls, splice_onto_full_record)
{
char mem_send[4608];
char mem_recv[4608];
int frag_len = 100;
int nfrags, i, off;
int p[2];
memrnd(mem_send, sizeof(mem_send));
ASSERT_GE(pipe(p), 0);
for (nfrags = 16; nfrags <= 44; nfrags++) {
for (i = 0, off = 0; i < nfrags; i++, off += frag_len) {
EXPECT_EQ(write(p[1], mem_send + off, frag_len), frag_len);
EXPECT_EQ(splice(p[0], NULL, self->fd, NULL, frag_len,
SPLICE_F_MORE), frag_len);
}
EXPECT_EQ(send(self->fd, mem_send + off, 1, MSG_MORE), 1);
off++;
EXPECT_EQ(write(p[1], mem_send + off, frag_len), frag_len);
EXPECT_EQ(splice(p[0], NULL, self->fd, NULL, frag_len,
SPLICE_F_MORE), frag_len);
off += frag_len;
EXPECT_EQ(send(self->fd, mem_send + off, 1, 0), 1);
off++;
EXPECT_EQ(recv(self->cfd, mem_recv, off, MSG_WAITALL), off);
EXPECT_EQ(memcmp(mem_send, mem_recv, off), 0);
}
close(p[0]);
close(p[1]);
}
TEST_F(tls, splice_to_pipe)
{
int send_len = TLS_PAYLOAD_MAX_LEN;