BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Pingfan Liu" <piliu@redhat.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCHv7 06/13] kexec_file: Chain the stages into a pipeline
Date: Thu, 13 Aug 2026 22:32:33 +0000	[thread overview]
Message-ID: <20260813223237.BEA321F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260322014402.8815-7-piliu@redhat.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] Aliasing ctx->kernel and ctx->next_parsing_buf in KEXEC_BPF_CMD_DECOMPRESS leads to a Use-After-Free.
- [Medium] Memory leak of newly allocated buffer 'pn' in KEXEC_BPF_CMD_COPY when the pipeline array is full.

Pre-existing issues:
- [Critical] The BPF container decomposition stage completely bypasses KEXEC signature verification.
- [Critical] The bpf_buffer_parser kfunc lacks the required __sz suffix on its size argument, defeating the BPF verifier.
- [High] Memory leak of parsing buffers due to a double-negation logic error (!!context->parsing_buf[i]).
- [High] Severe memory leak of kexec_context dynamically allocated components on error and success paths.
- [High] vfree() is improperly used on memory allocated by kernel_read_file_from_fd().
--

--- Patch [6]: [PATCHv7 06/13] kexec_file: Chain the stages into a pipeline ---
commit 8070ede2f761980c4a2de11a2d72fb8a5309bc74
Author: Pingfan Liu <piliu@redhat.com>

kexec_file: Chain the stages into a pipeline

This commit enables kexec stages to be chained into a pipeline. It promotes
intermediate outputs from next_parsing_buf to parsing_buf for the subsequent
BPF parsing stages. It also allows multiple layers with distinct formats to be
parsed sequentially.

> diff --git a/kernel/kexec_bpf_loader.c b/kernel/kexec_bpf_loader.c
> index af16f7b685d9a..7f7884411e2c7 100644
> --- a/kernel/kexec_bpf_loader.c
> +++ b/kernel/kexec_bpf_loader.c
[ ... ]
> @@ -301,6 +305,23 @@ static int kexec_buff_parser(struct bpf_parser_context *parser)
>  				vfree(ctx->kernel);
>  				ctx->kernel = decompressed_buf;
>  				ctx->kernel_sz = decompressed_sz;
> +				if (fill_pipeline) {
> +					int i;
> +
> +					for (i = 0; i < MAX_PARSING_BUF_NUM; i++) {
> +						if (ctx->next_parsing_buf[i])
> +							continue;
> +						ctx->next_parsing_buf[i] = decompressed_buf;
> +						ctx->next_parsing_buf_sz[i] = decompressed_sz;
> +						break;
> +					}

[Severity: High]
Does this aliasing of decompressed_buf create a use-after-free risk?

If a nested BPF program parses a sub-kernel and issues another
KEXEC_BPF_SUBCMD_KERNEL command, kexec_buff_parser() will unconditionally call
vfree(ctx->kernel):

kexec_buff_parser()
   case KEXEC_BPF_SUBCMD_KERNEL:
      vfree(ctx->kernel);

Since ctx->kernel and ctx->next_parsing_buf[i] point to the exact same buffer,
wouldn't this free the memory that the nested parser is actively reading from?

> +					/* No enough parsing slot */
> +					if (i == MAX_PARSING_BUF_NUM) {
> +						ctx->kernel = NULL;
> +						vfree(decompressed_buf);
> +						return -ENOMEM;
> +					}
> +				}
>  				break;
[ ... ]
> @@ -313,6 +334,22 @@ static int kexec_buff_parser(struct bpf_parser_context *parser)
>  		if (!p)
>  			return -ENOMEM;
>  		memcpy(p, buf, cmd->payload_len);
> +		if (fill_pipeline) {
> +			pn = __vmalloc(cmd->payload_len, GFP_KERNEL | __GFP_ACCOUNT);
> +			if (!pn) {
> +				vfree(p);
> +				return -ENOMEM;
> +			}
> +			memcpy(pn, buf, cmd->payload_len);
> +			for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
> +				if (!ctx->next_parsing_buf[i]) {
> +					ctx->next_parsing_buf[i] = pn;
> +					ctx->next_parsing_buf_sz[i] = cmd->payload_len;
> +					break;
> +				}
> +			}
> +		}

[Severity: Medium]
If the pipeline array is fully exhausted and ctx->next_parsing_buf has no
empty slots, the loop will complete without storing pn. Is there a missing
check after the loop to free pn when it cannot be stored?

[ ... ]
> @@ -637,6 +674,14 @@ static int process_bpf_parsers_container(const char *elf_buf, size_t elf_sz,
>  		/* Free the old parsing context, and reload the new */
>  		for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
>  			if (!!context->parsing_buf[i])
>  				break;
>  			vfree(context->parsing_buf[i]);

[Severity: High]
This is a pre-existing issue, but does this double negation logic incorrectly
skip cleanup?

Because !!context->parsing_buf[i] evaluates to true for any non-NULL
pointer, the loop will immediately break instead of freeing valid buffers.

[Severity: High]
This is a pre-existing issue, but is it safe to use vfree() here?

Since these buffers are originally populated by kernel_read_file_from_fd()
which uses kvmalloc(), shouldn't kvfree() be used to avoid panics on
kmalloc'd memory?

>  			context->parsing_buf[i] = NULL;
>  			context->parsing_buf_sz[i] = 0;
>  		}
> +		for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
> +			if (!context->next_parsing_buf[i])
> +				break;
> +			context->parsing_buf[i] = context->next_parsing_buf[i];


While reviewing this patch, I noticed a few pre-existing issues in other
related areas:

kernel/kexec_bpf_loader.c:decompose_kexec_image() {
...
		ret = process_bpf_parsers_container(parser_start, parser_sz, &ctx, 0);
		if (!ret) {
...
			vfree(ctx.cmdline);
		}
		return ret;
}

[Severity: High]
This is a pre-existing issue, but does this function leak memory on the error
path?

If process_bpf_parsers_container() returns an error, the function exits
directly and returns ret without freeing ctx.kernel, ctx.initrd, ctx.cmdline,
or the array of buffers in ctx.parsing_buf allocated by
kernel_read_file_from_fd().

Also, on the success path (!ret), the ctx.parsing_buf array appears to be
permanently leaked as well.


kernel/kexec_file.c:kimage_file_prepare_segments() {
...
	if (IS_ENABLED(CONFIG_KEXEC_BPF)) {
		/* Fill up image's kernel_buf, initrd_buf, cmdline_buf */
		ret = decompose_kexec_image(image, initrd_fd);
		switch (ret) {
		case 0:
			envelop = true;
...
#ifdef CONFIG_KEXEC_SIG
	if (!envelop) {
		ret = kimage_validate_signature(image);
		if (ret)
			goto out;
	}
#endif
...
}

[Severity: Critical]
This is a pre-existing issue, but doesn't skipping signature validation when
envelop is true create a security regression?

If decompose_kexec_image() successfully extracts the kernel/initrd from a
container via unverified BPF programs, could an attacker load an unsigned,
untrusted kernel simply by wrapping it in an ELF container, completely
defeating kernel signature enforcement and Lockdown?


kernel/bpf/bpf_buffer_parser.c:bpf_buffer_parser() {
...
__bpf_kfunc int bpf_buffer_parser(char *buf, int buf_sz,
		struct bpf_parser_context *context)
{
...
}

[Severity: Critical]
This is a pre-existing issue, but does the size parameter need the __sz suffix
to be properly verified?

Because the parameter is named buf_sz instead of buf__sz, the BPF verifier
treats it as a standard scalar and won't enforce bounds checking between the
pointer and the size. Could an unprivileged BPF program supply a small valid
pointer and an arbitrarily large buf_sz to cause an out-of-bounds read?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260322014402.8815-1-piliu@redhat.com?part=6

  parent reply	other threads:[~2026-08-13 22:32 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-22  1:43 [PATCHv7 00/13] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
2026-03-22  1:43 ` [PATCHv7 01/13] bpf: Introduce kfuncs to parser buffer content Pingfan Liu
2026-03-22  2:14   ` bot+bpf-ci
2026-08-13 22:20   ` sashiko-bot
2026-03-22  1:43 ` [PATCHv7 02/13] kexec_file: Use bpf-prog to decompose image Pingfan Liu
2026-03-22  2:14   ` bot+bpf-ci
2026-03-22  1:43 ` [PATCHv7 03/13] lib/decompress: Keep decompressor when CONFIG_KEEP_DECOMPRESSOR Pingfan Liu
2026-03-22  2:26   ` bot+bpf-ci
2026-03-22  1:43 ` [PATCHv7 04/13] kexec_file: Implement decompress method for parser Pingfan Liu
2026-03-22  2:26   ` bot+bpf-ci
2026-03-22  1:43 ` [PATCHv7 05/13] kexec_file: Implement copy " Pingfan Liu
2026-03-22  1:43 ` [PATCHv7 06/13] kexec_file: Chain the stages into a pipeline Pingfan Liu
2026-03-22  2:14   ` bot+bpf-ci
2026-08-13 22:32   ` sashiko-bot [this message]
2026-03-22  1:43 ` [PATCHv7 07/13] kexec_file: Introduce a bpf-prog lskel to run a format parser Pingfan Liu
2026-03-22  1:43 ` [PATCHv7 08/13] kexec_file: Factor out routine to find a symbol in ELF Pingfan Liu
2026-03-22  2:14   ` bot+bpf-ci
2026-03-23  7:07   ` kernel test robot
2026-03-23 10:19   ` kernel test robot
2026-03-22  1:43 ` [PATCHv7 09/13] kexec_file: Integrate bpf light skeleton to load image with bpf-prog Pingfan Liu
2026-03-22  2:14   ` bot+bpf-ci
2026-03-22  1:43 ` [PATCHv7 10/13] arm64/kexec: Select KEXEC_BPF to support UEFI-style kernel image Pingfan Liu
2026-03-22  1:44 ` [PATCHv7 11/13] tools/kexec: Introduce a bpf-prog to handle zboot image Pingfan Liu
2026-03-22  2:26   ` bot+bpf-ci
2026-03-22  1:44 ` [PATCHv7 12/13] tools/kexec: Introduce a bpf-prog to handle UKI image Pingfan Liu
2026-08-13 22:41   ` sashiko-bot
2026-03-22  1:44 ` [PATCHv7 13/13] tools/kexec: Introduce a tool to build zboot envelop Pingfan Liu
2026-03-23 19:02 ` [PATCHv7 00/13] kexec: Use BPF lskel to enable kexec to load PE format boot image Andrew Morton
2026-03-24  7:09   ` Pingfan Liu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260813223237.BEA321F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=piliu@redhat.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox