BPF List
 help / color / mirror / Atom feed
* [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args
@ 2026-06-19 22:49 Aelin Reidel
  2026-06-19 23:02 ` sashiko-bot
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Aelin Reidel @ 2026-06-19 22:49 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai
  Cc: bpf, linux-kernel, stable, Aelin Reidel

process_kfunc_with_implicit_args() obtains parameter names through
btf__name_by_offset() and passes them to btf__add_func_param() while
constructing a new function prototype. Tag names are processed in a
similar fashion.

The returned name pointer references memory owned by the BTF object.
btf__add_func_param(), btf__add_decl_tag(), etc. modify the same BTF and
may grow its internal storage, invalidating previously returned string
pointers.

This can result in btf__add_func_param(), btf__add_decl_tag(), etc.
dereferencing a stale pointer when copying the string, leading to crashes
in strset__add_str().

Duplicate the parameter name before calling btf__add_func_param() so it
remains valid across BTF updates.

Fixes: 9d199965990c ("resolve_btfids: Support for KF_IMPLICIT_ARGS")
Cc: stable@vger.kernel.org
Signed-off-by: Aelin Reidel <aelin@mainlining.org>
---
We were noticing resolve_btfids crashing almost all the time when
building our kernels with BTF debuginfo in postmarketOS. I'm not sure
why specificially our environment triggered this extremely reliably, but
I'm glad I was able to track down the issue. With the patch, I haven't
seen any further issues and our kernel builds are succeeding again.
---
Changes in v2:
- Apply the same fix to tag_name and adjust the commit message
  accordingly
- Fix the remaining use-after-free in the error handling path
- Link to v1: https://patch.msgid.link/20260619-resolve-btfids-implicit-args-use-after-free-v1-1-2af87d4704c8@mainlining.org

To: Alexei Starovoitov <ast@kernel.org>
To: Daniel Borkmann <daniel@iogearbox.net>
To: Andrii Nakryiko <andrii@kernel.org>
To: Eduard Zingerman <eddyz87@gmail.com>
To: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: Martin KaFai Lau <martin.lau@linux.dev>
To: Song Liu <song@kernel.org>
To: Yonghong Song <yonghong.song@linux.dev>
To: Jiri Olsa <jolsa@kernel.org>
To: Emil Tsalapatis <emil@etsalapatis.com>
To: Ihor Solodrai <ihor.solodrai@linux.dev>
Cc: bpf@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
 tools/bpf/resolve_btfids/main.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c
index f8a91fa7584f..94b89e9c942e 100644
--- a/tools/bpf/resolve_btfids/main.c
+++ b/tools/bpf/resolve_btfids/main.c
@@ -1113,6 +1113,7 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
 {
 	s32 idx, new_proto_id, new_func_id, proto_id;
 	const char *param_name, *tag_name;
+	char *tmp_param_name, *tmp_tag_name;
 	const struct btf_param *params;
 	enum btf_func_linkage linkage;
 	char tmp_name[KSYM_NAME_LEN];
@@ -1163,18 +1164,22 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
 		if (strcmp(tag_name, "bpf_kfunc") == 0)
 			continue;
 
+		tmp_tag_name = strdup(tag_name);
 		idx = btf_decl_tag(t)->component_idx;
 
 		if (btf_kflag(t))
-			err = btf__add_decl_attr(btf, tag_name, new_func_id, idx);
+			err = btf__add_decl_attr(btf, tmp_tag_name, new_func_id, idx);
 		else
-			err = btf__add_decl_tag(btf, tag_name, new_func_id, idx);
+			err = btf__add_decl_tag(btf, tmp_tag_name, new_func_id, idx);
 
 		if (err < 0) {
 			pr_err("ERROR: resolve_btfids: failed to add decl tag %s for %s\n",
-			       tag_name, tmp_name);
+			       tmp_tag_name, tmp_name);
+			free(tmp_tag_name);
 			return -EINVAL;
 		}
+
+		free(tmp_tag_name);
 	}
 
 add_new_proto:
@@ -1193,12 +1198,17 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
 		if (is_kf_implicit_arg(btf, &params[i]))
 			break;
 		param_name = btf__name_by_offset(btf, params[i].name_off);
-		err = btf__add_func_param(btf, param_name, params[i].type);
+		tmp_param_name = strdup(param_name);
+		if (!tmp_param_name)
+			return -ENOMEM;
+		err = btf__add_func_param(btf, tmp_param_name, params[i].type);
 		if (err < 0) {
 			pr_err("ERROR: resolve_btfids: failed to add param %s for %s\n",
-			       param_name, kfunc->name);
+			       tmp_param_name, kfunc->name);
+			free(tmp_param_name);
 			return err;
 		}
+		free(tmp_param_name);
 		t = (struct btf_type *)btf__type_by_id(btf, proto_id);
 	}
 

---
base-commit: 598c7067dd8b65b93f3ccada47e9014a13137f1b
change-id: 20260619-resolve-btfids-implicit-args-use-after-free-16fc2939529e

Best regards,
--  
Aelin Reidel <aelin@mainlining.org>


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args
  2026-06-19 22:49 [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args Aelin Reidel
@ 2026-06-19 23:02 ` sashiko-bot
  2026-06-19 23:48 ` bot+bpf-ci
  2026-06-26  5:26 ` Ihor Solodrai
  2 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-06-19 23:02 UTC (permalink / raw)
  To: Aelin Reidel; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Missing memory allocation check for `tmp_tag_name` leads to undefined behavior on OOM.
- [Medium] `strdup()` on potentially NULL `param_name` introduces a new crash vector on malformed BTF.
--

commit 6cb93b6d37df26aabf2d6e25d7969724248ceefb
Author: Aelin Reidel <aelin@mainlining.org>

resolve_btfids: preserve tag and parameter names when processing implicit args

This commit updates process_kfunc_with_implicit_args() to duplicate
tag and parameter strings before modifying the BTF object. This prevents
btf__add_* operations from dereferencing stale pointers if the internal
BTF storage is grown and reallocated during processing.

> diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c
> index f8a91fa7584f4..94b89e9c942ee 100644
> --- a/tools/bpf/resolve_btfids/main.c
> +++ b/tools/bpf/resolve_btfids/main.c
> @@ -1163,18 +1164,22 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
>  		if (strcmp(tag_name, "bpf_kfunc") == 0)
>  			continue;
>  
> +		tmp_tag_name = strdup(tag_name);
>  		idx = btf_decl_tag(t)->component_idx;
>  
>  		if (btf_kflag(t))
> -			err = btf__add_decl_attr(btf, tag_name, new_func_id, idx);
> +			err = btf__add_decl_attr(btf, tmp_tag_name, new_func_id, idx);
>  		else
> -			err = btf__add_decl_tag(btf, tag_name, new_func_id, idx);
> +			err = btf__add_decl_tag(btf, tmp_tag_name, new_func_id, idx);
>  
>  		if (err < 0) {
>  			pr_err("ERROR: resolve_btfids: failed to add decl tag %s for %s\n",
> -			       tag_name, tmp_name);
> +			       tmp_tag_name, tmp_name);

[Severity: Medium]
What happens if strdup() fails and tmp_tag_name is NULL?

If tmp_tag_name is NULL, btf__add_decl_tag() or btf__add_decl_attr() will
fail and return -EINVAL. The error path then blindly passes the NULL
tmp_tag_name to pr_err() using the %s format specifier.

Could this cause a segmentation fault in libc instead of exiting with a
clean error?

> +			free(tmp_tag_name);
>  			return -EINVAL;
>  		}
> +
> +		free(tmp_tag_name);
>  	}
>  
>  add_new_proto:
> @@ -1193,12 +1198,17 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
>  		if (is_kf_implicit_arg(btf, &params[i]))
>  			break;
>  		param_name = btf__name_by_offset(btf, params[i].name_off);
> -		err = btf__add_func_param(btf, param_name, params[i].type);
> +		tmp_param_name = strdup(param_name);

