diff options
author | Andrii Nakryiko <andriin@fb.com> | 2019-02-28 18:31:24 -0500 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2019-02-28 19:31:48 -0500 |
commit | 91097fbee4c025ac72f91ae41feba3a822cc1316 (patch) | |
tree | 3e1fb0359be566403120bd51df1e921c3b217d83 /tools/lib/bpf/btf.c | |
parent | 51edf5f6e015c48b62e24ab2fbcad8885ca1c74e (diff) |
btf: fix bug with resolving STRUCT/UNION into corresponding FWD
When checking available canonical candidates for struct/union algorithm
utilizes btf_dedup_is_equiv to determine if candidate is suitable. This
check is not enough when candidate is corresponding FWD for that
struct/union, because according to equivalence logic they are
equivalent. When it so happens that FWD and STRUCT/UNION end in hashing
to the same bucket, it's possible to create remapping loop from FWD to
STRUCT and STRUCT to same FWD, which will cause btf_dedup() to loop
forever.
This patch fixes the issue by additionally checking that type and
canonical candidate are strictly equal (utilizing btf_equal_struct).
Fixes: d5caef5b5655 ("btf: add BTF types deduplication algorithm")
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools/lib/bpf/btf.c')
-rw-r--r-- | tools/lib/bpf/btf.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 820f7fc8ebcc..1b8d8cdd3575 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c | |||
@@ -1663,7 +1663,7 @@ static __u32 btf_hash_struct(struct btf_type *t) | |||
1663 | * IDs. This check is performed during type graph equivalence check and | 1663 | * IDs. This check is performed during type graph equivalence check and |
1664 | * referenced types equivalence is checked separately. | 1664 | * referenced types equivalence is checked separately. |
1665 | */ | 1665 | */ |
1666 | static bool btf_equal_struct(struct btf_type *t1, struct btf_type *t2) | 1666 | static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2) |
1667 | { | 1667 | { |
1668 | struct btf_member *m1, *m2; | 1668 | struct btf_member *m1, *m2; |
1669 | __u16 vlen; | 1669 | __u16 vlen; |
@@ -2124,7 +2124,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, | |||
2124 | struct btf_member *cand_m, *canon_m; | 2124 | struct btf_member *cand_m, *canon_m; |
2125 | __u16 vlen; | 2125 | __u16 vlen; |
2126 | 2126 | ||
2127 | if (!btf_equal_struct(cand_type, canon_type)) | 2127 | if (!btf_shallow_equal_struct(cand_type, canon_type)) |
2128 | return 0; | 2128 | return 0; |
2129 | vlen = BTF_INFO_VLEN(cand_type->info); | 2129 | vlen = BTF_INFO_VLEN(cand_type->info); |
2130 | cand_m = (struct btf_member *)(cand_type + 1); | 2130 | cand_m = (struct btf_member *)(cand_type + 1); |
@@ -2265,7 +2265,7 @@ static void btf_dedup_merge_hypot_map(struct btf_dedup *d) | |||
2265 | static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id) | 2265 | static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id) |
2266 | { | 2266 | { |
2267 | struct btf_dedup_node *cand_node; | 2267 | struct btf_dedup_node *cand_node; |
2268 | struct btf_type *t; | 2268 | struct btf_type *cand_type, *t; |
2269 | /* if we don't find equivalent type, then we are canonical */ | 2269 | /* if we don't find equivalent type, then we are canonical */ |
2270 | __u32 new_id = type_id; | 2270 | __u32 new_id = type_id; |
2271 | __u16 kind; | 2271 | __u16 kind; |
@@ -2285,6 +2285,20 @@ static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id) | |||
2285 | for_each_dedup_cand(d, h, cand_node) { | 2285 | for_each_dedup_cand(d, h, cand_node) { |
2286 | int eq; | 2286 | int eq; |
2287 | 2287 | ||
2288 | /* | ||
2289 | * Even though btf_dedup_is_equiv() checks for | ||
2290 | * btf_shallow_equal_struct() internally when checking two | ||
2291 | * structs (unions) for equivalence, we need to guard here | ||
2292 | * from picking matching FWD type as a dedup candidate. | ||
2293 | * This can happen due to hash collision. In such case just | ||
2294 | * relying on btf_dedup_is_equiv() would lead to potentially | ||
2295 | * creating a loop (FWD -> STRUCT and STRUCT -> FWD), because | ||
2296 | * FWD and compatible STRUCT/UNION are considered equivalent. | ||
2297 | */ | ||
2298 | cand_type = d->btf->types[cand_node->type_id]; | ||
2299 | if (!btf_shallow_equal_struct(t, cand_type)) | ||
2300 | continue; | ||
2301 | |||
2288 | btf_dedup_clear_hypot_map(d); | 2302 | btf_dedup_clear_hypot_map(d); |
2289 | eq = btf_dedup_is_equiv(d, type_id, cand_node->type_id); | 2303 | eq = btf_dedup_is_equiv(d, type_id, cand_node->type_id); |
2290 | if (eq < 0) | 2304 | if (eq < 0) |