btf_find_struct_member() traverses into nested anonymous structures and unions by pushing members with !member->name_off onto anon_stack. However, it does not consider the unnamed bitfields (e.g. `int : 5` or `unsigned int : 0`) which also have member->name_off == 0. If such an unnamed bitfield is pushed to anon_stack, the btf_find_struct_member() return an error even if there are other valid entries in anon_stack. To fix this, only push unnamed struct/union members to anon_stack. Also move the btf_type_is_struct() check to the entry of this function because now it is sure only struct/union are pushed to anon_stack. Link: https://lore.kernel.org/all/178827249775.123716.7813217688423513612.stgit@devnote2/
Unified · Split
| @@ -74,24 +74,24 @@ const struct btf_member *btf_find_struct_member(struct btf *btf, · 73 unmodified lines | ||
| 74 | 74 | { |
| 75 | 75 | struct btf_anon_stack *anon_stack; |
| 76 | 76 | const struct btf_member *member; |
| 77 | + const struct btf_type *mtype; | |
| 77 | 78 | u32 tid, cur_offset = 0; |
| 78 | 79 | const char *name; |
| 79 | 80 | int i, top = 0; |
| 80 | 81 | |
| 82 | + if (!btf_type_is_struct(type)) | |
| 83 | + return ERR_PTR(-EINVAL); | |
| 84 | + | |
| 81 | 85 | anon_stack = kzalloc_objs(*anon_stack, BTF_ANON_STACK_MAX); |
| 82 | 86 | if (!anon_stack) |
| 83 | 87 | return ERR_PTR(-ENOMEM); |
| 84 | 88 | |
| 85 | 89 | retry: |
| 86 | − if (!btf_type_is_struct(type)) { | |
| 87 | − member = ERR_PTR(-EINVAL); | |
| 88 | − goto out; | |
| 89 | − } | |
| 90 | − | |
| 91 | 90 | for_each_member(i, type, member) { |
| 92 | 91 | if (!member->name_off) { |
| 93 | 92 | /* Anonymous union/struct: push it for later use */ |
| 94 | − if (btf_type_skip_modifiers(btf, member->type, &tid) && | |
| 93 | + mtype = btf_type_skip_modifiers(btf, member->type, &tid); | |
| 94 | + if (mtype && btf_type_is_struct(mtype) && | |
| 95 | 95 | top < BTF_ANON_STACK_MAX) { |
| 96 | 96 | anon_stack[top].tid = tid; |
| 97 | 97 | anon_stack[top++].offset = |