[Severity: Medium]
Can param_name be NULL here if the BTF input is malformed and the string
offset is out of bounds?

If btf__name_by_offset() returns NULL, wouldn't strdup() dereference the
NULL pointer and crash?

Prior to this patch, the potentially NULL pointer was safely passed
directly to btf__add_func_param(), which handles NULL by defaulting to an
anonymous parameter.

> +		if (!tmp_param_name)
> +			return -ENOMEM;
> +		err = btf__add_func_param(btf, tmp_param_name, params[i].type);
>  		if (err < 0) {
>  			pr_err("ERROR: resolve_btfids: failed to add param %s for %s\n",
> -			       param_name, kfunc->name);
> +			       tmp_param_name, kfunc->name);
> +			free(tmp_param_name);
>  			return err;
>  		}
> +		free(tmp_param_name);
>  		t = (struct btf_type *)btf__type_by_id(btf, proto_id);
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260620-resolve-btfids-implicit-args-use-after-free-v2-1-4132e1f639f0@mainlining.org?part=1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args
  2026-06-19 22:49 [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args Aelin Reidel
  2026-06-19 23:02 ` sashiko-bot
@ 2026-06-19 23:48 ` bot+bpf-ci
  2026-06-26  5:26 ` Ihor Solodrai
  2 siblings, 0 replies; 4+ messages in thread
From: bot+bpf-ci @ 2026-06-19 23:48 UTC (permalink / raw)
  To: aelin, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, ihor.solodrai
  Cc: bpf, linux-kernel, stable, aelin, ast, andrii, daniel, martin.lau,
	eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1599 bytes --]

> process_kfunc_with_implicit_args() obtains parameter names through
> btf__name_by_offset() and passes them to btf__add_func_param() while
> constructing a new function prototype. Tag names are processed in a
> similar fashion.
>
> The returned name pointer references memory owned by the BTF object.
> btf__add_func_param(), btf__add_decl_tag(), etc. modify the same BTF and
> may grow its internal storage, invalidating previously returned string
> pointers.
>
> This can result in btf__add_func_param(), btf__add_decl_tag(), etc.
> dereferencing a stale pointer when copying the string, leading to crashes
> in strset__add_str().

This isn't a bug, but could the crash path in strset__add_str() be spelled
out a little more?

btf__name_by_offset() returns a pointer into btf->strs_set->strs_data (while
the BTF is still modifiable and btf->strs_data is NULL), and
strset_str_append() in tools/lib/bpf/strset.c already reconstructs that
pointer if the buffer was reallocated before it copies:

tools/lib/bpf/strset.c:strset_str_append() {
	...
	old_data = set->strs_data;
	...
	if (old_data != set->strs_data)
		s = set->strs_data + (old_s - old_data);

	memcpy((void *)s, ...);
	...
}

Given that reconstruction, what crash in strset__add_str() remains, or is the
strdup intended as a defensive/robustness change rather than a fix for an
observed crash?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27852582382

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args
  2026-06-19 22:49 [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args Aelin Reidel
  2026-06-19 23:02 ` sashiko-bot
  2026-06-19 23:48 ` bot+bpf-ci
@ 2026-06-26  5:26 ` Ihor Solodrai
  2 siblings, 0 replies; 4+ messages in thread
From: Ihor Solodrai @ 2026-06-26  5:26 UTC (permalink / raw)
  To: Aelin Reidel, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis
  Cc: bpf, linux-kernel, stable

On 2026-06-19 3:49 p.m., Aelin Reidel wrote:
> process_kfunc_with_implicit_args() obtains parameter names through
> btf__name_by_offset() and passes them to btf__add_func_param() while
> constructing a new function prototype. Tag names are processed in a
> similar fashion.
> 
> The returned name pointer references memory owned by the BTF object.
> btf__add_func_param(), btf__add_decl_tag(), etc. modify the same BTF and
> may grow its internal storage, invalidating previously returned string
> pointers.
> 
> This can result in btf__add_func_param(), btf__add_decl_tag(), etc.
> dereferencing a stale pointer when copying the string, leading to crashes
> in strset__add_str().
> 
> Duplicate the parameter name before calling btf__add_func_param() so it
> remains valid across BTF updates.
> 
> Fixes: 9d199965990c ("resolve_btfids: Support for KF_IMPLICIT_ARGS")
> Cc: stable@vger.kernel.org
> Signed-off-by: Aelin Reidel <aelin@mainlining.org>
> ---
> We were noticing resolve_btfids crashing almost all the time when
> building our kernels with BTF debuginfo in postmarketOS. I'm not sure
> why specificially our environment triggered this extremely reliably, but
> I'm glad I was able to track down the issue. With the patch, I haven't
> seen any further issues and our kernel builds are succeeding again.

Hi Aelin, thank you for the report and patch.

My first instinct was to dismiss the patch as over defensive, because
libbpf gracefully handles reallocation of existing strings, and we
don't add new strings here.

Take a look at strset_str_append() in libbpf (strset.c:131):

	static long strset_str_append(struct strset *set, const char *s)
	{
		[...]

		/*
		 * The set->strs_data might have reallocated and if 's' pointed
		 * to an internal string within the old buffer, then it became
		 * dangling and needs to be reconstructed before the copy.
		 */
		if (old_data && old_data != (uintptr_t)set->strs_data &&
		    old_s >= old_data && old_s < old_data + old_data_len)
			s = set->strs_data + (old_s - old_data);

		memcpy(p, s, len);

		return len;
	}

In process_kfunc_with_implicit_args() both tag_name and param_name are
read *after* the first btf__add_func() / btf__add_func_proto() has
made the BTF modifiable, so btf__name_by_offset() should return a
pointer into btf->strs_set. I don't see where the bad pointer comes
from.

However you have a stable reproducer, so your strdup() change probably
covers a real UAF bug somewhere else (in libbpf?).

Let's track this down before coming up with a fix.

What version/commit of libbpf are you using in your kernel tree?

You could build resolve_btfids with ASAN, or run it with valgrind.

If you can share a reproducer that's easy to run, that would be
great too.

Thanks!

> ---
> Changes in v2:
> - Apply the same fix to tag_name and adjust the commit message
>    accordingly
> - Fix the remaining use-after-free in the error handling path
> - Link to v1: https://patch.msgid.link/20260619-resolve-btfids-implicit-args-use-after-free-v1-1-2af87d4704c8@mainlining.org
> 
> To: Alexei Starovoitov <ast@kernel.org>
> To: Daniel Borkmann <daniel@iogearbox.net>
> To: Andrii Nakryiko <andrii@kernel.org>
> To: Eduard Zingerman <eddyz87@gmail.com>
> To: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> To: Martin KaFai Lau <martin.lau@linux.dev>
> To: Song Liu <song@kernel.org>
> To: Yonghong Song <yonghong.song@linux.dev>
> To: Jiri Olsa <jolsa@kernel.org>
> To: Emil Tsalapatis <emil@etsalapatis.com>
> To: Ihor Solodrai <ihor.solodrai@linux.dev>
> Cc: bpf@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> ---
>   tools/bpf/resolve_btfids/main.c | 20 +++++++++++++++-----
>   1 file changed, 15 insertions(+), 5 deletions(-)
> 
> diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c
> index f8a91fa7584f..94b89e9c942e 100644
> --- a/tools/bpf/resolve_btfids/main.c
> +++ b/tools/bpf/resolve_btfids/main.c
> @@ -1113,6 +1113,7 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
>   {
>   	s32 idx, new_proto_id, new_func_id, proto_id;
>   	const char *param_name, *tag_name;
> +	char *tmp_param_name, *tmp_tag_name;
>   	const struct btf_param *params;
>   	enum btf_func_linkage linkage;
>   	char tmp_name[KSYM_NAME_LEN];
> @@ -1163,18 +1164,22 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
>   		if (strcmp(tag_name, "bpf_kfunc") == 0)
>   			continue;
>   
> +		tmp_tag_name = strdup(tag_name);
>   		idx = btf_decl_tag(t)->component_idx;
>   
>   		if (btf_kflag(t))
> -			err = btf__add_decl_attr(btf, tag_name, new_func_id, idx);
> +			err = btf__add_decl_attr(btf, tmp_tag_name, new_func_id, idx);
>   		else
> -			err = btf__add_decl_tag(btf, tag_name, new_func_id, idx);
> +			err = btf__add_decl_tag(btf, tmp_tag_name, new_func_id, idx);
>   
>   		if (err < 0) {
>   			pr_err("ERROR: resolve_btfids: failed to add decl tag %s for %s\n",
> -			       tag_name, tmp_name);
> +			       tmp_tag_name, tmp_name);
> +			free(tmp_tag_name);
>   			return -EINVAL;
>   		}
> +
> +		free(tmp_tag_name);
>   	}
>   
>   add_new_proto:
> @@ -1193,12 +1198,17 @@ static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct
>   		if (is_kf_implicit_arg(btf, &params[i]))
>   			break;
>   		param_name = btf__name_by_offset(btf, params[i].name_off);
> -		err = btf__add_func_param(btf, param_name, params[i].type);
> +		tmp_param_name = strdup(param_name);
> +		if (!tmp_param_name)
> +			return -ENOMEM;
> +		err = btf__add_func_param(btf, tmp_param_name, params[i].type);
>   		if (err < 0) {
>   			pr_err("ERROR: resolve_btfids: failed to add param %s for %s\n",
> -			       param_name, kfunc->name);
> +			       tmp_param_name, kfunc->name);
> +			free(tmp_param_name);
>   			return err;
>   		}
> +		free(tmp_param_name);
>   		t = (struct btf_type *)btf__type_by_id(btf, proto_id);
>   	}
>   
> 
> ---
> base-commit: 598c7067dd8b65b93f3ccada47e9014a13137f1b
> change-id: 20260619-resolve-btfids-implicit-args-use-after-free-16fc2939529e
> 
> Best regards,
> --
> Aelin Reidel <aelin@mainlining.org>
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-26  5:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-19 22:49 [PATCH v2] resolve_btfids: preserve tag and parameter names when processing implicit args Aelin Reidel
2026-06-19 23:02 ` sashiko-bot
2026-06-19 23:48 ` bot+bpf-ci
2026-06-26  5:26 ` Ihor Solodrai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox