* [PATCH bpf-next v1 0/2] Fix for untrusted BTF pointer writes
@ 2026-07-07 19:02 Kumar Kartikeya Dwivedi
2026-07-07 19:02 ` [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers Kumar Kartikeya Dwivedi
2026-07-07 19:02 ` [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression Kumar Kartikeya Dwivedi
0 siblings, 2 replies; 8+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-07 19:02 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team
When using custom btf_struct_access() callbacks, we miss rejecting
unstrusted BTF pointer writes. Fix and add a selftest for coverage.
Kumar Kartikeya Dwivedi (1):
selftests/bpf: Add untrusted BTF write regression
Nicholas Dudar (1):
bpf: Reject writes through untrusted BTF pointers
kernel/bpf/verifier.c | 8 ++++--
.../selftests/bpf/prog_tests/bpf_tcp_ca.c | 12 +++++++++
.../bpf/progs/tcp_ca_untrusted_btf_write.c | 26 +++++++++++++++++++
3 files changed, 44 insertions(+), 2 deletions(-)
create mode 100644 tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
base-commit: f425a0443b7f0221a4b34f6acc0c2924bf5877f2
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers
2026-07-07 19:02 [PATCH bpf-next v1 0/2] Fix for untrusted BTF pointer writes Kumar Kartikeya Dwivedi
@ 2026-07-07 19:02 ` Kumar Kartikeya Dwivedi
2026-07-07 19:48 ` bot+bpf-ci
2026-07-07 22:10 ` Amery Hung
2026-07-07 19:02 ` [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression Kumar Kartikeya Dwivedi
1 sibling, 2 replies; 8+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-07 19:02 UTC (permalink / raw)
To: bpf
Cc: Nicholas Dudar, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman, Emil Tsalapatis, kkd,
kernel-team
From: Nicholas Dudar <main.kalliope@gmail.com>
check_ptr_to_btf_access() lets program-type btf_struct_access callbacks
validate writes before the default BTF access path rejects non-read
accesses. That bypasses the read-only policy for untrusted BTF pointers
created by helpers such as bpf_rdonly_cast().
Reject non-read accesses through PTR_UNTRUSTED BTF pointers at the
common entry point, before the callback branch to handle all cases.
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
kernel/bpf/verifier.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3193b473762b..7cf555a7026c 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5813,6 +5813,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
return -EACCES;
}
+ if (atype != BPF_READ && (type_flag(reg->type) & PTR_UNTRUSTED)) {
+ verbose(env, "only read is supported\n");
+ return -EACCES;
+ }
+
if (env->ops->btf_struct_access && !type_is_alloc(reg->type) && atype == BPF_WRITE) {
if (!btf_is_kernel(reg->btf)) {
verifier_bug(env, "reg->btf must be kernel btf");
@@ -5825,8 +5830,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
reg_arg_name(env, argno), tname, off, size);
} else {
/* Writes are permitted with default btf_struct_access for
- * program allocated objects (which always have id > 0),
- * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
+ * program allocated objects (which always have id > 0).
*/
if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
verbose(env, "only read is supported\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression
2026-07-07 19:02 [PATCH bpf-next v1 0/2] Fix for untrusted BTF pointer writes Kumar Kartikeya Dwivedi
2026-07-07 19:02 ` [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers Kumar Kartikeya Dwivedi
@ 2026-07-07 19:02 ` Kumar Kartikeya Dwivedi
2026-07-07 22:31 ` Amery Hung
1 sibling, 1 reply; 8+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-07 19:02 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team
Add a TCP congestion-control struct_ops load test for a write through a
BTF pointer produced by bpf_rdonly_cast().
The test expects the verifier to reject the program before the TCP CA
btf_struct_access callback can whitelist the tcp_sock field write.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
.../selftests/bpf/prog_tests/bpf_tcp_ca.c | 12 +++++++++
.../bpf/progs/tcp_ca_untrusted_btf_write.c | 26 +++++++++++++++++++
2 files changed, 38 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
index fe30181e6336..eb05fc82f81b 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
@@ -14,6 +14,7 @@
#include "tcp_ca_incompl_cong_ops.skel.h"
#include "tcp_ca_unsupp_cong_op.skel.h"
#include "tcp_ca_kfunc.skel.h"
+#include "tcp_ca_untrusted_btf_write.skel.h"
#include "bpf_cc_cubic.skel.h"
static const unsigned int total_bytes = 10 * 1024 * 1024;
@@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)
tcp_ca_kfunc__destroy(skel);
}
+static void test_untrusted_btf_write(void)
+{
+ struct tcp_ca_untrusted_btf_write *skel;
+
+ skel = tcp_ca_untrusted_btf_write__open_and_load();
+ ASSERT_ERR_PTR(skel, "tcp_ca_untrusted_btf_write__open_and_load");
+ tcp_ca_untrusted_btf_write__destroy(skel);
+}
+
static void test_cc_cubic(void)
{
struct cb_opts cb_opts = {
@@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)
test_link_replace();
if (test__start_subtest("tcp_ca_kfunc"))
test_tcp_ca_kfunc();
+ if (test__start_subtest("untrusted_btf_write"))
+ test_untrusted_btf_write();
if (test__start_subtest("cc_cubic"))
test_cc_cubic();
if (test__start_subtest("dctcp_autoattach_map"))
diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
new file mode 100644
index 000000000000..eda4697aac80
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "bpf_tracing_net.h"
+#include <bpf/bpf_core_read.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+SEC("struct_ops")
+void BPF_PROG(untrusted_btf_write_init, struct sock *sk)
+{
+ struct tcp_sock *tp;
+ int v = 1;
+ void *p;
+
+ p = bpf_rdonly_cast(&v, 0);
+ tp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));
+ tp->snd_cwnd = 1;
+}
+
+SEC(".struct_ops")
+struct tcp_congestion_ops untrusted_btf_write = {
+ .init = (void *)untrusted_btf_write_init,
+ .name = "bpf_ro_btf",
+};
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers
2026-07-07 19:02 ` [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers Kumar Kartikeya Dwivedi
@ 2026-07-07 19:48 ` bot+bpf-ci
2026-07-07 22:10 ` Amery Hung
1 sibling, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-07-07 19:48 UTC (permalink / raw)
To: memxor, bpf
Cc: main.kalliope, ast, andrii, daniel, eddyz87, emil, kkd,
kernel-team, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1250 bytes --]
> check_ptr_to_btf_access() lets program-type btf_struct_access callbacks
> validate writes before the default BTF access path rejects non-read
> accesses. That bypasses the read-only policy for untrusted BTF pointers
> created by helpers such as bpf_rdonly_cast().
>
> Reject non-read accesses through PTR_UNTRUSTED BTF pointers at the
> common entry point, before the callback branch to handle all cases.
>
> Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This fixes a write path that bypassed the read-only policy for untrusted
BTF pointers, but there is no Fixes: tag.
The write-dispatch branch that took precedence over the untrusted
read-only check in check_ptr_to_btf_access(), along with the "but not for
untrusted PTR_TO_BTF_ID | MEM_ALLOC" comment that this patch removes, was
added when program allocated objects support was introduced.
Should this include:
Fixes: 282de143ead9 ("bpf: Introduce allocated objects support")
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/28892378159
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers
2026-07-07 19:02 ` [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers Kumar Kartikeya Dwivedi
2026-07-07 19:48 ` bot+bpf-ci
@ 2026-07-07 22:10 ` Amery Hung
1 sibling, 0 replies; 8+ messages in thread
From: Amery Hung @ 2026-07-07 22:10 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: bpf, Nicholas Dudar, Alexei Starovoitov, Andrii Nakryiko,
Daniel Borkmann, Eduard Zingerman, Emil Tsalapatis, kkd,
kernel-team
On Tue, Jul 7, 2026 at 12:02 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> From: Nicholas Dudar <main.kalliope@gmail.com>
>
> check_ptr_to_btf_access() lets program-type btf_struct_access callbacks
> validate writes before the default BTF access path rejects non-read
> accesses. That bypasses the read-only policy for untrusted BTF pointers
> created by helpers such as bpf_rdonly_cast().
>
> Reject non-read accesses through PTR_UNTRUSTED BTF pointers at the
> common entry point, before the callback branch to handle all cases.
>
> Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
> ---
> kernel/bpf/verifier.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 3193b473762b..7cf555a7026c 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5813,6 +5813,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
> return -EACCES;
> }
>
> + if (atype != BPF_READ && (type_flag(reg->type) & PTR_UNTRUSTED)) {
> + verbose(env, "only read is supported\n");
> + return -EACCES;
> + }
> +
> if (env->ops->btf_struct_access && !type_is_alloc(reg->type) && atype == BPF_WRITE) {
> if (!btf_is_kernel(reg->btf)) {
> verifier_bug(env, "reg->btf must be kernel btf");
> @@ -5825,8 +5830,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
> reg_arg_name(env, argno), tname, off, size);
> } else {
> /* Writes are permitted with default btf_struct_access for
> - * program allocated objects (which always have id > 0),
> - * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
> + * program allocated objects (which always have id > 0).
> */
> if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
> verbose(env, "only read is supported\n");
> --
> 2.53.0
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression
2026-07-07 19:02 ` [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression Kumar Kartikeya Dwivedi
@ 2026-07-07 22:31 ` Amery Hung
2026-07-07 22:36 ` Kumar Kartikeya Dwivedi
0 siblings, 1 reply; 8+ messages in thread
From: Amery Hung @ 2026-07-07 22:31 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team
On Tue, Jul 7, 2026 at 12:02 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> Add a TCP congestion-control struct_ops load test for a write through a
> BTF pointer produced by bpf_rdonly_cast().
>
> The test expects the verifier to reject the program before the TCP CA
> btf_struct_access callback can whitelist the tcp_sock field write.
>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
> .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 12 +++++++++
> .../bpf/progs/tcp_ca_untrusted_btf_write.c | 26 +++++++++++++++++++
> 2 files changed, 38 insertions(+)
> create mode 100644 tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
> index fe30181e6336..eb05fc82f81b 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
> @@ -14,6 +14,7 @@
> #include "tcp_ca_incompl_cong_ops.skel.h"
> #include "tcp_ca_unsupp_cong_op.skel.h"
> #include "tcp_ca_kfunc.skel.h"
> +#include "tcp_ca_untrusted_btf_write.skel.h"
> #include "bpf_cc_cubic.skel.h"
>
> static const unsigned int total_bytes = 10 * 1024 * 1024;
> @@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)
> tcp_ca_kfunc__destroy(skel);
> }
>
> +static void test_untrusted_btf_write(void)
> +{
> + struct tcp_ca_untrusted_btf_write *skel;
> +
> + skel = tcp_ca_untrusted_btf_write__open_and_load();
> + ASSERT_ERR_PTR(skel, "tcp_ca_untrusted_btf_write__open_and_load");
> + tcp_ca_untrusted_btf_write__destroy(skel);
> +}
> +
> static void test_cc_cubic(void)
> {
> struct cb_opts cb_opts = {
> @@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)
> test_link_replace();
> if (test__start_subtest("tcp_ca_kfunc"))
> test_tcp_ca_kfunc();
> + if (test__start_subtest("untrusted_btf_write"))
> + test_untrusted_btf_write();
> if (test__start_subtest("cc_cubic"))
> test_cc_cubic();
> if (test__start_subtest("dctcp_autoattach_map"))
> diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
> new file mode 100644
> index 000000000000..eda4697aac80
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
> @@ -0,0 +1,26 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "bpf_tracing_net.h"
> +#include <bpf/bpf_core_read.h>
> +#include <bpf/bpf_helpers.h>
> +#include <bpf/bpf_tracing.h>
> +
> +char _license[] SEC("license") = "GPL";
> +
> +SEC("struct_ops")
> +void BPF_PROG(untrusted_btf_write_init, struct sock *sk)
> +{
> + struct tcp_sock *tp;
> + int v = 1;
> + void *p;
> +
> + p = bpf_rdonly_cast(&v, 0);
> + tp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));
Do we need two bpf_rdonly_cast()? I tested the following and it also works:
tp = bpf_rdonly_cast(&v, bpf_core_type_id_kernel(struct tcp_sock));
> + tp->snd_cwnd = 1;
> +}
> +
> +SEC(".struct_ops")
> +struct tcp_congestion_ops untrusted_btf_write = {
> + .init = (void *)untrusted_btf_write_init,
> + .name = "bpf_ro_btf",
> +};
> --
> 2.53.0
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression
2026-07-07 22:31 ` Amery Hung
@ 2026-07-07 22:36 ` Kumar Kartikeya Dwivedi
2026-07-07 22:58 ` Amery Hung
0 siblings, 1 reply; 8+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-07 22:36 UTC (permalink / raw)
To: Amery Hung, Kumar Kartikeya Dwivedi
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team
On Wed Jul 8, 2026 at 12:31 AM CEST, Amery Hung wrote:
> On Tue, Jul 7, 2026 at 12:02 PM Kumar Kartikeya Dwivedi
> <memxor@gmail.com> wrote:
>>
>> Add a TCP congestion-control struct_ops load test for a write through a
>> BTF pointer produced by bpf_rdonly_cast().
>>
>> The test expects the verifier to reject the program before the TCP CA
>> btf_struct_access callback can whitelist the tcp_sock field write.
>>
>> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
>> ---
>> .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 12 +++++++++
>> .../bpf/progs/tcp_ca_untrusted_btf_write.c | 26 +++++++++++++++++++
>> 2 files changed, 38 insertions(+)
>> create mode 100644 tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
>>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
>> index fe30181e6336..eb05fc82f81b 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
>> @@ -14,6 +14,7 @@
>> #include "tcp_ca_incompl_cong_ops.skel.h"
>> #include "tcp_ca_unsupp_cong_op.skel.h"
>> #include "tcp_ca_kfunc.skel.h"
>> +#include "tcp_ca_untrusted_btf_write.skel.h"
>> #include "bpf_cc_cubic.skel.h"
>>
>> static const unsigned int total_bytes = 10 * 1024 * 1024;
>> @@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)
>> tcp_ca_kfunc__destroy(skel);
>> }
>>
>> +static void test_untrusted_btf_write(void)
>> +{
>> + struct tcp_ca_untrusted_btf_write *skel;
>> +
>> + skel = tcp_ca_untrusted_btf_write__open_and_load();
>> + ASSERT_ERR_PTR(skel, "tcp_ca_untrusted_btf_write__open_and_load");
>> + tcp_ca_untrusted_btf_write__destroy(skel);
>> +}
>> +
>> static void test_cc_cubic(void)
>> {
>> struct cb_opts cb_opts = {
>> @@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)
>> test_link_replace();
>> if (test__start_subtest("tcp_ca_kfunc"))
>> test_tcp_ca_kfunc();
>> + if (test__start_subtest("untrusted_btf_write"))
>> + test_untrusted_btf_write();
>> if (test__start_subtest("cc_cubic"))
>> test_cc_cubic();
>> if (test__start_subtest("dctcp_autoattach_map"))
>> diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
>> new file mode 100644
>> index 000000000000..eda4697aac80
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
>> @@ -0,0 +1,26 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include "bpf_tracing_net.h"
>> +#include <bpf/bpf_core_read.h>
>> +#include <bpf/bpf_helpers.h>
>> +#include <bpf/bpf_tracing.h>
>> +
>> +char _license[] SEC("license") = "GPL";
>> +
>> +SEC("struct_ops")
>> +void BPF_PROG(untrusted_btf_write_init, struct sock *sk)
>> +{
>> + struct tcp_sock *tp;
>> + int v = 1;
>> + void *p;
>> +
>> + p = bpf_rdonly_cast(&v, 0);
>> + tp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));
>
> Do we need two bpf_rdonly_cast()? I tested the following and it also works:
>
Yeah, single case works too, I mostly kept these two because of the original
report.
> tp = bpf_rdonly_cast(&v, bpf_core_type_id_kernel(struct tcp_sock));
>
>> + tp->snd_cwnd = 1;
>> +}
>> +
>> +SEC(".struct_ops")
>> +struct tcp_congestion_ops untrusted_btf_write = {
>> + .init = (void *)untrusted_btf_write_init,
>> + .name = "bpf_ro_btf",
>> +};
>> --
>> 2.53.0
>>
>>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression
2026-07-07 22:36 ` Kumar Kartikeya Dwivedi
@ 2026-07-07 22:58 ` Amery Hung
0 siblings, 0 replies; 8+ messages in thread
From: Amery Hung @ 2026-07-07 22:58 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team
On Tue, Jul 7, 2026 at 3:36 PM Kumar Kartikeya Dwivedi <memxor@gmail.com> wrote:
>
> On Wed Jul 8, 2026 at 12:31 AM CEST, Amery Hung wrote:
> > On Tue, Jul 7, 2026 at 12:02 PM Kumar Kartikeya Dwivedi
> > <memxor@gmail.com> wrote:
> >>
> >> Add a TCP congestion-control struct_ops load test for a write through a
> >> BTF pointer produced by bpf_rdonly_cast().
> >>
> >> The test expects the verifier to reject the program before the TCP CA
> >> btf_struct_access callback can whitelist the tcp_sock field write.
> >>
> >> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> >> ---
> >> .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 12 +++++++++
> >> .../bpf/progs/tcp_ca_untrusted_btf_write.c | 26 +++++++++++++++++++
> >> 2 files changed, 38 insertions(+)
> >> create mode 100644 tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
> >>
> >> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
> >> index fe30181e6336..eb05fc82f81b 100644
> >> --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
> >> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
> >> @@ -14,6 +14,7 @@
> >> #include "tcp_ca_incompl_cong_ops.skel.h"
> >> #include "tcp_ca_unsupp_cong_op.skel.h"
> >> #include "tcp_ca_kfunc.skel.h"
> >> +#include "tcp_ca_untrusted_btf_write.skel.h"
> >> #include "bpf_cc_cubic.skel.h"
> >>
> >> static const unsigned int total_bytes = 10 * 1024 * 1024;
> >> @@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)
> >> tcp_ca_kfunc__destroy(skel);
> >> }
> >>
> >> +static void test_untrusted_btf_write(void)
> >> +{
> >> + struct tcp_ca_untrusted_btf_write *skel;
> >> +
> >> + skel = tcp_ca_untrusted_btf_write__open_and_load();
> >> + ASSERT_ERR_PTR(skel, "tcp_ca_untrusted_btf_write__open_and_load");
> >> + tcp_ca_untrusted_btf_write__destroy(skel);
> >> +}
> >> +
> >> static void test_cc_cubic(void)
> >> {
> >> struct cb_opts cb_opts = {
> >> @@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)
> >> test_link_replace();
> >> if (test__start_subtest("tcp_ca_kfunc"))
> >> test_tcp_ca_kfunc();
> >> + if (test__start_subtest("untrusted_btf_write"))
> >> + test_untrusted_btf_write();
> >> if (test__start_subtest("cc_cubic"))
> >> test_cc_cubic();
> >> if (test__start_subtest("dctcp_autoattach_map"))
> >> diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
> >> new file mode 100644
> >> index 000000000000..eda4697aac80
> >> --- /dev/null
> >> +++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
> >> @@ -0,0 +1,26 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +
> >> +#include "bpf_tracing_net.h"
> >> +#include <bpf/bpf_core_read.h>
> >> +#include <bpf/bpf_helpers.h>
> >> +#include <bpf/bpf_tracing.h>
> >> +
> >> +char _license[] SEC("license") = "GPL";
> >> +
> >> +SEC("struct_ops")
> >> +void BPF_PROG(untrusted_btf_write_init, struct sock *sk)
> >> +{
> >> + struct tcp_sock *tp;
> >> + int v = 1;
> >> + void *p;
> >> +
> >> + p = bpf_rdonly_cast(&v, 0);
> >> + tp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));
> >
> > Do we need two bpf_rdonly_cast()? I tested the following and it also works:
> >
>
> Yeah, single case works too, I mostly kept these two because of the original
> report.
I see. I was wondering whether the first cast has some special
purposes. Single cast reads a bit cleaner to me, but no strong
preference.
Reviewed-by: Amery Hung <ameryhung@gmail.com>
>
> > tp = bpf_rdonly_cast(&v, bpf_core_type_id_kernel(struct tcp_sock));
> >
> >> + tp->snd_cwnd = 1;
> >> +}
> >> +
> >> +SEC(".struct_ops")
> >> +struct tcp_congestion_ops untrusted_btf_write = {
> >> + .init = (void *)untrusted_btf_write_init,
> >> + .name = "bpf_ro_btf",
> >> +};
> >> --
> >> 2.53.0
> >>
> >>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-07-07 22:58 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 19:02 [PATCH bpf-next v1 0/2] Fix for untrusted BTF pointer writes Kumar Kartikeya Dwivedi
2026-07-07 19:02 ` [PATCH bpf-next v1 1/2] bpf: Reject writes through untrusted BTF pointers Kumar Kartikeya Dwivedi
2026-07-07 19:48 ` bot+bpf-ci
2026-07-07 22:10 ` Amery Hung
2026-07-07 19:02 ` [PATCH bpf-next v1 2/2] selftests/bpf: Add untrusted BTF write regression Kumar Kartikeya Dwivedi
2026-07-07 22:31 ` Amery Hung
2026-07-07 22:36 ` Kumar Kartikeya Dwivedi
2026-07-07 22:58 ` Amery Hung
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox