All of lore.kernel.org
 help / color / mirror / Atom feed
From: Danilo Krummrich <dakr@kernel.org>
To: Alice Ryhl <aliceryhl@google.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Alexander Viro" <viro@zeniv.linux.org.uk>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Trevor Gross" <tmgross@umich.edu>,
	rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/2] uaccess: rust: add UserSliceReader::strcpy_into_buf
Date: Tue, 29 Apr 2025 12:36:24 +0200	[thread overview]
Message-ID: <aBCrqJe4two4I45G@pollux> (raw)
In-Reply-To: <20250429-strncpy-from-user-v2-2-7e6facac0bf0@google.com>

On Tue, Apr 29, 2025 at 09:02:23AM +0000, Alice Ryhl wrote:
> This patch adds a more convenient method for reading C strings from
> userspace. Logic is added to NUL-terminate the buffer when necessary so
> that a &CStr can be returned.
> 
> Note that we treat attempts to read past `self.length` as a fault, so
> this returns EFAULT if that limit is exceeded before `buf.len()` is
> reached.
> 
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
>  rust/kernel/uaccess.rs | 35 +++++++++++++++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
> 
> diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
> index acb703f074a30e60d42a222dd26aed80d8bdb76a..7cec1b62bd8b816f523c8be12cb29905740789fc 100644
> --- a/rust/kernel/uaccess.rs
> +++ b/rust/kernel/uaccess.rs
> @@ -293,6 +293,41 @@ pub fn read_all<A: Allocator>(mut self, buf: &mut Vec<u8, A>, flags: Flags) -> R
>          unsafe { buf.set_len(buf.len() + len) };
>          Ok(())
>      }
> +
> +    /// Read a NUL-terminated string from userspace and append it to `dst`.
> +    ///
> +    /// Fails with [`EFAULT`] if the read happens on a bad address.
> +    pub fn strcpy_into_buf<'buf>(&mut self, buf: &'buf mut [u8]) -> Result<&'buf CStr> {
> +        if buf.is_empty() {
> +            return Err(EINVAL);
> +        }
> +
> +        // SAFETY: The types are compatible and `strncpy_from_user` doesn't write uninitialized
> +        // bytes to `buf`.
> +        let mut dst = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
> +
> +        // We never read more than `self.length` bytes.
> +        if dst.len() > self.length {
> +            dst = &mut dst[..self.length];
> +        }
> +
> +        let mut len = raw_strncpy_from_user(self.ptr, dst)?;
> +        if len < dst.len() {
> +            // Add one to include the NUL-terminator.
> +            len += 1;
> +        } else if len < buf.len() {
> +            // We hit the `self.length` limit before `buf.len()`.
> +            return Err(EFAULT);

So, this one we can only ever hit if `len == dst.len()`, which means that the
string (incl. the NULL terminator) is longer than dst. If at the same time
`len < buf.len()`, we know that dst has been shortened because
`buf.len() > self.length`, which means that the string spans across the
self.length boundary.

That seems a bit subtle to me. Maybe we should check for `dst.len() < buf.len()`
instead and add a comment explaining the logic a bit more in detail.

> +        } else {
> +            // SAFETY: Due to the check at the beginning, the buffer is not empty.
> +            unsafe { *buf.last_mut().unwrap_unchecked() = 0 };
> +        }
> +        self.skip(len)?;
> +
> +        // SAFETY: `raw_strncpy_from_user` guarantees that this range of bytes represents a
> +        // NUL-terminated string with the only NUL byte being at the end.
> +        Ok(unsafe { CStr::from_bytes_with_nul_unchecked(&buf[..len]) })
> +    }
>  }
>  
>  /// A writer for [`UserSlice`].
> 
> -- 
> 2.49.0.901.g37484f566f-goog
> 

  reply	other threads:[~2025-04-29 10:36 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-29  9:02 [PATCH v2 0/2] strncpy_from_user for Rust Alice Ryhl
2025-04-29  9:02 ` [PATCH v2 1/2] uaccess: rust: add strncpy_from_user Alice Ryhl
2025-04-29 10:11   ` Danilo Krummrich
2025-04-29 10:30     ` Alice Ryhl
2025-04-29 11:04   ` Greg Kroah-Hartman
2025-04-29 15:09     ` Alice Ryhl
2025-04-29 17:30   ` Boqun Feng
2025-04-29 20:28     ` John Hubbard
2025-04-29 20:31       ` Boqun Feng
2025-04-29  9:02 ` [PATCH v2 2/2] uaccess: rust: add UserSliceReader::strcpy_into_buf Alice Ryhl
2025-04-29 10:36   ` Danilo Krummrich [this message]
2025-04-29 11:09   ` Greg Kroah-Hartman
2025-04-29 11:38     ` Danilo Krummrich
2025-04-29 11:48       ` Greg Kroah-Hartman
2025-04-29 15:15         ` Alice Ryhl
2025-04-29 15:50           ` Greg Kroah-Hartman
2025-04-30 10:58     ` Alice Ryhl
2025-04-30 11:04       ` Greg Kroah-Hartman
2025-04-29 18:02   ` Boqun Feng
2025-04-29 18:26     ` Boqun Feng
2025-04-29 19:29     ` Alice Ryhl
2025-04-29 19:47       ` Boqun Feng

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=aBCrqJe4two4I45G@pollux \
    --to=dakr@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=viro@zeniv.linux.org.uk \
    /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.