mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
bpf: Distinguish fixed- and variable-size kfunc mem args with MEM_FIXED_SIZE
A kfunc memory-pointer argument comes in two flavors: a fixed-size buffer whose access size is derived from the pointed-to BTF type, and a variable-size buffer paired with a following __sz/__szk size argument. Both were represented by separate kfunc_ptr_arg_type values (KF_ARG_PTR_TO_MEM vs KF_ARG_PTR_TO_MEM_SIZE) with the pointer classified as the latter when a size argument followed. Mirror how helpers describe the same distinction: classify both as KF_ARG_PTR_TO_MEM and OR in MEM_FIXED_SIZE for the fixed-size case, just as helpers use ARG_PTR_TO_MEM | MEM_FIXED_SIZE. The switches now key on base_type(kf_arg_type) so the flag rides along, and the KF_ARG_PTR_TO_MEM handler either resolves the size from BTF (MEM_FIXED_SIZE) or falls through to the mem/size-pair check, which validates the buffer against the following size register and skips it. No functional change. Currently, KF_ARG_MEM_SIZE and KF_ARG_CONST_MEM_SIZE are only reachable from ARG_PTR_TO_MEM fallthrough. A patch later will merge scalar checking into the same switch and remove the fallthrough. Signed-off-by: Amery Hung <ameryhung@gmail.com> Reviewed-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260801074633.1595644-15-ameryhung@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
parent
76fb087504
commit
90990ee10b
|
|
@ -11059,6 +11059,8 @@ static bool __btf_type_is_scalar_struct(struct bpf_verifier_env *env,
|
|||
}
|
||||
|
||||
enum kfunc_ptr_arg_type {
|
||||
KF_ARG_CONST_MEM_SIZE,
|
||||
KF_ARG_MEM_SIZE,
|
||||
KF_ARG_PTR_TO_CTX,
|
||||
KF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */
|
||||
KF_ARG_PTR_TO_REFCOUNTED_KPTR, /* Refcounted local kptr */
|
||||
|
|
@ -11068,7 +11070,6 @@ enum kfunc_ptr_arg_type {
|
|||
KF_ARG_PTR_TO_LIST_NODE,
|
||||
KF_ARG_PTR_TO_BTF_ID, /* Also covers reg2btf_ids conversions */
|
||||
KF_ARG_PTR_TO_MEM,
|
||||
KF_ARG_PTR_TO_MEM_SIZE, /* Size derived from next argument, skip it */
|
||||
KF_ARG_PTR_TO_CALLBACK,
|
||||
KF_ARG_PTR_TO_RB_ROOT,
|
||||
KF_ARG_PTR_TO_RB_NODE,
|
||||
|
|
@ -11334,7 +11335,7 @@ bool bpf_is_kfunc_pkt_changing(struct bpf_call_arg_meta *meta)
|
|||
return meta->func_id == special_kfunc_list[KF_bpf_xdp_pull_data];
|
||||
}
|
||||
|
||||
static enum kfunc_ptr_arg_type
|
||||
static int
|
||||
get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
|
||||
struct bpf_reg_state *regs, struct bpf_call_arg_meta *meta,
|
||||
const struct btf_type *t, const struct btf_type *ref_t,
|
||||
|
|
@ -11434,7 +11435,7 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
|
|||
btf_type_str(ref_t), ref_tname, arg_mem_size ? "void, " : "");
|
||||
return -EINVAL;
|
||||
}
|
||||
return arg_mem_size ? KF_ARG_PTR_TO_MEM_SIZE : KF_ARG_PTR_TO_MEM;
|
||||
return arg_mem_size ? KF_ARG_PTR_TO_MEM : KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
|
||||
}
|
||||
|
||||
static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
|
||||
|
|
@ -12136,7 +12137,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
|
|||
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
|
||||
}
|
||||
|
||||
switch (kf_arg_type) {
|
||||
switch (base_type(kf_arg_type)) {
|
||||
case KF_ARG_PTR_TO_ALLOC_BTF_ID:
|
||||
case KF_ARG_PTR_TO_BTF_ID:
|
||||
if (!is_trusted_reg(env, reg)) {
|
||||
|
|
@ -12159,7 +12160,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
|
|||
case KF_ARG_PTR_TO_RB_ROOT:
|
||||
case KF_ARG_PTR_TO_RB_NODE:
|
||||
case KF_ARG_PTR_TO_MEM:
|
||||
case KF_ARG_PTR_TO_MEM_SIZE:
|
||||
case KF_ARG_PTR_TO_CALLBACK:
|
||||
case KF_ARG_PTR_TO_CONST_STR:
|
||||
case KF_ARG_PTR_TO_WORKQUEUE:
|
||||
|
|
@ -12190,7 +12190,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (kf_arg_type) {
|
||||
switch (base_type(kf_arg_type)) {
|
||||
case KF_ARG_PTR_TO_CTX:
|
||||
if (reg->type != PTR_TO_CTX) {
|
||||
verbose(env, "%s expected pointer to ctx, but got %s\n",
|
||||
|
|
@ -12387,18 +12387,22 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
|
|||
return ret;
|
||||
break;
|
||||
case KF_ARG_PTR_TO_MEM:
|
||||
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
|
||||
if (IS_ERR(resolve_ret)) {
|
||||
verbose(env, "%s reference type('%s %s') size cannot be determined: %ld\n",
|
||||
reg_arg_name(env, argno), btf_type_str(ref_t),
|
||||
ref_tname, PTR_ERR(resolve_ret));
|
||||
return -EINVAL;
|
||||
if (kf_arg_type & MEM_FIXED_SIZE) {
|
||||
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
|
||||
if (IS_ERR(resolve_ret)) {
|
||||
verbose(env, "%s reference type('%s %s') size cannot be determined: %ld\n",
|
||||
reg_arg_name(env, argno), btf_type_str(ref_t),
|
||||
ref_tname, PTR_ERR(resolve_ret));
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = check_mem_reg(env, reg, argno, type_size, BPF_READ | BPF_WRITE, meta);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
ret = check_mem_reg(env, reg, argno, type_size, BPF_READ | BPF_WRITE, meta);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case KF_ARG_PTR_TO_MEM_SIZE:
|
||||
fallthrough;
|
||||
case KF_ARG_CONST_MEM_SIZE:
|
||||
case KF_ARG_MEM_SIZE:
|
||||
{
|
||||
struct bpf_reg_state *buff_reg = reg;
|
||||
struct bpf_reg_state *size_reg = get_func_arg_reg(caller, regs, i + 1);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user