Skip to content

Commit 8d98459

Browse files
Xu KuohaiKernel Patches Daemon
authored andcommitted
libbpf: Fix use-after-free in btf_dump_name_dups
ASAN reports an use-after-free in btf_dump_name_dups: ERROR: AddressSanitizer: heap-use-after-free on address 0xffff927006db at pc 0xaaaab5dfb618 bp 0xffffdd89b890 sp 0xffffdd89b928 READ of size 2 at 0xffff927006db thread T0 #0 0xaaaab5dfb614 in __interceptor_strcmp.part.0 (test_progs+0x21b614) #1 0xaaaab635f144 in str_equal_fn tools/lib/bpf/btf_dump.c:127 #2 0xaaaab635e3e0 in hashmap_find_entry tools/lib/bpf/hashmap.c:143 #3 0xaaaab635e72c in hashmap__find tools/lib/bpf/hashmap.c:212 #4 0xaaaab6362258 in btf_dump_name_dups tools/lib/bpf/btf_dump.c:1525 #5 0xaaaab636240c in btf_dump_resolve_name tools/lib/bpf/btf_dump.c:1552 #6 0xaaaab6362598 in btf_dump_type_name tools/lib/bpf/btf_dump.c:1567 #7 0xaaaab6360b48 in btf_dump_emit_struct_def tools/lib/bpf/btf_dump.c:912 #8 0xaaaab6360630 in btf_dump_emit_type tools/lib/bpf/btf_dump.c:798 #9 0xaaaab635f720 in btf_dump__dump_type tools/lib/bpf/btf_dump.c:282 #10 0xaaaab608523c in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:236 #11 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875 #12 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062 #13 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697 #14 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308 #15 0xaaaab5d65990 (test_progs+0x185990) 0xffff927006db is located 11 bytes inside of 16-byte region [0xffff927006d0,0xffff927006e0) freed by thread T0 here: #0 0xaaaab5e2c7c4 in realloc (test_progs+0x24c7c4) #1 0xaaaab634f4a0 in libbpf_reallocarray tools/lib/bpf/libbpf_internal.h:191 #2 0xaaaab634f840 in libbpf_add_mem tools/lib/bpf/btf.c:163 #3 0xaaaab636643c in strset_add_str_mem tools/lib/bpf/strset.c:106 #4 0xaaaab6366560 in strset__add_str tools/lib/bpf/strset.c:157 #5 0xaaaab6352d70 in btf__add_str tools/lib/bpf/btf.c:1519 #6 0xaaaab6353e10 in btf__add_field tools/lib/bpf/btf.c:2032 #7 0xaaaab6084fcc in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:232 #8 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875 #9 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062 #10 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697 #11 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308 #12 0xaaaab5d65990 (test_progs+0x185990) previously allocated by thread T0 here: #0 0xaaaab5e2c7c4 in realloc (test_progs+0x24c7c4) #1 0xaaaab634f4a0 in libbpf_reallocarray tools/lib/bpf/libbpf_internal.h:191 #2 0xaaaab634f840 in libbpf_add_mem tools/lib/bpf/btf.c:163 #3 0xaaaab636643c in strset_add_str_mem tools/lib/bpf/strset.c:106 #4 0xaaaab6366560 in strset__add_str tools/lib/bpf/strset.c:157 #5 0xaaaab6352d70 in btf__add_str tools/lib/bpf/btf.c:1519 #6 0xaaaab6353ff0 in btf_add_enum_common tools/lib/bpf/btf.c:2070 #7 0xaaaab6354080 in btf__add_enum tools/lib/bpf/btf.c:2102 #8 0xaaaab6082f50 in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:162 #9 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875 #10 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062 #11 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697 #12 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308 #13 0xaaaab5d65990 (test_progs+0x185990) The reason is that the key stored in hash table name_map is a string address, and the string memory is allocated by realloc() function, when the memory is resized by realloc() later, the old memory may be freed, so the address stored in name_map references to a freed memory, causing use-after-free. Fix it by storing duplicated string address in name_map. Fixes: 351131b ("libbpf: add btf_dump API for BTF-to-C conversion") Signed-off-by: Xu Kuohai <[email protected]>
1 parent 423a793 commit 8d98459

