BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Thiébaud Weksteen" <tweek@google.com>
Cc: selinux@vger.kernel.org, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next 2/5] bpf: Introduce BPF_LOADER_LOAD_FD command
Date: Thu, 13 Aug 2026 00:42:21 +0000	[thread overview]
Message-ID: <20260813004221.D6D0B1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260813002618.3755631-3-tweek@google.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] Information Leak / Out-of-Bounds Read in BPF verifier via loader_load_fd
- [High] Out-of-bounds Read / Denial of Service in ELF header validation
- [Medium] File Descriptor Hijacking Race Condition (TOCTOU)
- [Medium] API Misuse / Broken functionality on non-JIT configurations
- [Low] Direct cast of `__aligned_u64` to `void *` for `copy_to_user`
--

--- Patch [2]: [PATCH bpf-next 2/5] bpf: Introduce BPF_LOADER_LOAD_FD command ---
commit f9a928bc7f89cffc836753c26236211ed8039c51
Author: Thiébaud Weksteen <tweek@google.com>

bpf: Introduce BPF_LOADER_LOAD_FD command

This commit introduces the BPF_LOADER_LOAD_FD command to allow loading
and executing loader BPF programs directly from an ELF file.

> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 8d111da886553..d79cd63f9f7cd 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c

[ ... ]

> @@ -6291,6 +6292,336 @@ static int prog_assoc_struct_ops(union bpf_attr *attr)

[ ... ]

