diff mbox series

[bpf-next,1/3] bpf: Introduce BTF_TYPE_SAFE_TRUSTED_UNION

Message ID 20230709025912.3837-2-laoar.shao@gmail.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series bpf: Introduce union trusted | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 24 this patch: 24
netdev/cc_maintainers success CCed 12 of 12 maintainers
netdev/build_clang fail Errors and warnings before: 21 this patch: 23
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 24 this patch: 24
netdev/checkpatch warning CHECK: Alignment should match open parenthesis CHECK: Please don't use multiple blank lines WARNING: line length of 82 exceeds 80 columns WARNING: line length of 94 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on s390x with gcc

Commit Message

Yafang Shao July 9, 2023, 2:59 a.m. UTC
When we are verifying a field in a union, we may unexpectedly verify
another field which has the same offset in this union. So in such case,
we should annotate that field as PTR_UNTRUSTED. However, in some cases
we are sure some fields in a union is safe and then we can add them into
BTF_TYPE_SAFE_TRUSTED_UNION allow list.

Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
 kernel/bpf/btf.c      | 20 +++++++++-----------
 kernel/bpf/verifier.c | 21 +++++++++++++++++++++
 2 files changed, 30 insertions(+), 11 deletions(-)

Comments

Stanislav Fomichev July 10, 2023, 4:59 p.m. UTC | #1
On 07/09, Yafang Shao wrote:
> When we are verifying a field in a union, we may unexpectedly verify
> another field which has the same offset in this union. So in such case,
> we should annotate that field as PTR_UNTRUSTED. However, in some cases
> we are sure some fields in a union is safe and then we can add them into
> BTF_TYPE_SAFE_TRUSTED_UNION allow list.
> 
> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
> ---
>  kernel/bpf/btf.c      | 20 +++++++++-----------
>  kernel/bpf/verifier.c | 21 +++++++++++++++++++++
>  2 files changed, 30 insertions(+), 11 deletions(-)
> 
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 3dd47451f097..fae6fc24a845 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -6133,7 +6133,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
>  	const char *tname, *mname, *tag_value;
>  	u32 vlen, elem_id, mid;
>  
> -	*flag = 0;
>  again:
>  	if (btf_type_is_modifier(t))
>  		t = btf_type_skip_modifiers(btf, t->type, NULL);
> @@ -6144,6 +6143,14 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
>  	}
>  
>  	vlen = btf_type_vlen(t);
> +	if (BTF_INFO_KIND(t->info) == BTF_KIND_UNION && vlen != 1 && !(*flag & PTR_UNTRUSTED))
> +		/*
> +		 * walking unions yields untrusted pointers
> +		 * with exception of __bpf_md_ptr and other
> +		 * unions with a single member
> +		 */
> +		*flag |= PTR_UNTRUSTED;
> +
>  	if (off + size > t->size) {
>  		/* If the last element is a variable size array, we may
>  		 * need to relax the rule.
> @@ -6304,15 +6311,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
>  		 * of this field or inside of this struct
>  		 */
>  		if (btf_type_is_struct(mtype)) {
> -			if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
> -			    btf_type_vlen(mtype) != 1)
> -				/*
> -				 * walking unions yields untrusted pointers
> -				 * with exception of __bpf_md_ptr and other
> -				 * unions with a single member
> -				 */
> -				*flag |= PTR_UNTRUSTED;
> -
>  			/* our field must be inside that union or struct */
>  			t = mtype;
>  
> @@ -6478,7 +6476,7 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log,
>  			  bool strict)
>  {
>  	const struct btf_type *type;
> -	enum bpf_type_flag flag;
> +	enum bpf_type_flag flag = 0;
>  	int err;
>  
>  	/* Are we already done? */
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 11e54dd8b6dd..1fb0a64f5bce 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5847,6 +5847,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
>  #define BTF_TYPE_SAFE_RCU(__type)  __PASTE(__type, __safe_rcu)
>  #define BTF_TYPE_SAFE_RCU_OR_NULL(__type)  __PASTE(__type, __safe_rcu_or_null)
>  #define BTF_TYPE_SAFE_TRUSTED(__type)  __PASTE(__type, __safe_trusted)
> +#define BTF_TYPE_SAFE_TRUSTED_UNION(__type)  __PASTE(__type, __safe_trusted_union)
>  
>  /*
>   * Allow list few fields as RCU trusted or full trusted.
> @@ -5914,6 +5915,11 @@ BTF_TYPE_SAFE_TRUSTED(struct socket) {
>  	struct sock *sk;
>  };
>  


[..]

> +/* union trusted: these fields are trusted even in a uion */
> +BTF_TYPE_SAFE_TRUSTED_UNION(struct sk_buff) {
> +	struct sock *sk;
> +};

Does it say that sk member of sk_buff is always dereferencable?
Why is it universally safe?
In general, I don't really understand why it's safe to statically
mark the members this way. Shouldn't it depend on the context?
Alexei Starovoitov July 11, 2023, 2:55 a.m. UTC | #2
On Sat, Jul 8, 2023 at 7:59 PM Yafang Shao <laoar.shao@gmail.com> wrote:
>
> When we are verifying a field in a union, we may unexpectedly verify
> another field which has the same offset in this union. So in such case,
> we should annotate that field as PTR_UNTRUSTED. However, in some cases
> we are sure some fields in a union is safe and then we can add them into
> BTF_TYPE_SAFE_TRUSTED_UNION allow list.
>
> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
> ---
>  kernel/bpf/btf.c      | 20 +++++++++-----------
>  kernel/bpf/verifier.c | 21 +++++++++++++++++++++
>  2 files changed, 30 insertions(+), 11 deletions(-)
>
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 3dd47451f097..fae6fc24a845 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -6133,7 +6133,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
>         const char *tname, *mname, *tag_value;
>         u32 vlen, elem_id, mid;
>
> -       *flag = 0;
>  again:
>         if (btf_type_is_modifier(t))
>                 t = btf_type_skip_modifiers(btf, t->type, NULL);
> @@ -6144,6 +6143,14 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
>         }
>
>         vlen = btf_type_vlen(t);
> +       if (BTF_INFO_KIND(t->info) == BTF_KIND_UNION && vlen != 1 && !(*flag & PTR_UNTRUSTED))
> +               /*
> +                * walking unions yields untrusted pointers
> +                * with exception of __bpf_md_ptr and other
> +                * unions with a single member
> +                */
> +               *flag |= PTR_UNTRUSTED;
> +
>         if (off + size > t->size) {
>                 /* If the last element is a variable size array, we may
>                  * need to relax the rule.
> @@ -6304,15 +6311,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
>                  * of this field or inside of this struct
>                  */
>                 if (btf_type_is_struct(mtype)) {
> -                       if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
> -                           btf_type_vlen(mtype) != 1)
> -                               /*
> -                                * walking unions yields untrusted pointers
> -                                * with exception of __bpf_md_ptr and other
> -                                * unions with a single member
> -                                */
> -                               *flag |= PTR_UNTRUSTED;
> -
>                         /* our field must be inside that union or struct */
>                         t = mtype;
>
> @@ -6478,7 +6476,7 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log,
>                           bool strict)
>  {
>         const struct btf_type *type;
> -       enum bpf_type_flag flag;
> +       enum bpf_type_flag flag = 0;
>         int err;
>
>         /* Are we already done? */
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 11e54dd8b6dd..1fb0a64f5bce 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5847,6 +5847,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
>  #define BTF_TYPE_SAFE_RCU(__type)  __PASTE(__type, __safe_rcu)
>  #define BTF_TYPE_SAFE_RCU_OR_NULL(__type)  __PASTE(__type, __safe_rcu_or_null)
>  #define BTF_TYPE_SAFE_TRUSTED(__type)  __PASTE(__type, __safe_trusted)
> +#define BTF_TYPE_SAFE_TRUSTED_UNION(__type)  __PASTE(__type, __safe_trusted_union)
>
>  /*
>   * Allow list few fields as RCU trusted or full trusted.
> @@ -5914,6 +5915,11 @@ BTF_TYPE_SAFE_TRUSTED(struct socket) {
>         struct sock *sk;
>  };
>
> +/* union trusted: these fields are trusted even in a uion */
> +BTF_TYPE_SAFE_TRUSTED_UNION(struct sk_buff) {
> +       struct sock *sk;
> +};

Why is this needed?
We already have:
BTF_TYPE_SAFE_RCU_OR_NULL(struct sk_buff) {
        struct sock *sk;
};

> +       /* Clear the PTR_UNTRUSTED for the fields which are in the allow list */
> +       if (type_is_trusted_union(env, reg, field_name, btf_id))
> +               flag &= ~PTR_UNTRUSTED;

we cannot do this unconditionally.
The type_is_rcu_or_null() check applies only after
 in_rcu_cs(env) && !type_may_be_null(reg->type)).
