mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/3] bpf: Add user memory access kfuncs for linux_binprm
@ 2026-08-12 11:11 Anastasios Papagiannis
  2026-08-12 11:11 ` [PATCH bpf-next 1/3] mm: Add copy_remote_mm_str() Anastasios Papagiannis
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Anastasios Papagiannis @ 2026-08-12 11:11 UTC (permalink / raw)
  To: bpf
  Cc: linux-kernel, linux-mm, linux-fsdevel, viro, brauner, akpm,
	david, ast, daniel, andrii, eddyz87, memxor, kpsingh, matt, song,
	tasos.papagiannnis

During exec, argument and environment strings are copied into the new
address space held by struct linux_binprm before that address space is
installed on the task_struct. Existing eBPF user memory helpers only
support reading from the old address space (i.e. current process)
and for this reason programs cannot access these strings from the
bprm_check_security LSM hook.

This series adds two sleepable BPF kfuncs for copying bytes or
NUL-terminated strings from the address space held by struct linux_binprm.
This allows BPF LSM programs to inspect exec arguments before allowing
the exec to continue.

The series also adds selftests covering both kfuncs.

Anastasios Papagiannis (3):
  mm: Add copy_remote_mm_str()
  bpf: Add user memory access kfuncs for linux_binprm
  selftests/bpf: Test linux_binprm user memory kfuncs

 fs/bpf_fs_kfuncs.c                            | 112 ++++++++++++++++++
 include/linux/mm.h                            |   2 +
 mm/memory.c                                   |  25 +++-
 mm/nommu.c                                    |  25 +++-
 .../bpf/prog_tests/copy_from_user_bprm.c      |  52 ++++++++
 .../selftests/bpf/progs/copy_from_user_bprm.c |  74 ++++++++++++
 6 files changed, 288 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/copy_from_user_bprm.c
 create mode 100644 tools/testing/selftests/bpf/progs/copy_from_user_bprm.c


base-commit: 07cb86aa50816b070b99c89bf948762ef035a1f2
-- 
2.55.0


^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: [PATCH bpf-next v2 2/3] bpf: Add user memory access kfuncs for linux_binprm
@ 2026-08-21 19:51 Andrii Nakryiko
  2026-08-24 10:49 ` [PATCH bpf-next " Anastasios Papagiannis
  0 siblings, 1 reply; 14+ messages in thread
From: Andrii Nakryiko @ 2026-08-21 19:51 UTC (permalink / raw)
  To: Anastasios Papagiannis
  Cc: bpf, linux-kernel, linux-mm, linux-fsdevel, viro, brauner, akpm,
	david, ast, daniel, andrii, eddyz87, memxor, kpsingh, matt, song,
	utilityemal77

On Thu, Aug 20, 2026 at 6:18 AM Anastasios Papagiannis
<tasos.papagiannnis@gmail.com> wrote:
>
> When security_bprm_check runs, the arg and env strings for the exec have
> been copied into bprm->mm. The new address space has not been associated
> yet with a task_struct until exec_mmap(), so existing BPF user memory
> helpers can only read from the calling task's old address space.
>
> This patch adds bpf_copy_from_user_bprm() and
> bpf_copy_from_user_bprm_str() kfuncs. Both use the mm_struct provided by
> struct linux_binprm.
>
> Register these kfuncs on both MMU and NOMMU systems. On NOMMU systems,
> exec arguments are staged in bprm->page[] rather than mapped in bprm->mm,
> so the kfuncs return -EOPNOTSUPP.
>
> bpf_copy_from_user_bprm() has similar semantics as
> bpf_copy_from_user_task(). bpf_copy_from_user_bprm_str() copies one
> NUL-terminated string and returns its size including the NUL terminator.
> It accepts BPF_F_PAD_ZEROS to clear unused destination bytes on success.
>
> This patch registers both kfuncs with KF_SLEEPABLE because accessing the
> remote address space can fault. This allows BPF LSM programs attached to
> security_bprm_check to read arguments beginning at bprm->p and reject an
> exec based on its command-line arguments.
>
> Signed-off-by: Anastasios Papagiannis <tasos.papagiannnis@gmail.com>
> ---
>  fs/bpf_fs_kfuncs.c | 128 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 128 insertions(+)
>
> diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
> index f1863a891db6..1cd06f9e4890 100644
> --- a/fs/bpf_fs_kfuncs.c
> +++ b/fs/bpf_fs_kfuncs.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0
>  /* Copyright (c) 2024 Google LLC. */
>
> +#include <linux/binfmts.h>
>  #include <linux/bpf.h>
>  #include <linux/bpf_lsm.h>
>  #include <linux/btf.h>
> @@ -379,6 +380,131 @@ __bpf_kfunc struct inode *bpf_real_data_inode(struct file *file)
>         return d_real_inode(file_dentry(file));
>  }
>
> +/**
> + * bpf_copy_from_user_bprm - Copy data from a binary parameter address space
> + * @dst:             Destination address, in kernel space
> + * @dst__sz:         Number of bytes to copy
> + * @unsafe_ptr__ign: Source address in the binary parameter address space
> + * @bprm:            Binary parameters whose address space will be used
> + * @flags:           Reserved for future use; must be zero
> + *
> + * Copies data from the nascent address space associated with @bprm. This is
> + * useful for reading the argument and environment strings before the new
> + * address space is installed by exec_mmap(). For example, at the
> + * bprm_check_security LSM hook, @bprm->p points at the first argument string.
> + *
> + * The destination is zeroed if the requested number of bytes cannot be copied
> + * in full.
> + *
> + * Return: 0 on success, -EINVAL if @flags is non-zero, -EOPNOTSUPP on
> + * NOMMU systems, or -EFAULT if the copy fails or is partial.
> + */
> +__bpf_kfunc int bpf_copy_from_user_bprm(void *dst, u32 dst__sz,
> +                                       const void __user *unsafe_ptr__ign,
> +                                       const struct linux_binprm *bprm, u64 flags)

