All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.