summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-06-25 17:51:20 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-06-25 17:51:21 -0700
commitfbc10dff7846206585b02864fef4ebfd7cadf6e2 (patch)
treef8b63075d50f3460592e6a0ce26785e39ec9e2c6 /kernel
parent66bb952b449eac53dffb341108251d632767fd2d (diff)
parent0371fb57a0c941592a5ad5ad5ac597d3b653ee73 (diff)
Merge branch 'bpf-reject-offset-refcount-acquire-arguments'
Yiyang Chen says: ==================== bpf: Reject offset refcount acquire arguments bpf_refcount_acquire() is modeled as returning a refcounted allocation base, but it currently accepts PTR_TO_BTF_ID | MEM_ALLOC arguments whose offset already points at an embedded graph node returned from a list or rbtree operation. At runtime the kfunc starts from the supplied pointer and adds the type's refcount offset. With a graph-node pointer, that starts from base + node_off, while the verifier treats the returned pointer as the allocation base. Reject non-zero fixed-offset arguments to keep the runtime operation and the verifier model aligned. Programs that pop graph nodes can still acquire a reference after normalizing the node pointer with container_of(). Patch 1 handles the zero fixed-offset requirement in the existing check_func_arg_reg_off() / __check_ptr_off_reg() path without consuming a bpf_type_flag bit. Patch 2 adds a rejected direct list-node case. Changes from v3: - Add Eduard's Acked-by to patch 1. - Drop the redundant rbtree selftest case; the list case exercises the same refcount-acquire fixed-offset rejection path. - Trim the selftest commit message and remove the selftest Fixes tag. Changes from v2: - Avoid adding a new bpf_type_flag bit. - Carry the refcount-acquire zero fixed-offset requirement with an internal check_func_arg_reg_off() parameter. Changes from v1: - Move zero fixed-offset enforcement into check_func_arg_reg_off() / __check_ptr_off_reg(), as suggested by Eduard. - Drop the positive container_of() selftest case. - Remove the stale bpf_obj_drop() after bpf_list_push_front(), since the pushed reference is consumed even when the verifier explores the error branch. - Rebase to bpf-next master a975094bf98c. v3: https://lore.kernel.org/bpf/cover.1781979133.git.chenyy23@mails.tsinghua.edu.cn/ v2: https://lore.kernel.org/bpf/cover.1781963957.git.chenyy23@mails.tsinghua.edu.cn/ v1: https://lore.kernel.org/bpf/cover.1781852308.git.chenyy23@mails.tsinghua.edu.cn/ ==================== Link: https://patch.msgid.link/cover.1782192383.git.chenyy23@mails.tsinghua.edu.cn Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 21a365d436a5..3cdc2e90f643 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7996,9 +7996,10 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields)
return field;
}
-static int check_func_arg_reg_off(struct bpf_verifier_env *env,
- const struct bpf_reg_state *reg, argno_t argno,
- enum bpf_arg_type arg_type)
+static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg, argno_t argno,
+ enum bpf_arg_type arg_type,
+ bool btf_id_fixed_off_ok)
{
u32 type = reg->type;
@@ -8055,12 +8056,11 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env,
case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:
/* When referenced PTR_TO_BTF_ID is passed to release function,
* its fixed offset must be 0. In the other cases, fixed offset
- * can be non-zero. This was already checked above. So pass
- * fixed_off_ok as true to allow fixed offset for all other
- * cases. var_off always must be 0 for PTR_TO_BTF_ID, hence we
- * still need to do checks instead of returning.
+ * can be non-zero unless the caller requires otherwise.
+ * var_off always must be 0 for PTR_TO_BTF_ID, hence we still
+ * need to do checks instead of returning.
*/
- return __check_ptr_off_reg(env, reg, argno, true);
+ return __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);
case PTR_TO_CTX:
/*
* Allow fixed and variable offsets for syscall context, but
@@ -8076,6 +8076,13 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env,
}
}
+static int check_func_arg_reg_off(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg, argno_t argno,
+ enum bpf_arg_type arg_type)
+{
+ return __check_func_arg_reg_off(env, reg, argno, arg_type, true);
+}
+
static int check_arg_const_str(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, argno_t argno)
{
@@ -11947,6 +11954,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
enum bpf_arg_type arg_type = ARG_DONTCARE;
argno_t argno = argno_from_arg(i + 1);
int regno = reg_from_argno(argno);
+ bool btf_id_fixed_off_ok = true;
u32 ref_id, type_size;
bool is_ret_buf_sz = false;
int kf_arg_type;
@@ -12120,7 +12128,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
case KF_ARG_PTR_TO_MEM:
case KF_ARG_PTR_TO_MEM_SIZE:
case KF_ARG_PTR_TO_CALLBACK:
- case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
case KF_ARG_PTR_TO_CONST_STR:
case KF_ARG_PTR_TO_WORKQUEUE:
case KF_ARG_PTR_TO_TIMER:
@@ -12134,6 +12141,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
case KF_ARG_PTR_TO_CTX:
arg_type = ARG_PTR_TO_CTX;
break;
+ case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
+ arg_type = ARG_PTR_TO_BTF_ID;
+ btf_id_fixed_off_ok = false;
+ break;
default:
verifier_bug(env, "unknown kfunc arg type %d", kf_arg_type);
return -EFAULT;
@@ -12141,7 +12152,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
if (regno == meta->release_regno)
arg_type |= OBJ_RELEASE;
- ret = check_func_arg_reg_off(env, reg, argno, arg_type);
+ ret = __check_func_arg_reg_off(env, reg, argno, arg_type,
+ btf_id_fixed_off_ok);
if (ret < 0)
return ret;