Re: [PATCH bpf-next v7 1/5] mm: Add copy_remote_mm_str()
Andrii Nakryiko <[email protected]>
| Newsgroups | org.kernel.vger.linux-fsdevel,org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <CAEf4BzaH=PJh7QUhh7szGL+gCieYLOSbhriFWaZG92xFWDeGig@mail.gmail.com> |
On Tue, Sep 15, 2026 at 1:03 AM Anastasios Papagiannis <[email protected]> wrote: > > copy_remote_vm_str() gets the target address space from a struct > task_struct. This does not work for an address space that exists but is > not yet associated with a task_struct, such as the mm held by struct > linux_binprm during exec. > > Add copy_remote_mm_str(), which operates directly on a struct mm_struct. > > Use a common internal interface for the MMU and NOMMU implementations > and define both public wrappers in mm/util.c. Preserve the existing > copy_remote_vm_str() behavior, including handling zero-length requests > before acquiring the task's mm. > > Signed-off-by: Anastasios Papagiannis <[email protected]> > Acked-by: Lorenzo Stoakes (ARM) <[email protected]> > Acked-by: David Hildenbrand (Arm) <[email protected]> > --- > include/linux/mm.h | 8 +++--- > mm/internal.h | 3 +++ > mm/memory.c | 41 ++---------------------------- > mm/nommu.c | 41 ++---------------------------- > mm/util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 73 insertions(+), 82 deletions(-) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index dd09c438fa23..63f40e615754 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -3325,10 +3325,10 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, > extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, > void *buf, int len, unsigned int gup_flags); > > -#ifdef CONFIG_BPF_SYSCALL > -extern int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, > - void *buf, int len, unsigned int gup_flags); > -#endif > +int copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, > + void *buf, int len, unsigned int gup_flags); > +int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, > + void *buf, int len, unsigned int gup_flags); > > long get_user_pages_remote(struct mm_struct *mm, > unsigned long start, unsigned long nr_pages, > diff --git a/mm/internal.h b/mm/internal.h > index 38b1165212c9..557b29381355 100644 > --- a/mm/internal.h > +++ b/mm/internal.h > @@ -25,6 +25,9 @@ > struct folio_batch; > struct hstate; > > +int __copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, > + void *buf, int len, unsigned int gup_flags); > + > struct huge_bootmem_page { > struct list_head list; > struct hstate *hstate; > diff --git a/mm/memory.c b/mm/memory.c > index 8b0c2c735d3d..fe2f5e988fb9 100644 > --- a/mm/memory.c > +++ b/mm/memory.c > @@ -7331,8 +7331,8 @@ EXPORT_SYMBOL_GPL(access_process_vm); > * Copy a string from another process's address space as given in mm. > * If there is any error return -EFAULT. > */ > -static int __copy_remote_vm_str(struct mm_struct *mm, unsigned long addr, > - void *buf, int len, unsigned int gup_flags) > +int __copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, > + void *buf, int len, unsigned int gup_flags) > { > void *old_buf = buf; > int err = 0; > @@ -7407,43 +7407,6 @@ static int __copy_remote_vm_str(struct mm_struct *mm, unsigned long addr, > return err; > return buf - old_buf; > } > - > -/** > - * copy_remote_vm_str - copy a string from another process's address space. > - * @tsk: the task of the target address space > - * @addr: start address to read from > - * @buf: destination buffer > - * @len: number of bytes to copy > - * @gup_flags: flags modifying lookup behaviour > - * > - * The caller must hold a reference on @mm. > - * > - * Return: number of bytes copied from @addr (source) to @buf (destination); > - * not including the trailing NUL. Always guaranteed to leave NUL-terminated > - * buffer. On any error, return -EFAULT. > - */ > -int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, > - void *buf, int len, unsigned int gup_flags) > -{ > - struct mm_struct *mm; > - int ret; > - > - if (unlikely(len == 0)) > - return 0; > - > - mm = get_task_mm(tsk); > - if (!mm) { > - *(char *)buf = '\0'; > - return -EFAULT; > - } > - > - ret = __copy_remote_vm_str(mm, addr, buf, len, gup_flags); > - > - mmput(mm); > - > - return ret; > -} > -EXPORT_SYMBOL_GPL(copy_remote_vm_str); > #endif /* CONFIG_BPF_SYSCALL */ > > /* > diff --git a/mm/nommu.c b/mm/nommu.c > index 498e01ee40b0..98596e60311f 100644 > --- a/mm/nommu.c > +++ b/mm/nommu.c > @@ -1746,8 +1746,8 @@ EXPORT_SYMBOL_GPL(access_process_vm); > * Copy a string from another process's address space as given in mm. > * If there is any error return -EFAULT. > */ > -static int __copy_remote_vm_str(struct mm_struct *mm, unsigned long addr, > - void *buf, int len) > +int __copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, > + void *buf, int len, unsigned int gup_flags) > { > unsigned long addr_end; > struct vm_area_struct *vma; > @@ -1781,43 +1781,6 @@ static int __copy_remote_vm_str(struct mm_struct *mm, unsigned long addr, > mmap_read_unlock(mm); > return ret; > } > - > -/** > - * copy_remote_vm_str - copy a string from another process's address space. > - * @tsk: the task of the target address space > - * @addr: start address to read from > - * @buf: destination buffer > - * @len: number of bytes to copy > - * @gup_flags: flags modifying lookup behaviour (unused) > - * > - * The caller must hold a reference on @mm. > - * > - * Return: number of bytes copied from @addr (source) to @buf (destination); > - * not including the trailing NUL. Always guaranteed to leave NUL-terminated > - * buffer. On any error, return -EFAULT. > - */ > -int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, > - void *buf, int len, unsigned int gup_flags) > -{ > - struct mm_struct *mm; > - int ret; > - > - if (unlikely(len == 0)) > - return 0; > - > - mm = get_task_mm(tsk); > - if (!mm) { > - *(char *)buf = '\0'; > - return -EFAULT; > - } > - > - ret = __copy_remote_vm_str(mm, addr, buf, len); > - > - mmput(mm); > - > - return ret; > -} > -EXPORT_SYMBOL_GPL(copy_remote_vm_str); > #endif /* CONFIG_BPF_SYSCALL */ > > /** > diff --git a/mm/util.c b/mm/util.c > index bf0513d1d3d0..47c2e3ae8496 100644 > --- a/mm/util.c > +++ b/mm/util.c > @@ -1061,6 +1061,68 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) > return res; > } > > +#ifdef CONFIG_BPF_SYSCALL AI has a point, declarations in mm.h are not guarded by #ifdef CONFIG_BPF_SYSCALL, no? These look generic, I'd remove BPF_SYSCALL guard pw-bot: cr > +/** > + * copy_remote_mm_str - copy a string from a remote address space. > + * @mm: the remote address space > + * @addr: start address to read from > + * @buf: destination buffer > + * @len: number of bytes to copy > + * @gup_flags: flags modifying lookup behaviour > + * > + * The caller must hold a reference on @mm. > + * > + * Return: number of bytes copied from @addr (source) to @buf (destination), > + * not including the trailing NUL. If @len is zero, return 0 without accessing > + * @buf. Otherwise, @buf is always NUL-terminated. On any error, return > + * -EFAULT. > + */ > +int copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, > + void *buf, int len, unsigned int gup_flags) > +{ > + if (unlikely(len == 0)) > + return 0; > + > + return __copy_remote_mm_str(mm, addr, buf, len, gup_flags); > +} > + > +/** > + * copy_remote_vm_str - copy a string from another process's address space. > + * @tsk: the task of the target address space > + * @addr: start address to read from > + * @buf: destination buffer > + * @len: number of bytes to copy > + * @gup_flags: flags modifying lookup behaviour > + * > + * Return: number of bytes copied from @addr (source) to @buf (destination), > + * not including the trailing NUL. If @len is zero, return 0 without accessing > + * @buf. Otherwise, @buf is always NUL-terminated. On any error, return > + * -EFAULT. > + */ > +int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, > + void *buf, int len, unsigned int gup_flags) > +{ > + struct mm_struct *mm; > + int ret; > + > + if (unlikely(len == 0)) > + return 0; > + > + mm = get_task_mm(tsk); > + if (!mm) { > + *(char *)buf = '\0'; > + return -EFAULT; > + } > + > + ret = __copy_remote_mm_str(mm, addr, buf, len, gup_flags); > + > + mmput(mm); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(copy_remote_vm_str); > +#endif /* CONFIG_BPF_SYSCALL */ > + > int __weak memcmp_pages(struct page *page1, struct page *page2) > { > char *addr1, *addr2; > -- > 2.55.0 >