From: Yonghong Song <yonghong.song@linux.dev>
To: Taegu Ha <hataegu0826@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>
Cc: Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Shuah Khan <shuah@kernel.org>,
bpf@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
Subject: Re: [PATCH bpf 1/1] bpf: reject overlarge global subprog argument sizes
Date: Wed, 27 May 2026 09:59:21 -0700 [thread overview]
Message-ID: <549d58c6-05f0-4176-98ec-c88e96ee4375@linux.dev> (raw)
In-Reply-To: <20260527052539.3388700-2-hataegu0826@gmail.com>
On 5/26/26 10:25 PM, Taegu Ha wrote:
> Global subprogram argument checking derives generic pointer sizes from BTF
> and passes the resolved size to check_mem_reg() as a u32. The access-size
> validation path then uses a signed int, and stack pointers negate the value
> before calling check_helper_mem_access().
>
> A BTF type such as int[0x3fffffff] resolves to 0xfffffffc bytes. On a stack
> pointer, (int)mem_size becomes -4 and the negation validates only four
> bytes. A caller can therefore pass a four-byte stack slot while the callee
> is verified with a nearly 4GiB memory argument, allowing accesses outside
> the caller object.
>
> This was confirmed with a non-executing raw-BTF reproducer. On a
> vulnerable kernel, the verifier accepted a program where the caller passed
> a four-byte stack slot, while the callee argument was described by BTF as
> int[0x3fffffff]. The verifier log showed:
>
> R1=mem_or_null(id=1,sz=0xfffffffc)
> r0 = *(u32 *)(r1 +4)
>
> The program was only loaded to prove verifier acceptance and was not
> attached or executed.
>
> Reject sizes that cannot be represented by the signed verifier access-size
> API before any conversion. Cast the non-stack case after the bound check to
> make the conversion explicit, and add a verifier regression test for the
> oversized BTF argument.
>
> Fixes: 2cb27158adb3 ("bpf: poison dead stack slots")
> Signed-off-by: Taegu Ha <hataegu0826@gmail.com>
> ---
> kernel/bpf/verifier.c | 7 ++++++-
> .../bpf/progs/verifier_global_subprogs.c | 17 +++++++++++++++++
> 2 files changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 7fb88e1cd7c4..1007f204a1f5 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -7107,6 +7107,11 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg
> struct bpf_reg_state saved_reg;
> int err;
>
> + if (mem_size > S32_MAX) {
> + verbose(env, "R%d memory size %u is too large\n", regno, mem_size);
> + return -EACCES;
> + }
> +
> if (bpf_register_is_null(reg))
> return 0;
>
> @@ -7119,7 +7124,7 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg
> mark_ptr_not_null_reg(reg);
> }
>
> - int size = base_type(reg->type) == PTR_TO_STACK ? -(int)mem_size : mem_size;
> + int size = base_type(reg->type) == PTR_TO_STACK ? -(int)mem_size : (int)mem_size;
>
> err = check_helper_mem_access(env, regno, size, BPF_READ, true, NULL);
> err = err ?: check_helper_mem_access(env, regno, size, BPF_WRITE, true, NULL);
> diff --git a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
> index 1e08aff7532e..0ff8f85b4d46 100644
> --- a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
> +++ b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
> @@ -151,6 +151,23 @@ int anon_user_mem_valid(void *ctx)
> return subprog_user_anon_mem(&t);
> }
>
> +__noinline __weak int subprog_user_anon_mem_huge(int (*p)[0x3fffffff])
> +{
> + return p ? (*p)[1] : 0;
> +}
> +
> +SEC("?tracepoint")
> +__failure __log_level(2)
> +__msg("R1 memory size 4294967292 is too large")
> +int anon_user_mem_huge_size_invalid(void *ctx)
> +{
> + int (*p)[0x3fffffff];
> + int tiny = 42;
> +
> + p = (void *)&tiny;
> + return subprog_user_anon_mem_huge(p) + tiny;
> +}
Without verifier.c change, verification is successful.
The objdump:
0000000000000160 <subprog_user_anon_mem_huge>:
; {
44: b4 00 00 00 00 00 00 00 w0 = 0x0
; return p ? (*p)[1] : 0;
45: 15 01 01 00 00 00 00 00 if r1 == 0x0 goto +0x1 <L0>
46: 61 10 04 00 00 00 00 00 w0 = *(u32 *)(r1 + 0x4)
<L0>:
47: 95 00 00 00 00 00 00 00 exit
0000000000000040 <anon_user_mem_huge_size_invalid>:
; int tiny = 42;
8: b4 01 00 00 2a 00 00 00 w1 = 0x2a
9: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 0x4) = w1
10: bf a1 00 00 00 00 00 00 r1 = r10
11: 07 01 00 00 fc ff ff ff r1 += -0x4
; return subprog_user_anon_mem_huge(p) + tiny;
12: 85 10 00 00 ff ff ff ff call -0x1
0000000000000060: R_BPF_64_32 subprog_user_anon_mem_huge
13: 61 a1 fc ff 00 00 00 00 w1 = *(u32 *)(r10 - 0x4)
14: 0c 01 00 00 00 00 00 00 w1 += w0
15: bc 10 00 00 00 00 00 00 w0 = w1
16: 95 00 00 00 00 00 00 00 exit
The big 0x3fffffff does not really matter.
> +
> __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull)
> {
> return (*p1) * (*p2); /* good, no need for NULL checks */
next prev parent reply other threads:[~2026-05-27 16:59 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-27 5:25 [PATCH bpf 0/1] bpf: reject overlarge global subprog argument sizes Taegu Ha
2026-05-27 5:25 ` [PATCH bpf 1/1] " Taegu Ha
2026-05-27 16:59 ` Yonghong Song [this message]
2026-05-27 17:48 ` 하태구
2026-05-27 17:53 ` 하태구
2026-05-28 5:03 ` Yonghong Song
2026-05-28 5:25 ` [PATCH v2 0/1] " Taegu Ha
2026-05-28 5:25 ` [PATCH v2 1/1] " Taegu Ha
2026-05-28 6:05 ` bot+bpf-ci
2026-05-28 6:21 ` [PATCH bpf-next v3] " Taegu Ha
2026-05-28 15:17 ` Yonghong Song
2026-06-01 1:00 ` patchwork-bot+netdevbpf
2026-06-01 6:04 ` 하태구
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=549d58c6-05f0-4176-98ec-c88e96ee4375@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=hataegu0826@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=memxor@gmail.com \
--cc=shuah@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.