From: Werner Kasselman <werner@verivus.ai>
To: "bpf@vger.kernel.org" <bpf@vger.kernel.org>,
"netdev@vger.kernel.org" <netdev@vger.kernel.org>
Cc: "andrii@kernel.org" <andrii@kernel.org>,
"ast@kernel.org" <ast@kernel.org>,
"brakmo@fb.com" <brakmo@fb.com>,
"daniel@iogearbox.net" <daniel@iogearbox.net>,
"davem@davemloft.net" <davem@davemloft.net>,
"eddyz87@gmail.com" <eddyz87@gmail.com>,
"edumazet@google.com" <edumazet@google.com>,
"haoluo@google.com" <haoluo@google.com>,
"horms@kernel.org" <horms@kernel.org>,
"john.fastabend@gmail.com" <john.fastabend@gmail.com>,
"jolsa@kernel.org" <jolsa@kernel.org>,
"kpsingh@kernel.org" <kpsingh@kernel.org>,
"kuba@kernel.org" <kuba@kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"linux-kselftest@vger.kernel.org"
<linux-kselftest@vger.kernel.org>,
"martin.lau@linux.dev" <martin.lau@linux.dev>,
"pabeni@redhat.com" <pabeni@redhat.com>,
"sdf@fomichev.me" <sdf@fomichev.me>,
"shuah@kernel.org" <shuah@kernel.org>,
"song@kernel.org" <song@kernel.org>,
"yonghong.song@linux.dev" <yonghong.song@linux.dev>,
"jiayuan.chen@linux.dev" <jiayuan.chen@linux.dev>,
Werner Kasselman <werner@verivus.ai>,
"stable@vger.kernel.org" <stable@vger.kernel.org>
Subject: [PATCH 2/2] bpf: guard sock_ops rtt_min against non-locked tcp_sock
Date: Fri, 17 Apr 2026 02:31:26 +0000 [thread overview]
Message-ID: <20260417023119.3830723-3-werner@verivus.com> (raw)
In-Reply-To: <20260417023119.3830723-1-werner@verivus.com>
sock_ops_convert_ctx_access() reads rtt_min without the
is_locked_tcp_sock guard used for every other tcp_sock field. On
request_sock-backed sock_ops callbacks, sk points at a
tcp_request_sock and the converted load reads past the end of the
allocation.
Reuse SOCK_OPS_LOAD_TCP_SOCK_FIELD() for the rtt_min access and compute
the offset with offsetof(struct minmax_sample, v). This leaves the byte
addressed unchanged from the old sizeof_field(struct minmax_sample, t)
expression, while making rtt_min consistent with every other tcp_sock
field.
This also picks up the same dst_reg == src_reg handling used by the
other guarded field loads. Extend the sock_ops_get_sk selftest with an
rtt_min subtest that checks request_sock-backed !fullsock callbacks read
zero instead of leaking request_sock-adjacent memory.
Found via AST-based call-graph analysis using sqry.
Fixes: 44f0e43037d3 ("bpf: Add support for reading sk_state and more")
Cc: stable@vger.kernel.org
Signed-off-by: Werner Kasselman <werner@verivus.com>
---
net/core/filter.c | 12 +++----
.../bpf/prog_tests/sock_ops_get_sk.c | 9 ++++++
.../selftests/bpf/progs/sock_ops_get_sk.c | 31 +++++++++++++++++++
3 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index e8ad062f63bc..9c43193a5c39 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -10827,14 +10827,12 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
sizeof(struct minmax));
BUILD_BUG_ON(sizeof(struct minmax) <
sizeof(struct minmax_sample));
+ BUILD_BUG_ON(offsetof(struct tcp_sock, rtt_min) +
+ offsetof(struct minmax_sample, v) > S16_MAX);
- *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(
- struct bpf_sock_ops_kern, sk),
- si->dst_reg, si->src_reg,
- offsetof(struct bpf_sock_ops_kern, sk));
- *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg,
- offsetof(struct tcp_sock, rtt_min) +
- sizeof_field(struct minmax_sample, t));
+ off = offsetof(struct tcp_sock, rtt_min) +
+ offsetof(struct minmax_sample, v);
+ SOCK_OPS_LOAD_TCP_SOCK_FIELD(BPF_W, off);
break;
case offsetof(struct bpf_sock_ops, bpf_sock_ops_cb_flags):
diff --git a/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c b/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c
index 343d92c4df30..1aea4c97d5d3 100644
--- a/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c
+++ b/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c
@@ -70,6 +70,15 @@ void test_ns_sock_ops_get_sk(void)
ASSERT_EQ(skel->bss->diff_reg_bug_detected, 0, "diff_reg_bug_not_detected");
}
+ /* Test sock_ops rtt_min access in !fullsock callbacks */
+ if (test__start_subtest("get_rtt_min")) {
+ run_sock_ops_test(cgroup_fd,
+ bpf_program__fd(skel->progs.sock_ops_get_rtt_min));
+ ASSERT_EQ(skel->bss->rtt_min_null_seen, 1, "rtt_min_null_seen");
+ ASSERT_EQ(skel->bss->rtt_min_bug_detected, 0,
+ "rtt_min_bug_not_detected");
+ }
+
sock_ops_get_sk__destroy(skel);
close_cgroup:
close(cgroup_fd);
diff --git a/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c b/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c
index 3a0689f8ce7c..dee07da8901e 100644
--- a/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c
+++ b/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c
@@ -114,4 +114,35 @@ __naked void sock_ops_get_sk_diff_reg(void)
: __clobber_all);
}
+/* sock_ops rtt_min access: different-register, is_locked_tcp_sock == 0 path (TCP_NEW_SYN_RECV). */
+int rtt_min_bug_detected;
+int rtt_min_null_seen;
+
+SEC("sockops")
+__naked void sock_ops_get_rtt_min(void)
+{
+ asm volatile (
+ "r7 = *(u32 *)(r1 + %[is_fullsock_off]);"
+ "r2 = *(u32 *)(r1 + %[rtt_min_off]);"
+ "if r7 != 0 goto 2f;"
+ "if r2 == 0 goto 1f;"
+ "r1 = %[rtt_min_bug_detected] ll;"
+ "r3 = 1;"
+ "*(u32 *)(r1 + 0) = r3;"
+ "goto 2f;"
+ "1:"
+ "r1 = %[rtt_min_null_seen] ll;"
+ "r3 = 1;"
+ "*(u32 *)(r1 + 0) = r3;"
+ "2:"
+ "r0 = 1;"
+ "exit;"
+ :
+ : __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
+ __imm_const(rtt_min_off, offsetof(struct bpf_sock_ops, rtt_min)),
+ __imm_addr(rtt_min_bug_detected),
+ __imm_addr(rtt_min_null_seen)
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
--
2.43.0
next prev parent reply other threads:[~2026-04-17 2:31 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-17 2:31 [PATCH bpf v3 0/2] bpf: fix sock_ops rtt_min OOB read Werner Kasselman
2026-04-17 2:31 ` [PATCH 1/2] bpf: extract SOCK_OPS_LOAD_TCP_SOCK_FIELD from SOCK_OPS_GET_FIELD Werner Kasselman
2026-04-17 2:31 ` Werner Kasselman [this message]
2026-04-20 20:43 ` [PATCH 2/2] bpf: guard sock_ops rtt_min against non-locked tcp_sock Martin KaFai Lau
2026-04-20 22:16 ` [PATCH bpf v4 0/2] " Werner Kasselman
2026-04-20 22:16 ` [PATCH bpf v4 1/2] " Werner Kasselman
2026-04-20 22:16 ` [PATCH bpf v4 2/2] selftests/bpf: cover same-reg sock_ops rtt_min request_sock access Werner Kasselman
2026-04-20 23:00 ` [PATCH bpf v5 0/2] bpf: guard sock_ops rtt_min against non-locked tcp_sock Werner Kasselman
2026-04-20 23:00 ` [PATCH bpf v5 1/2] " Werner Kasselman
2026-04-22 21:03 ` Martin KaFai Lau
2026-04-20 23:00 ` [PATCH bpf v5 2/2] selftests/bpf: cover same-reg sock_ops rtt_min request_sock access Werner Kasselman
2026-04-22 21:11 ` Martin KaFai Lau
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=20260417023119.3830723-3-werner@verivus.com \
--to=werner@verivus.ai \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brakmo@fb.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=haoluo@google.com \
--cc=horms@kernel.org \
--cc=jiayuan.chen@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=stable@vger.kernel.org \
--cc=yonghong.song@linux.dev \
/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.