diff mbox series

[v12,02/10] btf: Handle dynamic pointer parameter in kfuncs

Message ID 20220818152929.402605-3-roberto.sassu@huaweicloud.com (mailing list archive)
State New
Headers show
Series bpf: Add kfuncs for PKCS#7 signature verification | expand

Commit Message

Roberto Sassu Aug. 18, 2022, 3:29 p.m. UTC
From: Roberto Sassu <roberto.sassu@huawei.com>

Allow the bpf_dynptr_kern parameter to be specified in kfuncs. Also, ensure
that the dynamic pointer is valid and initialized.

To properly detect whether a parameter is of the desired type, introduce
the stringify_struct() macro to compare the returned structure name with
the desired name. In addition, protect against structure renames, by
halting the build with BUILD_BUG_ON(), so that developers have to revisit
the code.

Cc: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 include/linux/bpf_verifier.h |  3 +++
 include/linux/btf.h          |  9 +++++++++
 kernel/bpf/btf.c             | 18 ++++++++++++++++++
 kernel/bpf/verifier.c        |  4 ++--
 4 files changed, 32 insertions(+), 2 deletions(-)

Comments

Jarkko Sakkinen Aug. 26, 2022, 4:54 a.m. UTC | #1
On Thu, Aug 18, 2022 at 05:29:21PM +0200, roberto.sassu@huaweicloud.com wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> Allow the bpf_dynptr_kern parameter to be specified in kfuncs. Also, ensure
> that the dynamic pointer is valid and initialized.
> 
> To properly detect whether a parameter is of the desired type, introduce
> the stringify_struct() macro to compare the returned structure name with
> the desired name. In addition, protect against structure renames, by
> halting the build with BUILD_BUG_ON(), so that developers have to revisit
> the code.
> 
> Cc: Joanne Koong <joannelkoong@gmail.com>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
>  include/linux/bpf_verifier.h |  3 +++
>  include/linux/btf.h          |  9 +++++++++
>  kernel/bpf/btf.c             | 18 ++++++++++++++++++
>  kernel/bpf/verifier.c        |  4 ++--
>  4 files changed, 32 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 2e3bad8640dc..55876fbdbae2 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -560,6 +560,9 @@ int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state
>  			     u32 regno);
>  int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
>  		   u32 regno, u32 mem_size);
> +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env,
> +			      struct bpf_reg_state *reg,
> +			      enum bpf_arg_type arg_type);
>  
>  /* this lives here instead of in bpf.h because it needs to dereference tgt_prog */
>  static inline u64 bpf_trampoline_compute_key(const struct bpf_prog *tgt_prog,
> diff --git a/include/linux/btf.h b/include/linux/btf.h
> index ad93c2d9cc1c..f546d368ac5d 100644
> --- a/include/linux/btf.h
> +++ b/include/linux/btf.h
> @@ -52,6 +52,15 @@
>  #define KF_SLEEPABLE    (1 << 5) /* kfunc may sleep */
>  #define KF_DESTRUCTIVE  (1 << 6) /* kfunc performs destructive actions */
>  
> +/*
> + * Return the name of the passed struct, if exists, or halt the build if for
> + * example the structure gets renamed. In this way, developers have to revisit
> + * the code using that structure name, and update it accordingly.
> + */
> +#define stringify_struct(x)			\
> +	({ BUILD_BUG_ON(sizeof(struct x) < 0);	\
> +	   __stringify(x); })
> +
>  struct btf;
>  struct btf_member;
>  struct btf_type;
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index e49b3b6d48ad..26cb548420af 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -6362,15 +6362,20 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
>  
>  			if (is_kfunc) {
>  				bool arg_mem_size = i + 1 < nargs && is_kfunc_arg_mem_size(btf, &args[i + 1], &regs[regno + 1]);
> +				bool arg_dynptr = btf_type_is_struct(ref_t) &&
> +						  !strcmp(ref_tname,
> +							  stringify_struct(bpf_dynptr_kern));
>  
>  				/* Permit pointer to mem, but only when argument
>  				 * type is pointer to scalar, or struct composed
>  				 * (recursively) of scalars.
>  				 * When arg_mem_size is true, the pointer can be
>  				 * void *.
> +				 * Also permit initialized dynamic pointers.
>  				 */
>  				if (!btf_type_is_scalar(ref_t) &&
>  				    !__btf_type_is_scalar_struct(log, btf, ref_t, 0) &&
> +				    !arg_dynptr &&
>  				    (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
>  					bpf_log(log,
>  						"arg#%d pointer type %s %s must point to %sscalar, or struct with scalar\n",
> @@ -6378,6 +6383,19 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
>  					return -EINVAL;
>  				}
>  
> +				if (arg_dynptr) {
> +					if (!is_dynptr_reg_valid_init(env, reg,
> +							ARG_PTR_TO_DYNPTR)) {
> +						bpf_log(log,
> +							"arg#%d pointer type %s %s must be initialized\n",
> +							i, btf_type_str(ref_t),
> +							ref_tname);
> +						return -EINVAL;
> +					}
> +
> +					continue;
> +				}
> +
>  				/* Check for mem, len pair */
>  				if (arg_mem_size) {
>  					if (check_kfunc_mem_size_reg(env, &regs[regno + 1], regno + 1)) {
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 2c1f8069f7b7..aa834e7bb296 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -779,8 +779,8 @@ static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_
>  	return true;
>  }
>  
> -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> -				     enum bpf_arg_type arg_type)
> +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> +			      enum bpf_arg_type arg_type)
>  {
>  	struct bpf_func_state *state = func(env, reg);
>  	int spi = get_spi(reg->off);
> -- 
> 2.25.1
> 

Might be niticking but generally I'd consider splitting
exports as commits of their own.

BR, Jarko
Alexei Starovoitov Aug. 26, 2022, 5:16 a.m. UTC | #2
On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <jarkko@kernel.org> wrote:
> >
> > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > -                                  enum bpf_arg_type arg_type)
> > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > +                           enum bpf_arg_type arg_type)
> >  {
> >       struct bpf_func_state *state = func(env, reg);
> >       int spi = get_spi(reg->off);
> > --
> > 2.25.1
> >
>
> Might be niticking but generally I'd consider splitting
> exports as commits of their own.

-static bool
+bool

into a separate commit?

I guess it makes sense for people whose salary depends on
number of commits.
We don't play these games.
Jarkko Sakkinen Aug. 26, 2022, 5:46 a.m. UTC | #3
On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
> On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > >
> > > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > -                                  enum bpf_arg_type arg_type)
> > > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > +                           enum bpf_arg_type arg_type)
> > >  {
> > >       struct bpf_func_state *state = func(env, reg);
> > >       int spi = get_spi(reg->off);
> > > --
> > > 2.25.1
> > >
> >
> > Might be niticking but generally I'd consider splitting
> > exports as commits of their own.
> 
> -static bool
> +bool
> 
> into a separate commit?
> 
> I guess it makes sense for people whose salary depends on
> number of commits.
> We don't play these games.

What kind of argument is that anyway.

BR, Jarkko
Jarkko Sakkinen Aug. 26, 2022, 2:43 p.m. UTC | #4
On Fri, Aug 26, 2022 at 08:46:14AM +0300, Jarkko Sakkinen wrote:
> On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
> > On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > > >
> > > > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > > -                                  enum bpf_arg_type arg_type)
> > > > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > > +                           enum bpf_arg_type arg_type)
> > > >  {
> > > >       struct bpf_func_state *state = func(env, reg);
> > > >       int spi = get_spi(reg->off);
> > > > --
> > > > 2.25.1
> > > >
> > >
> > > Might be niticking but generally I'd consider splitting
> > > exports as commits of their own.
> > 
> > -static bool
> > +bool
> > 
> > into a separate commit?
> > 
> > I guess it makes sense for people whose salary depends on
> > number of commits.
> > We don't play these games.
> 
> What kind of argument is that anyway.

"Separate each *logical change* into a separate patch." [*]

To add, generally any user space visible space should be an
isolated patch.

Please, stop posting nonsense.

[*] https://www.kernel.org/doc/html/v5.19/process/submitting-patches.html#separate-your-changes

BR, Jarkko
Jarkko Sakkinen Aug. 26, 2022, 2:46 p.m. UTC | #5
On Fri, Aug 26, 2022 at 05:43:50PM +0300, Jarkko Sakkinen wrote:
> On Fri, Aug 26, 2022 at 08:46:14AM +0300, Jarkko Sakkinen wrote:
> > On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
> > > On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <jarkko@kernel.org> wrote:
> > > > >
> > > > > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > > > -                                  enum bpf_arg_type arg_type)
> > > > > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> > > > > +                           enum bpf_arg_type arg_type)
> > > > >  {
> > > > >       struct bpf_func_state *state = func(env, reg);
> > > > >       int spi = get_spi(reg->off);
> > > > > --
> > > > > 2.25.1
> > > > >
> > > >
> > > > Might be niticking but generally I'd consider splitting
> > > > exports as commits of their own.
> > > 
> > > -static bool
> > > +bool
> > > 
> > > into a separate commit?
> > > 
> > > I guess it makes sense for people whose salary depends on
> > > number of commits.
> > > We don't play these games.
> > 
> > What kind of argument is that anyway.
> 
> "Separate each *logical change* into a separate patch." [*]
> 
> To add, generally any user space visible space should be an
                                           ~~~~~
                                           change

BR, Jarkko
Roberto Sassu Aug. 26, 2022, 3:34 p.m. UTC | #6
On Fri, 2022-08-26 at 17:43 +0300, Jarkko Sakkinen wrote:
> On Fri, Aug 26, 2022 at 08:46:14AM +0300, Jarkko Sakkinen wrote:
> > On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
> > > On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <
> > > jarkko@kernel.org> wrote:
> > > > > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env
> > > > > *env, struct bpf_reg_state *reg,
> > > > > -                                  enum bpf_arg_type
> > > > > arg_type)
> > > > > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env,
> > > > > struct bpf_reg_state *reg,
> > > > > +                           enum bpf_arg_type arg_type)
> > > > >  {
> > > > >       struct bpf_func_state *state = func(env, reg);
> > > > >       int spi = get_spi(reg->off);
> > > > > --
> > > > > 2.25.1
> > > > > 
> > > > 
> > > > Might be niticking but generally I'd consider splitting
> > > > exports as commits of their own.
> > > 
> > > -static bool
> > > +bool
> > > 
> > > into a separate commit?
> > > 
> > > I guess it makes sense for people whose salary depends on
> > > number of commits.
> > > We don't play these games.
> > 
> > What kind of argument is that anyway.
> 
> "Separate each *logical change* into a separate patch." [*]

The logical change, as per the patch subject, is allowing the
possibility of including eBPF dynamic pointers in a kfunc definition.
It requires to call an existing function that was already defined
elsewhere.

Maybe I'm wrong, but I don't see only exporting a function definition
to an include file as a logical change. To me, the changes in this
patch are clearly connected. Or even better, they tell why the function
definition has been exported, that would not appear if moving the
function definition is a standalone patch.

> 
> To add, generally any user space visible space should be an
> isolated patch.

As far as I understood, definitions visible to user space should be in
include/uapi.

> 
> Please, stop posting nonsense.

If I may, saying this does not encourage people to try to submit their
code. I feel it is a bit strong, and I kindly ask you to express your
opinion in a more gentle way.

Thanks

Roberto
Jarkko Sakkinen Aug. 26, 2022, 4:32 p.m. UTC | #7
On Fri, Aug 26, 2022 at 05:34:57PM +0200, Roberto Sassu wrote:
> On Fri, 2022-08-26 at 17:43 +0300, Jarkko Sakkinen wrote:
> > On Fri, Aug 26, 2022 at 08:46:14AM +0300, Jarkko Sakkinen wrote:
> > > On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
> > > > On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <
> > > > jarkko@kernel.org> wrote:
> > > > > > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env
> > > > > > *env, struct bpf_reg_state *reg,
> > > > > > -                                  enum bpf_arg_type
> > > > > > arg_type)
> > > > > > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env,
> > > > > > struct bpf_reg_state *reg,
> > > > > > +                           enum bpf_arg_type arg_type)
> > > > > >  {
> > > > > >       struct bpf_func_state *state = func(env, reg);
> > > > > >       int spi = get_spi(reg->off);
> > > > > > --
> > > > > > 2.25.1
> > > > > > 
> > > > > 
> > > > > Might be niticking but generally I'd consider splitting
> > > > > exports as commits of their own.
> > > > 
> > > > -static bool
> > > > +bool
> > > > 
> > > > into a separate commit?
> > > > 
> > > > I guess it makes sense for people whose salary depends on
> > > > number of commits.
> > > > We don't play these games.
> > > 
> > > What kind of argument is that anyway.
> > 
> > "Separate each *logical change* into a separate patch." [*]
> 
> The logical change, as per the patch subject, is allowing the
> possibility of including eBPF dynamic pointers in a kfunc definition.
> It requires to call an existing function that was already defined
> elsewhere.
> 
> Maybe I'm wrong, but I don't see only exporting a function definition
> to an include file as a logical change. To me, the changes in this
> patch are clearly connected. Or even better, they tell why the function
> definition has been exported, that would not appear if moving the
> function definition is a standalone patch.
> 
> > 
> > To add, generally any user space visible space should be an
> > isolated patch.
> 
> As far as I understood, definitions visible to user space should be in
> include/uapi.

It does change e.g. the output of kallsyms.

It's not ABI but it's still user space visble.

> 
> > 
> > Please, stop posting nonsense.
> 
> If I may, saying this does not encourage people to try to submit their
> code. I feel it is a bit strong, and I kindly ask you to express your
> opinion in a more gentle way.

I agree. That's why I was wondering what is this nonsense
about salary and games.

BR, Jarkko
Jarkko Sakkinen Aug. 26, 2022, 4:41 p.m. UTC | #8
On Fri, Aug 26, 2022 at 07:32:54PM +0300, Jarkko Sakkinen wrote:
> On Fri, Aug 26, 2022 at 05:34:57PM +0200, Roberto Sassu wrote:
> > On Fri, 2022-08-26 at 17:43 +0300, Jarkko Sakkinen wrote:
> > > On Fri, Aug 26, 2022 at 08:46:14AM +0300, Jarkko Sakkinen wrote:
> > > > On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
> > > > > On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <
> > > > > jarkko@kernel.org> wrote:
> > > > > > > -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env
> > > > > > > *env, struct bpf_reg_state *reg,
> > > > > > > -                                  enum bpf_arg_type
> > > > > > > arg_type)
> > > > > > > +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env,
> > > > > > > struct bpf_reg_state *reg,
> > > > > > > +                           enum bpf_arg_type arg_type)
> > > > > > >  {
> > > > > > >       struct bpf_func_state *state = func(env, reg);
> > > > > > >       int spi = get_spi(reg->off);
> > > > > > > --
> > > > > > > 2.25.1
> > > > > > > 
> > > > > > 
> > > > > > Might be niticking but generally I'd consider splitting
> > > > > > exports as commits of their own.
> > > > > 
> > > > > -static bool
> > > > > +bool
> > > > > 
> > > > > into a separate commit?
> > > > > 
> > > > > I guess it makes sense for people whose salary depends on
> > > > > number of commits.
> > > > > We don't play these games.
> > > > 
> > > > What kind of argument is that anyway.
> > > 
> > > "Separate each *logical change* into a separate patch." [*]
> > 
> > The logical change, as per the patch subject, is allowing the
> > possibility of including eBPF dynamic pointers in a kfunc definition.
> > It requires to call an existing function that was already defined
> > elsewhere.
> > 
> > Maybe I'm wrong, but I don't see only exporting a function definition
> > to an include file as a logical change. To me, the changes in this
> > patch are clearly connected. Or even better, they tell why the function
> > definition has been exported, that would not appear if moving the
> > function definition is a standalone patch.
> > 
> > > 
> > > To add, generally any user space visible space should be an
> > > isolated patch.
> > 
> > As far as I understood, definitions visible to user space should be in
> > include/uapi.
> 
> It does change e.g. the output of kallsyms.
> 
> It's not ABI but it's still user space visble.
> 
> > 
> > > 
> > > Please, stop posting nonsense.
> > 
> > If I may, saying this does not encourage people to try to submit their
> > code. I feel it is a bit strong, and I kindly ask you to express your
> > opinion in a more gentle way.
> 
> I agree. That's why I was wondering what is this nonsense
> about salary and games.

Please denote that I started my review with "Might be nitpicking...".

It's neither particularly disencouraging nor enforcing for anyone.

The blast that came after that, on the other hand, IMHO meets
exactly those standards.

BR, Jarkko
Roberto Sassu Aug. 26, 2022, 7:10 p.m. UTC | #9
On 8/26/2022 6:41 PM, Jarkko Sakkinen wrote:
> On Fri, Aug 26, 2022 at 07:32:54PM +0300, Jarkko Sakkinen wrote:
>> On Fri, Aug 26, 2022 at 05:34:57PM +0200, Roberto Sassu wrote:
>>> On Fri, 2022-08-26 at 17:43 +0300, Jarkko Sakkinen wrote:
>>>> On Fri, Aug 26, 2022 at 08:46:14AM +0300, Jarkko Sakkinen wrote:
>>>>> On Thu, Aug 25, 2022 at 10:16:14PM -0700, Alexei Starovoitov wrote:
>>>>>> On Thu, Aug 25, 2022 at 9:54 PM Jarkko Sakkinen <
>>>>>> jarkko@kernel.org> wrote:
>>>>>>>> -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env
>>>>>>>> *env, struct bpf_reg_state *reg,
>>>>>>>> -                                  enum bpf_arg_type
>>>>>>>> arg_type)
>>>>>>>> +bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env,
>>>>>>>> struct bpf_reg_state *reg,
>>>>>>>> +                           enum bpf_arg_type arg_type)
>>>>>>>>   {
>>>>>>>>        struct bpf_func_state *state = func(env, reg);
>>>>>>>>        int spi = get_spi(reg->off);
>>>>>>>> --
>>>>>>>> 2.25.1
>>>>>>>>
>>>>>>>
>>>>>>> Might be niticking but generally I'd consider splitting
>>>>>>> exports as commits of their own.
>>>>>>
>>>>>> -static bool
>>>>>> +bool
>>>>>>
>>>>>> into a separate commit?
>>>>>>
>>>>>> I guess it makes sense for people whose salary depends on
>>>>>> number of commits.
>>>>>> We don't play these games.
>>>>>
>>>>> What kind of argument is that anyway.
>>>>
>>>> "Separate each *logical change* into a separate patch." [*]
>>>
>>> The logical change, as per the patch subject, is allowing the
>>> possibility of including eBPF dynamic pointers in a kfunc definition.
>>> It requires to call an existing function that was already defined
>>> elsewhere.
>>>
>>> Maybe I'm wrong, but I don't see only exporting a function definition
>>> to an include file as a logical change. To me, the changes in this
>>> patch are clearly connected. Or even better, they tell why the function
>>> definition has been exported, that would not appear if moving the
>>> function definition is a standalone patch.
>>>
>>>>
>>>> To add, generally any user space visible space should be an
>>>> isolated patch.
>>>
>>> As far as I understood, definitions visible to user space should be in
>>> include/uapi.
>>
>> It does change e.g. the output of kallsyms.
>>
>> It's not ABI but it's still user space visble.
>>
>>>
>>>>
>>>> Please, stop posting nonsense.
>>>
>>> If I may, saying this does not encourage people to try to submit their
>>> code. I feel it is a bit strong, and I kindly ask you to express your
>>> opinion in a more gentle way.
>>
>> I agree. That's why I was wondering what is this nonsense
>> about salary and games.
> 
> Please denote that I started my review with "Might be nitpicking...".
> 
> It's neither particularly disencouraging nor enforcing for anyone.

Thanks for clarifying. Yes, it is not. Sorry, I misunderstood.

Roberto
diff mbox series

Patch

diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 2e3bad8640dc..55876fbdbae2 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -560,6 +560,9 @@  int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state
 			     u32 regno);
 int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
 		   u32 regno, u32 mem_size);
+bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env,
+			      struct bpf_reg_state *reg,
+			      enum bpf_arg_type arg_type);
 
 /* this lives here instead of in bpf.h because it needs to dereference tgt_prog */
 static inline u64 bpf_trampoline_compute_key(const struct bpf_prog *tgt_prog,
diff --git a/include/linux/btf.h b/include/linux/btf.h
index ad93c2d9cc1c..f546d368ac5d 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -52,6 +52,15 @@ 
 #define KF_SLEEPABLE    (1 << 5) /* kfunc may sleep */
 #define KF_DESTRUCTIVE  (1 << 6) /* kfunc performs destructive actions */
 
+/*
+ * Return the name of the passed struct, if exists, or halt the build if for
+ * example the structure gets renamed. In this way, developers have to revisit
+ * the code using that structure name, and update it accordingly.
+ */
+#define stringify_struct(x)			\
+	({ BUILD_BUG_ON(sizeof(struct x) < 0);	\
+	   __stringify(x); })
+
 struct btf;
 struct btf_member;
 struct btf_type;
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index e49b3b6d48ad..26cb548420af 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6362,15 +6362,20 @@  static int btf_check_func_arg_match(struct bpf_verifier_env *env,
 
 			if (is_kfunc) {
 				bool arg_mem_size = i + 1 < nargs && is_kfunc_arg_mem_size(btf, &args[i + 1], &regs[regno + 1]);
+				bool arg_dynptr = btf_type_is_struct(ref_t) &&
+						  !strcmp(ref_tname,
+							  stringify_struct(bpf_dynptr_kern));
 
 				/* Permit pointer to mem, but only when argument
 				 * type is pointer to scalar, or struct composed
 				 * (recursively) of scalars.
 				 * When arg_mem_size is true, the pointer can be
 				 * void *.
+				 * Also permit initialized dynamic pointers.
 				 */
 				if (!btf_type_is_scalar(ref_t) &&
 				    !__btf_type_is_scalar_struct(log, btf, ref_t, 0) &&
+				    !arg_dynptr &&
 				    (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
 					bpf_log(log,
 						"arg#%d pointer type %s %s must point to %sscalar, or struct with scalar\n",
@@ -6378,6 +6383,19 @@  static int btf_check_func_arg_match(struct bpf_verifier_env *env,
 					return -EINVAL;
 				}
 
+				if (arg_dynptr) {
+					if (!is_dynptr_reg_valid_init(env, reg,
+							ARG_PTR_TO_DYNPTR)) {
+						bpf_log(log,
+							"arg#%d pointer type %s %s must be initialized\n",
+							i, btf_type_str(ref_t),
+							ref_tname);
+						return -EINVAL;
+					}
+
+					continue;
+				}
+
 				/* Check for mem, len pair */
 				if (arg_mem_size) {
 					if (check_kfunc_mem_size_reg(env, &regs[regno + 1], regno + 1)) {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2c1f8069f7b7..aa834e7bb296 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -779,8 +779,8 @@  static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_
 	return true;
 }
 
-static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
-				     enum bpf_arg_type arg_type)
+bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+			      enum bpf_arg_type arg_type)
 {
 	struct bpf_func_state *state = func(env, reg);
 	int spi = get_spi(reg->off);