File tree

1 file changed

+37
-10
lines changed

1 file changed

+37
-10
lines changed

tools/lib/bpf/btf_dump.c

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,17 @@ static int btf_dump_resize(struct btf_dump *d)
219219
return 0;
220220
}
221221

222+
static void btf_dump_free_names(struct hashmap *map)
223+
{
224+
size_t bkt;
225+
struct hashmap_entry *cur;
226+
227+
hashmap__for_each_entry(map, cur, bkt)
228+
free((void *)cur->key);
229+
230+
hashmap__free(map);
231+
}
232+
222233
void btf_dump__free(struct btf_dump *d)
223234
{
224235
int i;
@@ -237,8 +248,8 @@ void btf_dump__free(struct btf_dump *d)
237248
free(d->cached_names);
238249
free(d->emit_queue);
239250
free(d->decl_stack);
240-
hashmap__free(d->type_names);
241-
hashmap__free(d->ident_names);
251+
btf_dump_free_names(d->type_names);
252+
btf_dump_free_names(d->ident_names);
242253

243254
free(d);
244255
}
@@ -634,8 +645,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
634645

635646
static const char *btf_dump_type_name(struct btf_dump *d, __u32 id);
636647
static const char *btf_dump_ident_name(struct btf_dump *d, __u32 id);
637-
static size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
638-
const char *orig_name);
648+
static ssize_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
649+
const char *orig_name);
639650

640651
static bool btf_dump_is_blacklisted(struct btf_dump *d, __u32 id)
641652
{
@@ -991,7 +1002,7 @@ static void btf_dump_emit_enum32_val(struct btf_dump *d,
9911002
bool is_signed = btf_kflag(t);
9921003
const char *fmt_str;
9931004
const char *name;
994-
size_t dup_cnt;
1005+
ssize_t dup_cnt;
9951006
int i;
9961007

9971008
for (i = 0; i < vlen; i++, v++) {
@@ -1016,7 +1027,7 @@ static void btf_dump_emit_enum64_val(struct btf_dump *d,
10161027
bool is_signed = btf_kflag(t);
10171028
const char *fmt_str;
10181029
const char *name;
1019-
size_t dup_cnt;
1030+
ssize_t dup_cnt;
10201031
__u64 val;
10211032
int i;
10221033

@@ -1517,14 +1528,30 @@ static void btf_dump_emit_type_cast(struct btf_dump *d, __u32 id,
15171528
}
15181529

15191530
/* return number of duplicates (occurrences) of a given name */
1520-
static size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
1521-
const char *orig_name)
1531+
static ssize_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
1532+
const char *orig_name)
15221533
{
1523-
size_t dup_cnt = 0;
1534+
int err;
1535+
char *old_name;
1536+
char *new_name;
1537+
ssize_t dup_cnt = 0;
1538+
1539+
new_name = strdup(orig_name);
1540+
if (!new_name)
1541+
return -ENOMEM;
15241542

15251543
hashmap__find(name_map, orig_name, (void **)&dup_cnt);
15261544
dup_cnt++;
1527-
hashmap__set(name_map, orig_name, (void *)dup_cnt, NULL, NULL);
1545+
1546+
err = hashmap__set(name_map, new_name, (void *)dup_cnt,
1547+
(const void **)&old_name, NULL);
1548+
if (err) {
1549+
free(new_name);
1550+
return err;
1551+
}
1552+
1553+
if (old_name)
1554+
free(old_name);
15281555

15291556
return dup_cnt;
15301557
}

0 commit comments

Comments
 (0)