> +static int bpf_elf_validity_cache_sechdrs(struct elf_info *info)
> +{
> +	Elf64_Shdr *sechdrs;
> +	Elf64_Shdr *shdr;
> +	int i;
> +	int err;
> +
> +	err = bpf_elf_validity_ehdr(info);
> +	if (err < 0)
> +		return err;
> +
> +	if (info->hdr->e_shentsize != sizeof(Elf64_Shdr)) {
> +		pr_err("Invalid ELF section header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	/*
> +	 * e_shnum is 16 bits, and sizeof(Elf64_Shdr) is
> +	 * known and small. So e_shnum * sizeof(Elf64_Shdr)
> +	 * will not overflow unsigned long on any platform.
> +	 */
> +	if (info->hdr->e_shoff >= info->len
> +	    || (info->hdr->e_shnum * sizeof(Elf64_Shdr) >
> +		info->len - info->hdr->e_shoff)) {
> +		pr_err("Invalid ELF section header overflow\n");
> +		return -ENOEXEC;
> +	}
> +
> +	sechdrs = (void *)info->hdr + info->hdr->e_shoff;
> +
> +	/*
> +	 * The code assumes that section 0 has a length of zero and
> +	 * an addr of zero, so check for it.
> +	 */
> +	if (sechdrs[0].sh_type != SHT_NULL

[Severity: High]
Does this bounds check properly handle the case where info->hdr->e_shnum
is 0?

If an attacker provides an ELF file with e_shnum set to 0 and e_shoff set
near the end of the file (e.g., info->len - 1), the size check evaluates
0 > 1, which is false. The code will then proceed to access sechdrs[0]
unconditionally.

Since info->hdr is backed by a vmalloc buffer, could this read past the
buffer boundary into the unmapped guard page and cause a panic?

[ ... ]

> +static int loader_load_fd(union bpf_attr *attr)
> +{

[ ... ]

> +	memset(&sattr, 0, sizeof(sattr));
> +	sattr.prog_type = BPF_PROG_TYPE_SYSCALL;
> +	sattr.license = (unsigned long) license;
> +	sattr.insns = (unsigned long) insns;
> +	sattr.insn_cnt = insns_sz / sizeof(struct bpf_insn);
> +	sattr.fd_array = (unsigned long) &map_fd;

[Severity: Critical]
Is it safe to pass a kernel stack pointer (&map_fd) via sattr.fd_array
while leaving fd_array_cnt implicitly as 0?

When fd_array_cnt is 0, the BPF verifier falls back to the legacy sparse
array resolution path in fd_array_get_map_idx_sparse(). In this path, the
verifier extracts an immediate value from a BPF_PSEUDO_MAP_FD instruction
and uses it as an index.

Since fd_array is treated as a kernel pointer, copy_from_bpfptr_offset()
expands directly to a memory copy:

    memcpy(&fd, &map_fd + idx, sizeof(int));

Because the index is attacker-controlled and lacks bounds checking, could
this allow an unprivileged user to reliably read arbitrary memory from the
kernel stack?

> +	sattr.prog_flags = BPF_F_SLEEPABLE;
> +	strscpy(sattr.prog_name, BPF_LOADER_PROG_SEC, sizeof(BPF_LOADER_PROG_SEC));
> +	prog_fd = kern_sys_bpf(BPF_PROG_LOAD, &sattr, sizeof(sattr));
> +	if (prog_fd < 0) {
> +		err = prog_fd;
> +		goto close_map_err;
> +	}
> +
> +	memset(&sattr, 0, sizeof(sattr));
> +	ctx_sz = attr->load_fd.ctx_size;
> +	kctx = kzalloc(ctx_sz, GFP_KERNEL);
> +	if (kctx == NULL) {
> +		err = -ENOMEM;
> +		goto close_prog_err;
> +	}
> +	sattr.test.prog_fd = prog_fd;
> +	sattr.test.ctx_in = (unsigned long) kctx;
> +	sattr.test.ctx_size_in = ctx_sz;
> +	err = kern_sys_bpf(BPF_PROG_TEST_RUN, &sattr, sizeof(sattr));

[Severity: Medium]
Does kern_sys_bpf() support BPF_PROG_TEST_RUN when CONFIG_BPF_JIT is
disabled?

Looking at kern_sys_bpf(), it only intercepts BPF_PROG_TEST_RUN when
CONFIG_BPF_JIT is enabled. Without JIT, it falls through to ____bpf_sys_bpf()
which explicitly rejects BPF_PROG_TEST_RUN and returns -EINVAL.

Could this cause the BPF_LOADER_LOAD_FD command to be completely broken on
non-JIT kernel configurations?

> +	if (err < 0)
> +		goto free_ctx;
> +	err = sattr.test.retval;
> +	if (err < 0)
> +		goto free_ctx;
> +
> +	if (copy_to_user((void *) attr->load_fd.ctx, kctx, ctx_sz) != 0)

[Severity: Low]
Is it correct to directly cast __aligned_u64 to a void pointer here?

Directly casting attr->load_fd.ctx to (void *) bypasses Sparse address space
annotations for __user memory. On 32-bit architectures, this can also cause
pointer truncation warnings.

Should this use the u64_to_user_ptr() macro instead?

> +		err = -EFAULT;
> +
> +free_ctx:
> +	kfree(kctx);
> +close_prog_err:
> +	close_fd(prog_fd);
> +close_map_err:
> +	close_fd(map_fd);

[Severity: Medium]
Could unconditionally closing these file descriptors introduce a race
condition?

The kern_sys_bpf() function allocates file descriptors and installs them,
making them temporarily visible in the calling process's file descriptor
table.

If a concurrent thread blocks copy_to_user() (for instance, by passing a
userfaultfd-backed memory region for attr->load_fd.ctx), it could close
these exposed file descriptors and open new ones.

When the page fault resolves, would loader_load_fd() resume and inadvertently
close the newly opened files that now occupy those descriptor slots?

> +out_free_buf:
> +	vfree(buf);
> +out:
> +	return err;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260813002618.3755631-1-tweek@google.com?part=2

  reply	other threads:[~2026-08-13  0:42 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-13  0:26 [PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD Thiébaud Weksteen
2026-08-13  0:26 ` [PATCH bpf-next 1/5] fs/kernel_read_file,selinux: Add BPF_LOADER constant Thiébaud Weksteen
2026-08-13  0:36   ` sashiko-bot
2026-08-13  1:25   ` bot+bpf-ci
2026-08-13  0:26 ` [PATCH bpf-next 2/5] bpf: Introduce BPF_LOADER_LOAD_FD command Thiébaud Weksteen
2026-08-13  0:42   ` sashiko-bot [this message]
2026-08-13  1:40   ` bot+bpf-ci
2026-08-13  0:26 ` [PATCH bpf-next 3/5] selinux: use kernel sid in security_bpf_* Thiébaud Weksteen
2026-08-13  0:40   ` sashiko-bot
2026-08-13  1:25   ` bot+bpf-ci
2026-08-13  0:26 ` [PATCH bpf-next 4/5] selinux: Add BPF_LOADER_LOAD_FD syscall permission Thiébaud Weksteen
2026-08-13  0:41   ` sashiko-bot
2026-08-13  0:26 ` [PATCH bpf-next 5/5] selftests/bpf: add loader_load_fd tests Thiébaud Weksteen
2026-08-13  0:36   ` sashiko-bot
2026-08-13  1:25   ` bot+bpf-ci

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=20260813004221.D6D0B1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=selinux@vger.kernel.org \
    --cc=tweek@google.com \
    /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