mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
Merge patch series "uaccess/sockptr: copy_struct_ fixes and more helpers"
Stefan Metzmacher <metze@samba.org> says:
Here are some patches related to
copy_struct_{from,to}_{user,sockptr}()
I collected during my work on an IPPROTO_SMBDIRECT
implementation wrapping the smbdirect code used
by cifs.ko and ksmbd.ko.
The first patch fixes copy_struct_to_user()
to behave like documented.
The 2nd patch fixes the case where
copy_struct_from_user() is called by
copy_struct_from_sockptr().
The 3rd patch introduces
copy_struct_{from,to}_bounce_buffer()
as a result of a discussion about the
IPPROTO_QUIC driver in order to
be future prove when handling msg_control
messages in sendmsg and recvmsg.
But I'll likely also use them in my
IPPROTO_SMBDIRECT driver.
The 4th patch makes copy_struct_from_sockptr()
a trivial wrapper switching between
copy_struct_from_user() and
copy_struct_from_bounce_buffer()
The 5th patch introduces copy_struct_to_sockptr()
which I'll also use in my IPPROTO_SMBDIRECT driver.
* patches from https://patch.msgid.link/cover.1775576651.git.metze@samba.org:
sockptr: introduce copy_struct_to_sockptr()
sockptr: let copy_struct_from_sockptr() use copy_struct_from_bounce_buffer()
uaccess: add copy_struct_{from,to}_bounce_buffer() helpers
sockptr: fix usize check in copy_struct_from_sockptr() for user pointers
uaccess: fix ignored_trailing logic in copy_struct_to_user()
Link: https://patch.msgid.link/cover.1775576651.git.metze@samba.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
commit
6f43b87876
|
|
@ -87,24 +87,10 @@ static inline int copy_safe_from_sockptr(void *dst, size_t ksize,
|
|||
static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
|
||||
sockptr_t src, size_t usize)
|
||||
{
|
||||
size_t size = min(ksize, usize);
|
||||
size_t rest = max(ksize, usize) - size;
|
||||
|
||||
if (!sockptr_is_kernel(src))
|
||||
return copy_struct_from_user(dst, ksize, src.user, size);
|
||||
return copy_struct_from_user(dst, ksize, src.user, usize);
|
||||
|
||||
if (usize < ksize) {
|
||||
memset(dst + size, 0, rest);
|
||||
} else if (usize > ksize) {
|
||||
char *p = src.kernel;
|
||||
|
||||
while (rest--) {
|
||||
if (*p++)
|
||||
return -E2BIG;
|
||||
}
|
||||
}
|
||||
memcpy(dst, src.kernel, size);
|
||||
return 0;
|
||||
return copy_struct_from_bounce_buffer(dst, ksize, src.kernel, usize);
|
||||
}
|
||||
|
||||
static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
|
||||
|
|
@ -121,6 +107,16 @@ static inline int copy_to_sockptr(sockptr_t dst, const void *src, size_t size)
|
|||
return copy_to_sockptr_offset(dst, 0, src, size);
|
||||
}
|
||||
|
||||
static inline int
|
||||
copy_struct_to_sockptr(sockptr_t dst, size_t usize, const void *src,
|
||||
size_t ksize, bool *ignored_trailing)
|
||||
{
|
||||
if (!sockptr_is_kernel(dst))
|
||||
return copy_struct_to_user(dst.user, usize, src, ksize, ignored_trailing);
|
||||
|
||||
return copy_struct_to_bounce_buffer(dst.kernel, usize, src, ksize, ignored_trailing);
|
||||
}
|
||||
|
||||
static inline void *memdup_sockptr_noprof(sockptr_t src, size_t len)
|
||||
{
|
||||
void *p = kmalloc_track_caller_noprof(len, GFP_USER | __GFP_NOWARN);
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@ copy_struct_to_user(void __user *dst, size_t usize, const void *src,
|
|||
return -EFAULT;
|
||||
}
|
||||
if (ignored_trailing)
|
||||
*ignored_trailing = ksize < usize &&
|
||||
*ignored_trailing = usize < ksize &&
|
||||
memchr_inv(src + size, 0, rest) != NULL;
|
||||
/* Copy the interoperable parts of the struct. */
|
||||
if (copy_to_user(dst, src, size))
|
||||
|
|
@ -518,6 +518,69 @@ copy_struct_to_user(void __user *dst, size_t usize, const void *src,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
__copy_struct_generic_bounce_buffer(void *dst, size_t dstsize,
|
||||
const void *src, size_t srcsize,
|
||||
bool *ignored_trailing)
|
||||
{
|
||||
size_t size = min(dstsize, srcsize);
|
||||
size_t rest = max(dstsize, srcsize) - size;
|
||||
|
||||
/* Deal with trailing bytes. */
|
||||
if (dstsize > srcsize)
|
||||
memset(dst + size, 0, rest);
|
||||
if (ignored_trailing)
|
||||
*ignored_trailing = dstsize < srcsize &&
|
||||
memchr_inv(src + size, 0, rest) != NULL;
|
||||
/* Copy the interoperable parts of the struct. */
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is like copy_struct_from_user(), but the
|
||||
* src buffer was already copied into a kernel
|
||||
* bounce buffer, so it will never return -EFAULT.
|
||||
*/
|
||||
static __always_inline __must_check int
|
||||
copy_struct_from_bounce_buffer(void *dst, size_t dstsize,
|
||||
const void *src, size_t srcsize)
|
||||
{
|
||||
bool ignored_trailing;
|
||||
|
||||
/* Double check if ksize is larger than a known object size. */
|
||||
if (WARN_ON_ONCE(dstsize > __builtin_object_size(dst, 1)))
|
||||
return -E2BIG;
|
||||
|
||||
__copy_struct_generic_bounce_buffer(dst, dstsize,
|
||||
src, srcsize,
|
||||
&ignored_trailing);
|
||||
if (unlikely(ignored_trailing))
|
||||
return -E2BIG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is like copy_struct_to_user(), but the
|
||||
* dst buffer is a kernel bounce buffer instead
|
||||
* of a direct userspace buffer, so it will never return -EFAULT.
|
||||
*/
|
||||
static __always_inline __must_check int
|
||||
copy_struct_to_bounce_buffer(void *dst, size_t dstsize,
|
||||
const void *src,
|
||||
size_t srcsize,
|
||||
bool *ignored_trailing)
|
||||
{
|
||||
/* Double check if srcsize is larger than a known object size. */
|
||||
if (WARN_ON_ONCE(srcsize > __builtin_object_size(src, 1)))
|
||||
return -E2BIG;
|
||||
|
||||
__copy_struct_generic_bounce_buffer(dst, dstsize,
|
||||
src, srcsize,
|
||||
ignored_trailing);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size);
|
||||
|
||||
long copy_from_kernel_nofault(void *dst, const void *src, size_t size);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user