[PATCH 13/31] btf_encoder: Fix early cleanup crashes in btf_encoder__new/delete

Arnaldo Carvalho de Melo <[email protected]> Wed, 29 Jul 2026 16:07:13 -0300
Newsgroups org.kernel.vger.dwarves,org.kernel.vger.bpf
Message-ID <[email protected]>
From: Arnaldo Carvalho de Melo <[email protected]>

Fix three issues in btf_encoder initialization and cleanup:

1. INIT_LIST_HEAD(&encoder->elf_functions_list) was done after two
   goto out_delete paths (strdup and btf__new failures).  Since the
   encoder is zalloc'd, elf_functions_list.next is NULL, so
   btf_encoder__delete() → elf_functions_list__clear() → list_for_each_safe
   dereferences NULL.  Move the INIT_LIST_HEAD to the start.

2. btf_encoder__delete() iterates secinfo[] unconditionally, but if
   the calloc for secinfo fails, the pointer is NULL while seccnt is
   already set, causing a NULL dereference.  Add a NULL guard.

3. Add NULL check for elf_strptr() return value before strcmp() in
   btf_encoder__write_elf(), preventing a crash on malformed ELF files.

Before: NULL deref on strdup failure + secinfo alloc failure + bad ELF
After:  clean error paths in all cases

Fixes: 99e78ff34f8171f9 ("btf_encoder: Introduce elf_functions_list")
Reported-by: Sashiko:gemini-3-1-pro-preview
Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
 btf_encoder.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index 0fbd7e3420b0457f..5c12e79f5ef648ba 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -2029,7 +2029,7 @@ static int btf_encoder__write_elf(struct btf_encoder *encoder, const struct btf
 		if (shdr == NULL)
 			continue;
 		char *secname = elf_strptr(elf, strndx, shdr->sh_name);
-		if (strcmp(secname, btf_secname) == 0) {
+		if (secname != NULL && strcmp(secname, btf_secname) == 0) {
 			btf_data = elf_getdata(scn, btf_data);
 			break;
 		}
@@ -2780,6 +2780,7 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 	struct elf_functions *funcs = NULL;
 
 	if (encoder) {
+		INIT_LIST_HEAD(&encoder->elf_functions_list);
 		encoder->cu = cu;
 		encoder->raw_output = detached_filename != NULL;
 		encoder->source_filename = strdup(cu->filename);
@@ -2818,7 +2819,6 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 		if (conf_load->encode_btf_global_vars)
 			encoder->encode_vars |= BTF_VAR_GLOBAL;
 
-		INIT_LIST_HEAD(&encoder->elf_functions_list);
 		funcs = btf_encoder__elf_functions(encoder);
 		if (!funcs)
 			goto out_delete;
@@ -2912,9 +2912,11 @@ void btf_encoder__delete(struct btf_encoder *encoder)
 	if (encoder == NULL)
 		return;
 
-	for (shndx = 0; shndx < encoder->seccnt; shndx++)
-		__gobuffer__delete(&encoder->secinfo[shndx].secinfo);
-	free(encoder->secinfo);
+	if (encoder->secinfo) {
+		for (shndx = 0; shndx < encoder->seccnt; shndx++)
+			__gobuffer__delete(&encoder->secinfo[shndx].secinfo);
+		free(encoder->secinfo);
+	}
 	zfree(&encoder->filename);
 	zfree(&encoder->source_filename);
 	btf__free(encoder->btf);
-- 
2.55.0