bpf: verifier: Relax caller requirements for kfunc projection type args
Currently, if a kfunc accepts a projection type as an argument (eg struct __sk_buff *), the caller must exactly provide exactly the same type with provable provenance. However in practice, kfuncs that accept projection types _must_ cast to the underlying type before use b/c projection type layouts are completely made up. Thus, it is ok to relax the verifier rules around implicit conversions. We will use this functionality in the next commit when we align kfuncs to user-facing types. Signed-off-by: Daniel Xu <dxu@dxuuu.xyz> Link: https://lore.kernel.org/r/e2c025cb09ccfd4af1ec9e18284dc3cecff7514d.1718207789.git.dxu@dxuuu.xyz Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
0ce089cbdc
commit
ec209ad863
@ -531,6 +531,7 @@ s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
|
||||
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
|
||||
struct module *owner);
|
||||
struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf, u32 btf_id);
|
||||
bool btf_is_projection_of(const char *pname, const char *tname);
|
||||
bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
const struct btf_type *t, enum bpf_prog_type prog_type,
|
||||
int arg);
|
||||
|
@ -5820,6 +5820,15 @@ static int find_kern_ctx_type_id(enum bpf_prog_type prog_type)
|
||||
return ctx_type->type;
|
||||
}
|
||||
|
||||
bool btf_is_projection_of(const char *pname, const char *tname)
|
||||
{
|
||||
if (strcmp(pname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0)
|
||||
return true;
|
||||
if (strcmp(pname, "xdp_md") == 0 && strcmp(tname, "xdp_buff") == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool btf_is_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
|
||||
const struct btf_type *t, enum bpf_prog_type prog_type,
|
||||
int arg)
|
||||
@ -5882,9 +5891,7 @@ again:
|
||||
* int socket_filter_bpf_prog(struct __sk_buff *skb)
|
||||
* { // no fields of skb are ever used }
|
||||
*/
|
||||
if (strcmp(ctx_tname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0)
|
||||
return true;
|
||||
if (strcmp(ctx_tname, "xdp_md") == 0 && strcmp(tname, "xdp_buff") == 0)
|
||||
if (btf_is_projection_of(ctx_tname, tname))
|
||||
return true;
|
||||
if (strcmp(ctx_tname, tname)) {
|
||||
/* bpf_user_pt_regs_t is a typedef, so resolve it to
|
||||
|
@ -11265,6 +11265,8 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
|
||||
bool strict_type_match = false;
|
||||
const struct btf *reg_btf;
|
||||
const char *reg_ref_tname;
|
||||
bool taking_projection;
|
||||
bool struct_same;
|
||||
u32 reg_ref_id;
|
||||
|
||||
if (base_type(reg->type) == PTR_TO_BTF_ID) {
|
||||
@ -11308,7 +11310,13 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
|
||||
|
||||
reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id, ®_ref_id);
|
||||
reg_ref_tname = btf_name_by_offset(reg_btf, reg_ref_t->name_off);
|
||||
if (!btf_struct_ids_match(&env->log, reg_btf, reg_ref_id, reg->off, meta->btf, ref_id, strict_type_match)) {
|
||||
struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_ref_id, reg->off, meta->btf, ref_id, strict_type_match);
|
||||
/* If kfunc is accepting a projection type (ie. __sk_buff), it cannot
|
||||
* actually use it -- it must cast to the underlying type. So we allow
|
||||
* caller to pass in the underlying type.
|
||||
*/
|
||||
taking_projection = btf_is_projection_of(ref_tname, reg_ref_tname);
|
||||
if (!taking_projection && !struct_same) {
|
||||
verbose(env, "kernel function %s args#%d expected pointer to %s %s but R%d has a pointer to %s %s\n",
|
||||
meta->func_name, argno, btf_type_str(ref_t), ref_tname, argno + 1,
|
||||
btf_type_str(reg_ref_t), reg_ref_tname);
|
||||
|
Loading…
Reference in New Issue
Block a user