making this linux_binprm-specific seems short-sighted and overly
specialized, why not pass `const struct mm *` and call new kfuncs
bpf_copy_from_user_mm[_str] ?

and this seems to belong right next to bpf_copy_from_user_task_str()
and others in kernel/bpf/helpers.c (and bpf_copy_from_user_task
variants should just delegate to this mm-based APIs and minimize code
duplication)

pw-bot: cr

> +{
> +#ifdef CONFIG_MMU
> +       struct mm_struct *mm;
> +       int ret;
> +#endif
> +
> +       if (unlikely(flags))
> +               return -EINVAL;
> +
> +       if (unlikely(!dst__sz))
> +               return 0;
> +
> +#ifdef CONFIG_MMU
> +       mm = bprm->mm;
> +       if (!mm) {
> +               memset(dst, 0, dst__sz);
> +               return -EFAULT;
> +       }
> +
> +       ret = access_remote_vm(mm, (unsigned long)unsafe_ptr__ign,
> +                              dst, dst__sz, 0);
> +       if (ret != dst__sz) {
> +               memset(dst, 0, dst__sz);
> +               return -EFAULT;
> +       }
> +
> +       return 0;
> +#else
> +       memset(dst, 0, dst__sz);
> +       return -EOPNOTSUPP;
> +#endif
> +}
> +
> +/**
> + * bpf_copy_from_user_bprm_str - Copy a string from binary parameter memory
> + * @dst:             Destination address, in kernel space. This buffer must be
> + *                   at least @dst__sz bytes long
> + * @dst__sz:         Maximum number of bytes to copy, including the trailing NUL
> + * @unsafe_ptr__ign: Source address in the binary parameter address space
> + * @bprm:            Binary parameters whose address space will be used
> + * @flags:           The only supported flag is BPF_F_PAD_ZEROS
> + *
> + * Copies a NUL-terminated string from the nascent address space associated
> + * with @bprm. If the string is too long, @dst is still NUL-terminated unless
> + * @dst__sz is zero.
> + *
> + * If BPF_F_PAD_ZEROS is set, the unused portion of @dst is cleared on success
> + * and all of @dst is cleared on failure.
> + *
> + * Return: The number of copied bytes including the NUL terminator on success,
> + * or a negative error code on failure. On NOMMU systems, -EOPNOTSUPP is
> + * returned.
> + */
> +__bpf_kfunc int bpf_copy_from_user_bprm_str(void *dst, u32 dst__sz,
> +                                           const void __user *unsafe_ptr__ign,
> +                                           const struct linux_binprm *bprm,
> +                                           u64 flags)
> +{
> +#ifdef CONFIG_MMU
> +       struct mm_struct *mm;
> +       int ret;
> +#endif
> +
> +       if (unlikely(flags & ~BPF_F_PAD_ZEROS))
> +               return -EINVAL;
> +
> +       if (unlikely(!dst__sz))
> +               return 0;
> +
> +#ifdef CONFIG_MMU
> +       mm = bprm->mm;
> +       if (!mm) {
> +               if (flags & BPF_F_PAD_ZEROS)
> +                       memset(dst, 0, dst__sz);
> +               else
> +                       *(char *)dst = '\0';
> +
> +               return -EFAULT;
> +       }
> +
> +       ret = copy_remote_mm_str(mm, (unsigned long)unsafe_ptr__ign,
> +                                dst, dst__sz, 0);
> +       if (ret < 0) {
> +               if (flags & BPF_F_PAD_ZEROS)
> +                       memset(dst, 0, dst__sz);
> +
> +               return ret;
> +       }
> +
> +       if (flags & BPF_F_PAD_ZEROS)
> +               memset(dst + ret, 0, dst__sz - ret);
> +
> +       return ret + 1;
> +#else
> +       if (flags & BPF_F_PAD_ZEROS)
> +               memset(dst, 0, dst__sz);
> +       else
> +               *(char *)dst = '\0';
> +
> +       return -EOPNOTSUPP;
> +#endif
> +}
> +
>  __bpf_kfunc_end_defs();
>
>  BTF_KFUNCS_START(bpf_fs_kfunc_set_ids)
> @@ -390,6 +516,8 @@ BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE)
>  BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE)
>  BTF_ID_FLAGS(func, bpf_remove_dentry_xattr, KF_SLEEPABLE)
>  BTF_ID_FLAGS(func, bpf_real_data_inode, KF_SLEEPABLE | KF_RET_NULL)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_bprm, KF_SLEEPABLE)
> +BTF_ID_FLAGS(func, bpf_copy_from_user_bprm_str, KF_SLEEPABLE)
>  BTF_KFUNCS_END(bpf_fs_kfunc_set_ids)
>
>  static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id)
> --
> 2.55.0
>

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

