Re: [PATCH bpf-next v2 2/4] bpf: Add a kfunc to type cast from bpf uapi ctx to kernel ctx

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Nov 20, 2022 at 10:55:54AM -0800, Yonghong Song wrote:
> 
> 
> On 11/20/22 10:33 AM, Alexei Starovoitov wrote:
> > On Sun, Nov 20, 2022 at 08:15:22AM -0800, Yonghong Song wrote:
> > > Implement bpf_cast_to_kern_ctx() kfunc which does a type cast
> > > of a uapi ctx object to the corresponding kernel ctx. Previously
> > > if users want to access some data available in kctx but not
> > > in uapi ctx, bpf_probe_read_kernel() helper is needed.
> > > The introduction of bpf_cast_to_kern_ctx() allows direct
> > > memory access which makes code simpler and easier to understand.
> > > 
> > > Signed-off-by: Yonghong Song <yhs@xxxxxx>
> > > ---
> > >   include/linux/btf.h   |  5 +++++
> > >   kernel/bpf/btf.c      | 25 +++++++++++++++++++++++++
> > >   kernel/bpf/helpers.c  |  6 ++++++
> > >   kernel/bpf/verifier.c | 21 +++++++++++++++++++++
> > >   4 files changed, 57 insertions(+)
> > > 
> > > diff --git a/include/linux/btf.h b/include/linux/btf.h
> > > index d5b26380a60f..4b5d799f5d02 100644
> > > --- a/include/linux/btf.h
> > > +++ b/include/linux/btf.h
> > > @@ -470,6 +470,7 @@ const struct btf_member *
> > >   btf_get_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);
> > > +int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type);
> > >   bool btf_types_are_same(const struct btf *btf1, u32 id1,
> > >   			const struct btf *btf2, u32 id2);
> > >   #else
> > > @@ -514,6 +515,10 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
> > >   {
> > >   	return NULL;
> > >   }
> > > +static inline int get_kern_ctx_btf_id(struct bpf_verifier_log *log,
> > > +				      enum bpf_prog_type prog_type) {
> > > +	return -EINVAL;
> > > +}
> > >   static inline bool btf_types_are_same(const struct btf *btf1, u32 id1,
> > >   				      const struct btf *btf2, u32 id2)
> > >   {
> > > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> > > index 0a3abbe56c5d..bef1b6cfe6b8 100644
> > > --- a/kernel/bpf/btf.c
> > > +++ b/kernel/bpf/btf.c
> > > @@ -5603,6 +5603,31 @@ static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
> > >   	return kern_ctx_type->type;
> > >   }
> > > +int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type)
> > > +{
> > > +	const struct btf_member *kctx_member;
> > > +	const struct btf_type *conv_struct;
> > > +	const struct btf_type *kctx_type;
> > > +	u32 kctx_type_id;
> > > +
> > > +	conv_struct = bpf_ctx_convert.t;
> > > +	if (!conv_struct) {
> > > +		bpf_log(log, "btf_vmlinux is malformed\n");
> > > +		return -EINVAL;
> > > +	}
> > 
> > If we get to this point this internal pointer would be already checked.
> > No need to check it again. Just use it.
> 
> This is probably not true.
> 
> Currently, conv_struct is tested in function btf_get_prog_ctx_type() which
> is called by get_kfunc_ptr_arg_type().
> 
> const struct btf_member *
> btf_get_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)
> {
>         const struct btf_type *conv_struct;
>         const struct btf_type *ctx_struct;
>         const struct btf_member *ctx_type;
>         const char *tname, *ctx_tname;
> 
>         conv_struct = bpf_ctx_convert.t;
>         if (!conv_struct) {
>                 bpf_log(log, "btf_vmlinux is malformed\n");
>                 return NULL;
>         }
> 	...
> }
> 
> In get_kfunc_ptr_arg_type(),
> 
> ...
> 
>         /* In this function, we verify the kfunc's BTF as per the argument
> type,
>          * leaving the rest of the verification with respect to the register
>          * type to our caller. When a set of conditions hold in the BTF type
> of
>          * arguments, we resolve it to a known kfunc_ptr_arg_type.
>          */
>         if (btf_get_prog_ctx_type(&env->log, meta->btf, t,
> resolve_prog_type(env->prog), argno))
>                 return KF_ARG_PTR_TO_CTX;
> 
> Note that if bpf_ctx_convert.t is NULL, btf_get_prog_ctx_type() simply
> returns NULL and the logic simply follows through.

Right. It will return NULL and the code further won't see KF_ARG_PTR_TO_CTX
and will not call get_kern_ctx_btf_id().
So it still looks to me that the check can be dropped.

> Should we actually add a NULL checking for bpf_ctx_convert.t in
> bpf_parse_vmlinux?

Ideally yes, but right now CONFIG_DEBUG_INFO_BTF can be enabled
independently and I'm afraid btf_get_prog_ctx_type() can be called
via btf_translate_to_vmlinux() even when btf_vmlinux == NULL.
So bpf_ctx_convert.t == NULL at that point
because btf_parse_vmlinux wasn't called.

> 
> ...
>         err = btf_check_type_tags(env, btf, 1);
>         if (err)
>                 goto errout;
> 
>         /* btf_parse_vmlinux() runs under bpf_verifier_lock */
>         bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
> 
>         bpf_struct_ops_init(btf, log);
> ...
> 



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux