btf->struct_meta_tab is populated by btf_parse_struct_metas in btf.c. There, a BTF record is created for any type containing a spin_lock or any next-gen datastructure node/head. Currently, for non-MAP_VALUE types, reg_btf_record will only search for a record using struct_meta_tab if the reg->type exactly matches (PTR_TO_BTF_ID | MEM_ALLOC). This exact match is too strict: an "allocated obj" type - returned from bpf_obj_new - might pick up other flags while working its way through the program. Loosen the check to be exact for base_type and just use MEM_ALLOC mask for type_flag. This patch is marked Fixes as the original intent of reg_btf_record was unlikely to have been to fail finding btf_record for valid alloc obj types with additional flags, some of which (e.g. PTR_UNTRUSTED) are valid register type states for alloc obj independent of this series. However, I didn't find a specific broken repro case outside of this series' added functionality, so it's possible that nothing was triggering this logic error before.
Unified · Split
| @@ -451,6 +451,11 @@ static bool reg_type_not_null(enum bpf_reg_type type) · 450 unmodified lines | |||
| 451 | type == PTR_TO_SOCK_COMMON; | 451 | type == PTR_TO_SOCK_COMMON; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | static bool type_is_ptr_alloc_obj(u32 type) | ||
| 455 | { | ||
| 456 | return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC; | ||
| 457 | } | ||
| 458 | |||
| 454 | static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) | 459 | static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) |
| 455 | { | 460 | { |
| 456 | struct btf_record *rec = NULL; | 461 | struct btf_record *rec = NULL; |
| @@ -458,7 +463,7 @@ static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) · 1 unmodified line | |||
| 458 | 463 | ||
| 459 | if (reg->type == PTR_TO_MAP_VALUE) { | 464 | if (reg->type == PTR_TO_MAP_VALUE) { |
| 460 | rec = reg->map_ptr->record; | 465 | rec = reg->map_ptr->record; |
| 461 | } else if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC)) { | 466 | } else if (type_is_ptr_alloc_obj(reg->type)) { |
| 462 | meta = btf_find_struct_meta(reg->btf, reg->btf_id); | 467 | meta = btf_find_struct_meta(reg->btf, reg->btf_id); |
| 463 | if (meta) | 468 | if (meta) |
| 464 | rec = meta->record; | 469 | rec = meta->record; |