All of lore.kernel.org
 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 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.