end of thread, other threads:[~2026-08-31  9:26 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-12 11:11 [PATCH bpf-next 0/3] bpf: Add user memory access kfuncs for linux_binprm Anastasios Papagiannis
2026-08-12 11:11 ` [PATCH bpf-next 1/3] mm: Add copy_remote_mm_str() Anastasios Papagiannis
2026-08-12 12:03   ` bot+bpf-ci
2026-08-12 11:11 ` [PATCH bpf-next 2/3] bpf: Add user memory access kfuncs for linux_binprm Anastasios Papagiannis
2026-08-12 12:18   ` bot+bpf-ci
2026-08-12 18:40   ` Justin Suess
2026-08-18  8:24     ` Anastasios Papagiannis
2026-08-18 21:34       ` Justin Suess
2026-08-12 11:11 ` [PATCH bpf-next 3/3] selftests/bpf: Test linux_binprm user memory kfuncs Anastasios Papagiannis
2026-08-12 12:18   ` bot+bpf-ci
2026-08-12 18:42   ` Justin Suess
2026-08-21 19:51 [PATCH bpf-next v2 2/3] bpf: Add user memory access kfuncs for linux_binprm Andrii Nakryiko
2026-08-24 10:49 ` [PATCH bpf-next " Anastasios Papagiannis
2026-08-24 20:01   ` Andrii Nakryiko
2026-08-31  9:25     ` Anastasios Papagiannis

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

all inboxes | Powered by JetHome®