Yafang Shao July 11, 2023, 2:20 p.m. UTC | #3
On Tue, Jul 11, 2023 at 12:59 AM Stanislav Fomichev <sdf@google.com> wrote:
>
> On 07/09, Yafang Shao wrote:
> > When we are verifying a field in a union, we may unexpectedly verify
> > another field which has the same offset in this union. So in such case,
> > we should annotate that field as PTR_UNTRUSTED. However, in some cases
> > we are sure some fields in a union is safe and then we can add them into
> > BTF_TYPE_SAFE_TRUSTED_UNION allow list.
> >
> > Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
> > ---
> >  kernel/bpf/btf.c      | 20 +++++++++-----------
> >  kernel/bpf/verifier.c | 21 +++++++++++++++++++++
> >  2 files changed, 30 insertions(+), 11 deletions(-)
> >
> > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> > index 3dd47451f097..fae6fc24a845 100644
> > --- a/kernel/bpf/btf.c
> > +++ b/kernel/bpf/btf.c
> > @@ -6133,7 +6133,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> >       const char *tname, *mname, *tag_value;
> >       u32 vlen, elem_id, mid;
> >
> > -     *flag = 0;
> >  again:
> >       if (btf_type_is_modifier(t))
> >               t = btf_type_skip_modifiers(btf, t->type, NULL);
> > @@ -6144,6 +6143,14 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> >       }
> >
> >       vlen = btf_type_vlen(t);
> > +     if (BTF_INFO_KIND(t->info) == BTF_KIND_UNION && vlen != 1 && !(*flag & PTR_UNTRUSTED))
> > +             /*
> > +              * walking unions yields untrusted pointers
> > +              * with exception of __bpf_md_ptr and other
> > +              * unions with a single member
> > +              */
> > +             *flag |= PTR_UNTRUSTED;
> > +
> >       if (off + size > t->size) {
> >               /* If the last element is a variable size array, we may
> >                * need to relax the rule.
> > @@ -6304,15 +6311,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> >                * of this field or inside of this struct
> >                */
> >               if (btf_type_is_struct(mtype)) {
> > -                     if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
> > -                         btf_type_vlen(mtype) != 1)
> > -                             /*
> > -                              * walking unions yields untrusted pointers
> > -                              * with exception of __bpf_md_ptr and other
> > -                              * unions with a single member
> > -                              */
> > -                             *flag |= PTR_UNTRUSTED;
> > -
> >                       /* our field must be inside that union or struct */
> >                       t = mtype;
> >
> > @@ -6478,7 +6476,7 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log,
> >                         bool strict)
> >  {
> >       const struct btf_type *type;
> > -     enum bpf_type_flag flag;
> > +     enum bpf_type_flag flag = 0;
> >       int err;
> >
> >       /* Are we already done? */
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 11e54dd8b6dd..1fb0a64f5bce 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -5847,6 +5847,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
> >  #define BTF_TYPE_SAFE_RCU(__type)  __PASTE(__type, __safe_rcu)
> >  #define BTF_TYPE_SAFE_RCU_OR_NULL(__type)  __PASTE(__type, __safe_rcu_or_null)
> >  #define BTF_TYPE_SAFE_TRUSTED(__type)  __PASTE(__type, __safe_trusted)
> > +#define BTF_TYPE_SAFE_TRUSTED_UNION(__type)  __PASTE(__type, __safe_trusted_union)
> >
> >  /*
> >   * Allow list few fields as RCU trusted or full trusted.
> > @@ -5914,6 +5915,11 @@ BTF_TYPE_SAFE_TRUSTED(struct socket) {
> >       struct sock *sk;
> >  };
> >
>
>
> [..]
>
> > +/* union trusted: these fields are trusted even in a uion */
> > +BTF_TYPE_SAFE_TRUSTED_UNION(struct sk_buff) {
> > +     struct sock *sk;
> > +};
>
> Does it say that sk member of sk_buff is always dereferencable?
> Why is it universally safe?
> In general, I don't really understand why it's safe to statically
> mark the members this way. Shouldn't it depend on the context?

Right. It should depend on the context. Will change it.
Yafang Shao July 11, 2023, 2:21 p.m. UTC | #4
On Tue, Jul 11, 2023 at 10:56 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Sat, Jul 8, 2023 at 7:59 PM Yafang Shao <laoar.shao@gmail.com> wrote:
> >
> > When we are verifying a field in a union, we may unexpectedly verify
> > another field which has the same offset in this union. So in such case,
> > we should annotate that field as PTR_UNTRUSTED. However, in some cases
> > we are sure some fields in a union is safe and then we can add them into
> > BTF_TYPE_SAFE_TRUSTED_UNION allow list.
> >
> > Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
> > ---
> >  kernel/bpf/btf.c      | 20 +++++++++-----------
> >  kernel/bpf/verifier.c | 21 +++++++++++++++++++++
> >  2 files changed, 30 insertions(+), 11 deletions(-)
> >
> > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> > index 3dd47451f097..fae6fc24a845 100644
> > --- a/kernel/bpf/btf.c
> > +++ b/kernel/bpf/btf.c
> > @@ -6133,7 +6133,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> >         const char *tname, *mname, *tag_value;
> >         u32 vlen, elem_id, mid;
> >
> > -       *flag = 0;
> >  again:
> >         if (btf_type_is_modifier(t))
> >                 t = btf_type_skip_modifiers(btf, t->type, NULL);
> > @@ -6144,6 +6143,14 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> >         }
> >
> >         vlen = btf_type_vlen(t);
> > +       if (BTF_INFO_KIND(t->info) == BTF_KIND_UNION && vlen != 1 && !(*flag & PTR_UNTRUSTED))
> > +               /*
> > +                * walking unions yields untrusted pointers
> > +                * with exception of __bpf_md_ptr and other
> > +                * unions with a single member
> > +                */
> > +               *flag |= PTR_UNTRUSTED;
> > +
> >         if (off + size > t->size) {
> >                 /* If the last element is a variable size array, we may
> >                  * need to relax the rule.
> > @@ -6304,15 +6311,6 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> >                  * of this field or inside of this struct
> >                  */
> >                 if (btf_type_is_struct(mtype)) {
> > -                       if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
> > -                           btf_type_vlen(mtype) != 1)
> > -                               /*
> > -                                * walking unions yields untrusted pointers
> > -                                * with exception of __bpf_md_ptr and other
> > -                                * unions with a single member
> > -                                */
> > -                               *flag |= PTR_UNTRUSTED;
> > -
> >                         /* our field must be inside that union or struct */
> >                         t = mtype;
> >
> > @@ -6478,7 +6476,7 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log,
> >                           bool strict)
> >  {
> >         const struct btf_type *type;
> > -       enum bpf_type_flag flag;
> > +       enum bpf_type_flag flag = 0;
> >         int err;
> >
> >         /* Are we already done? */
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 11e54dd8b6dd..1fb0a64f5bce 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -5847,6 +5847,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
> >  #define BTF_TYPE_SAFE_RCU(__type)  __PASTE(__type, __safe_rcu)
> >  #define BTF_TYPE_SAFE_RCU_OR_NULL(__type)  __PASTE(__type, __safe_rcu_or_null)
> >  #define BTF_TYPE_SAFE_TRUSTED(__type)  __PASTE(__type, __safe_trusted)
> > +#define BTF_TYPE_SAFE_TRUSTED_UNION(__type)  __PASTE(__type, __safe_trusted_union)
> >
> >  /*
> >   * Allow list few fields as RCU trusted or full trusted.
> > @@ -5914,6 +5915,11 @@ BTF_TYPE_SAFE_TRUSTED(struct socket) {
> >         struct sock *sk;
> >  };
> >
> > +/* union trusted: these fields are trusted even in a uion */
> > +BTF_TYPE_SAFE_TRUSTED_UNION(struct sk_buff) {
> > +       struct sock *sk;
> > +};
>
> Why is this needed?

Will discard it.

> We already have:
> BTF_TYPE_SAFE_RCU_OR_NULL(struct sk_buff) {
>         struct sock *sk;
> };
>
> > +       /* Clear the PTR_UNTRUSTED for the fields which are in the allow list */
> > +       if (type_is_trusted_union(env, reg, field_name, btf_id))
> > +               flag &= ~PTR_UNTRUSTED;
>
> we cannot do this unconditionally.
> The type_is_rcu_or_null() check applies only after
>  in_rcu_cs(env) && !type_may_be_null(reg->type)).

Thanks for the explanation. Will change it.
diff mbox series

Patch

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 3dd47451f097..fae6fc24a845 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6133,7 +6133,6 @@  static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
 	const char *tname, *mname, *tag_value;
 	u32 vlen, elem_id, mid;
 
-	*flag = 0;
 again:
 	if (btf_type_is_modifier(t))
 		t = btf_type_skip_modifiers(btf, t->type, NULL);
@@ -6144,6 +6143,14 @@  static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
 	}
 
 	vlen = btf_type_vlen(t);
+	if (BTF_INFO_KIND(t->info) == BTF_KIND_UNION && vlen != 1 && !(*flag & PTR_UNTRUSTED))
+		/*
+		 * walking unions yields untrusted pointers
+		 * with exception of __bpf_md_ptr and other
+		 * unions with a single member
+		 */
+		*flag |= PTR_UNTRUSTED;
+
 	if (off + size > t->size) {
 		/* If the last element is a variable size array, we may
 		 * need to relax the rule.
@@ -6304,15 +6311,6 @@  static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
 		 * of this field or inside of this struct
 		 */
 		if (btf_type_is_struct(mtype)) {
-			if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
-			    btf_type_vlen(mtype) != 1)
-				/*
-				 * walking unions yields untrusted pointers
-				 * with exception of __bpf_md_ptr and other
-				 * unions with a single member
-				 */
-				*flag |= PTR_UNTRUSTED;
-
 			/* our field must be inside that union or struct */
 			t = mtype;
 
@@ -6478,7 +6476,7 @@  bool btf_struct_ids_match(struct bpf_verifier_log *log,
 			  bool strict)
 {
 	const struct btf_type *type;
-	enum bpf_type_flag flag;
+	enum bpf_type_flag flag = 0;
 	int err;
 
 	/* Are we already done? */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 11e54dd8b6dd..1fb0a64f5bce 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5847,6 +5847,7 @@  static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
 #define BTF_TYPE_SAFE_RCU(__type)  __PASTE(__type, __safe_rcu)
 #define BTF_TYPE_SAFE_RCU_OR_NULL(__type)  __PASTE(__type, __safe_rcu_or_null)
 #define BTF_TYPE_SAFE_TRUSTED(__type)  __PASTE(__type, __safe_trusted)
+#define BTF_TYPE_SAFE_TRUSTED_UNION(__type)  __PASTE(__type, __safe_trusted_union)
 
 /*
  * Allow list few fields as RCU trusted or full trusted.
@@ -5914,6 +5915,11 @@  BTF_TYPE_SAFE_TRUSTED(struct socket) {
 	struct sock *sk;
 };
 
+/* union trusted: these fields are trusted even in a uion */
+BTF_TYPE_SAFE_TRUSTED_UNION(struct sk_buff) {
+	struct sock *sk;
+};
+
 static bool type_is_rcu(struct bpf_verifier_env *env,
 			struct bpf_reg_state *reg,
 			const char *field_name, u32 btf_id)
@@ -5950,6 +5956,17 @@  static bool type_is_trusted(struct bpf_verifier_env *env,
 	return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, "__safe_trusted");
 }
 
+
+static bool type_is_trusted_union(struct bpf_verifier_env *env,
+			    struct bpf_reg_state *reg,
+			    const char *field_name, u32 btf_id)
+{
+	BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_UNION(struct sk_buff));
+
+	return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id,
+					  "__safe_trusted_union");
+}
+
 static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
 				   struct bpf_reg_state *regs,
 				   int regno, int off, int size,
@@ -6087,6 +6104,10 @@  static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
 		clear_trusted_flags(&flag);
 	}
 
+	/* Clear the PTR_UNTRUSTED for the fields which are in the allow list */
+	if (type_is_trusted_union(env, reg, field_name, btf_id))
+		flag &= ~PTR_UNTRUSTED;
+
 	if (atype == BPF_READ && value_regno >= 0)
 		mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag);