mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
bpf: Reject memory for kfunc projection type args
struct __sk_buff and struct xdp_md are projection types of struct sk_buff
and struct xdp_buff. A kfunc that takes a projection type casts the
argument to the underlying type. When the projection type is the ctx type
of the prog, the verifier accepts only the ctx. In other progs,
process_arg_ptr_to_btf_id() accepts a pointer to the underlying type.
But this function identifies the underlying type only by its name. A struct
of the same name in prog BTF also matches. Its objects are memory of the
prog. This test also ignores the offset of the register. Thus the kfunc
uses memory of the prog, or the middle of an skb, as an skb.
Accept the underlying type only from kernel BTF, and only at offset 0. A
prog that passes an skb of the kernel sees no change.
struct xdp_md has only scalar members. Thus in a prog with another ctx
type, resolve_func_arg_type() changes ARG_PTR_TO_BTF_ID to memory, and the
verifier accepts memory of the prog. Keep ARG_PTR_TO_BTF_ID for projection
types. The first Fixes tag is for this change. That commit merged the
conntrack kfunc sets of two prog types with different ctx types. Thus
bpf_xdp_ct_{alloc,lookup}() can use memory of the prog as an xdp_buff.
Fixes: a4703e3184 ("bpf: Switch to new kfunc flags infrastructure")
Fixes: ec209ad863 ("bpf: verifier: Relax caller requirements for kfunc projection type args")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-9-alexei.starovoitov@gmail.com
This commit is contained in:
parent
14d3e5bf9f
commit
f89ebf0749
|
|
@ -631,6 +631,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_type(const char *pname);
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -6590,6 +6590,15 @@ static int find_kern_ctx_type_id(enum bpf_prog_type prog_type)
|
|||
return ctx_type->type;
|
||||
}
|
||||
|
||||
/*
|
||||
* A projection type is the view that programs have of a kernel object with
|
||||
* another layout: see btf_is_projection_of() for the two types behind them.
|
||||
*/
|
||||
bool btf_is_projection_type(const char *pname)
|
||||
{
|
||||
return strcmp(pname, "__sk_buff") == 0 || strcmp(pname, "xdp_md") == 0;
|
||||
}
|
||||
|
||||
bool btf_is_projection_of(const char *pname, const char *tname)
|
||||
{
|
||||
if (strcmp(pname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0)
|
||||
|
|
|
|||
|
|
@ -13585,7 +13585,13 @@ static int resolve_func_arg_type(struct bpf_verifier_env *env,
|
|||
ref_t = btf_type_skip_modifiers(btf, ref_id, &ref_id);
|
||||
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
|
||||
|
||||
if (!btf_type_is_scalar_struct(env, btf, ref_t))
|
||||
/*
|
||||
* A kfunc that takes a projection type (ie. xdp_md) casts it to the
|
||||
* underlying type. So memory of the program cannot stand in for it,
|
||||
* even if the projection type holds only scalars.
|
||||
*/
|
||||
if (btf_is_projection_type(ref_tname) ||
|
||||
!btf_type_is_scalar_struct(env, btf, ref_t))
|
||||
return 0;
|
||||
|
||||
resolve_ret = btf_resolve_size(btf, ref_t, arg_size);
|
||||
|
|
@ -14340,9 +14346,13 @@ static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_re
|
|||
|
||||
/* 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.
|
||||
* caller to pass in the underlying type. Only kernel BTF has that type:
|
||||
* a type of the same name in the BTF of the program is program memory.
|
||||
* And only a pointer to the start of the object points to that type.
|
||||
*/
|
||||
taking_projection = is_kfunc(meta) && btf_is_projection_of(arg_tname, reg_tname);
|
||||
taking_projection = is_kfunc(meta) && btf_is_kernel(reg_btf) &&
|
||||
!reg->var_off.value &&
|
||||
btf_is_projection_of(arg_tname, reg_tname);
|
||||
if (!taking_projection && !struct_same) {
|
||||
verbose(env, "%s %s expected pointer to %s %s but %s has a pointer to %s %s\n",
|
||||
meta->func_name, reg_arg_name(env, argno),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user