summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorEduard Zingerman <eddyz87@gmail.com>2026-07-15 02:31:43 -0700
committerEduard Zingerman <eddyz87@gmail.com>2026-07-15 02:33:45 -0700
commit4967bd533db2dc947574ee55ba44b3306ef3b7b1 (patch)
treef6673d2ceae4a0fb17bdfcb26a5de8b0a32bdcd2 /kernel
parent2d8af4e633d3dea7269f2dad724977ce48034fd4 (diff)
parent6f59deb32efa4673fc3b1fef9f3a0da48e9d8494 (diff)
downloadlinux-4967bd533db2dc947574ee55ba44b3306ef3b7b1.tar.gz
linux-4967bd533db2dc947574ee55ba44b3306ef3b7b1.zip
Merge branch 'bpf-reject-negative-const-offsets-for-buffer-pointers'
Sun Jian says: ==================== bpf: Reject negative const offsets for buffer pointers Reject negative effective offsets for PTR_TO_TP_BUFFER and PTR_TO_BUF accesses. Calculate the effective access start using signed arithmetic to prevent unsigned access-end accounting from wrapping, and cover both load-time rejection and the raw tracepoint writable attach-time path. --- Changes in v5: - Simplify __check_buffer_access() to reject a negative effective start after confirming that var_off is constant. Validate the combined offset instead of rejecting negative instruction offsets separately. Drop the duplicate BPF_MAX_VAR_OFF check because pointer arithmetic already bounds constant offsets, and remove the redundant size < 0 check. - Switch the raw tracepoint writable attach tests from nbd_send_request to bpf_testmod_test_writable_bare_tp, avoiding the NBD configuration dependency and its false-pass condition. - Split the attach coverage into named subtests and require bpf_raw_tracepoint_open() to return -EINVAL. - Add verifier coverage for a negative constant PTR_TO_BUF offset. Changes in v4: - Correct the Fixes tag to point to 022ac0750883, where pointer offsets were folded into reg->var_off. - Drop the end > U32_MAX check, which is unreachable after bounding const var_off with BPF_MAX_VAR_OFF while keeping instruction offsets and access sizes bounded. Changes in v3: - Check constant var_off against +/-BPF_MAX_VAR_OFF before computing the effective access range, matching the existing verifier pointer offset convention. - Keep explicit rejection of negative instruction offsets and keep bounded negative constant var_off valid when the effective offset is non-negative. Changes in v2: - Split the kernel fix and selftests into separate patches. - Add an attach-time raw tracepoint writable test that exercises max_tp_access against nbd_send_request's writable size. - Adjust selftest formatting to use the 100 character line width. Tested: - ./test_progs -v -t verifier_raw_tp_writable - ./test_progs -v -t verifier_ptr_to_buf - ./test_progs -v -t raw_tp_writable_reject_bad_access - ./test_progs -v -t raw_tp_writable_test_run v4: https://lore.kernel.org/bpf/20260708090151.151729-1-sun.jian.kdev@gmail.com/ v3: https://lore.kernel.org/bpf/20260708040715.116680-1-sun.jian.kdev@gmail.com/ v2: https://lore.kernel.org/bpf/20260707060804.93561-1-sun.jian.kdev@gmail.com/ v1: https://lore.kernel.org/bpf/20260703035137.109608-1-sun.jian.kdev@gmail.com/ ==================== Link: https://patch.msgid.link/20260714093846.18159-1-sun.jian.kdev@gmail.com Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 6515d4d3c003..9f1333676365 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5326,14 +5326,11 @@ static int check_max_stack_depth(struct bpf_verifier_env *env)
static int __check_buffer_access(struct bpf_verifier_env *env,
const char *buf_info,
const struct bpf_reg_state *reg,
- argno_t argno, int off, int size)
+ argno_t argno, int off, int size,
+ u32 *access_end)
{
- if (off < 0) {
- verbose(env,
- "%s invalid %s buffer access: off=%d, size=%d\n",
- reg_arg_name(env, argno), buf_info, off, size);
- return -EACCES;
- }
+ s64 start;
+
if (!tnum_is_const(reg->var_off)) {
char tn_buf[48];
@@ -5344,6 +5341,15 @@ static int __check_buffer_access(struct bpf_verifier_env *env,
return -EACCES;
}
+ start = (s64)reg->var_off.value + off;
+ if (start < 0) {
+ verbose(env,
+ "%s invalid negative %s buffer offset: off=%d, var_off=%lld\n",
+ reg_arg_name(env, argno), buf_info, off, (s64)reg->var_off.value);
+ return -EACCES;
+ }
+
+ *access_end = start + size;
return 0;
}
@@ -5351,14 +5357,14 @@ static int check_tp_buffer_access(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg,
argno_t argno, int off, int size)
{
+ u32 access_end;
int err;
- err = __check_buffer_access(env, "tracepoint", reg, argno, off, size);
+ err = __check_buffer_access(env, "tracepoint", reg, argno, off, size, &access_end);
if (err)
return err;
- env->prog->aux->max_tp_access = max(reg->var_off.value + off + size,
- env->prog->aux->max_tp_access);
+ env->prog->aux->max_tp_access = max(access_end, env->prog->aux->max_tp_access);
return 0;
}
@@ -5370,13 +5376,14 @@ static int check_buffer_access(struct bpf_verifier_env *env,
u32 *max_access)
{
const char *buf_info = type_is_rdonly_mem(reg->type) ? "rdonly" : "rdwr";
+ u32 access_end;
int err;
- err = __check_buffer_access(env, buf_info, reg, argno, off, size);
+ err = __check_buffer_access(env, buf_info, reg, argno, off, size, &access_end);
if (err)
return err;
- *max_access = max(reg->var_off.value + off + size, *max_access);
+ *max_access = max(access_end, *max_access);
return 0;
}