From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Jordan Rome <linux@jordanrome.com>
Cc: bpf@vger.kernel.org, linux-mm@kvack.org,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Kernel Team <kernel-team@fb.com>,
Andrew Morton <akpm@linux-foundation.org>,
Shakeel Butt <shakeel.butt@linux.dev>,
Alexander Potapenko <glider@google.com>
Subject: Re: [bpf-next v3 1/3] mm: add copy_remote_vm_str
Date: Fri, 24 Jan 2025 16:08:53 -0800 [thread overview]
Message-ID: <CAEf4Bzb9EOwQnzCL4j6vGFdJ-hgPXif5Z8iXUT-sKvf+bgTfEg@mail.gmail.com> (raw)
In-Reply-To: <20250124181602.1872142-1-linux@jordanrome.com>
On Fri, Jan 24, 2025 at 10:22 AM Jordan Rome <linux@jordanrome.com> wrote:
>
> Similar to `access_process_vm` but specific to strings.
> Also chunks reads by page and utilizes `strscpy`
> for handling null termination.
>
> Signed-off-by: Jordan Rome <linux@jordanrome.com>
> ---
> include/linux/mm.h | 3 ++
> mm/memory.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
> mm/nommu.c | 68 ++++++++++++++++++++++++++
> 3 files changed, 190 insertions(+)
>
[...]
> + maddr = kmap_local_page(page);
> + retval = strscpy(buf, maddr + offset, bytes);
> + unmap_and_put_page(page, maddr);
> +
> + if (retval > -1 && retval < bytes) {
> + /* found the end of the string */
> + buf += retval;
> + goto out;
> + }
> +
> + if (retval == -E2BIG) {
nit: strscpy() can't return any other error, so I'd structure result
handling as:
if (retval < 0) {
/* that annoying last byte copy */
retval = bytes;
}
if (retval < bytes) {
/* "we are done" handling */
}
/* common len, buf, addr adjustment logic stays here */
but also here's the question. If we get E2BIG, while bytes is exactly
how many bytes we have left in the buffer, the last byte should be
zero, no? So this should be cleanly handled, right? Or do we have a
test for that and it works already?
> + retval = bytes;
> + /*
> + * Because strscpy always null terminates we need to
> + * copy the last byte in the page if we are going to
> + * load more pages
> + */
> + if (bytes < len) {
> + end = bytes - 1;
> + copy_from_user_page(vma,
> + page,
> + addr + end,
> + buf + end,
you don't need the `end` variable, just use `bytes - 1` twice?
> + maddr + (PAGE_SIZE - 1),
> + 1);
> + }
> + }
> +
> + len -= retval;
> + buf += retval;
> + addr += retval;
> + }
> +
> +out:
> + mmap_read_unlock(mm);
> + if (err)
> + 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 transfer
> + * @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).
> + * If the source string is shorter than @len then return the length of the
> + * source string. If the source string is longer than @len, return @len.
> + * On any error, return -EFAULT.
strncpy_from_user_nofault() doc says:
On success, returns the length of the string INCLUDING the trailing NUL
Is this the case with copy_remote_vm_str() as well? I.e., if the
source string is 5 bytes + NUL, dst buf is 10. Will we get 5 or 6
returned? We should be very careful with all this +/- 1 business in
corner cases, too easy to mess this up.
> + */
> +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;
> +
> + mm = get_task_mm(tsk);
> + if (!mm)
> + return -EFAULT;
> +
> + ret = __copy_remote_vm_str(mm, addr, buf, len, gup_flags);
> +
> + mmput(mm);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(copy_remote_vm_str);
> +
[...]
next prev parent reply other threads:[~2025-01-25 0:09 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-24 18:16 Jordan Rome
2025-01-25 0:08 ` Andrii Nakryiko [this message]
2025-01-25 14:01 ` Jordan Rome
2025-01-27 19:21 ` Andrii Nakryiko
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=CAEf4Bzb9EOwQnzCL4j6vGFdJ-hgPXif5Z8iXUT-sKvf+bgTfEg@mail.gmail.com \
--to=andrii.nakryiko@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=glider@google.com \
--cc=kernel-team@fb.com \
--cc=linux-mm@kvack.org \
--cc=linux@jordanrome.com \
--cc=shakeel.butt@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox