On 13/12/2022 12:55, Beata Michalska wrote:
Introduce a variant of copy_struct_from_user that will make use of copy_to_user_with_ptr as its actual copying routine, in order to
Just noticed, s/copy_to_user/copy_from_user/
Kevin
preserve capability tags throughout the process.
Signed-off-by: Beata Michalska beata.michalska@arm.com
include/linux/uaccess.h | 60 ++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 13 deletions(-)
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 88b2224e85c3..e17bd4dce0d6 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -356,6 +356,24 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from, extern __must_check int check_zeroed_user(const void __user *from, size_t size); +static __always_inline __must_check int +__copy_struct_from_user_prepare(void *dst, size_t ksize, const void __user *src,
size_t usize)
+{
- size_t size = min(ksize, usize);
- size_t rest = max(ksize, usize) - size;
- /* Deal with trailing bytes. */
- if (usize < ksize) {
memset(dst + size, 0, rest);
- } else if (usize > ksize) {
int ret = check_zeroed_user(src + size, rest);
if (ret <= 0)
return ret ?: -E2BIG;
- }
- return 0;
+}
/**
- copy_struct_from_user: copy a struct from userspace
- @dst: Destination address, in kernel space. This buffer must be @ksize
@@ -408,20 +426,36 @@ copy_struct_from_user(void *dst, size_t ksize, const void __user *src, size_t usize) { size_t size = min(ksize, usize);
- size_t rest = max(ksize, usize) - size;
- int ret;
- /* Deal with trailing bytes. */
- if (usize < ksize) {
memset(dst + size, 0, rest);
- } else if (usize > ksize) {
int ret = check_zeroed_user(src + size, rest);
if (ret <= 0)
return ret ?: -E2BIG;
- }
- /* Copy the interoperable parts of the struct. */
- if (copy_from_user(dst, src, size))
return -EFAULT;
- return 0;
- ret = __copy_struct_from_user_prepare(dst, ksize, src, usize);
- return ret ?: (copy_from_user(dst, src, size) ? -EFAULT : 0);
+}
+/**
- copy_struct_from_user_with_ptr: copy a struct from userspace
- @dst: Destination address, in kernel space. This buffer must be @ksize
bytes long.
- @ksize: Size of @dst struct.
- @src: Source address, in userspace.
- @usize: (Alleged) size of @src struct.
- Counterpart of copy_struct_from_user that deals with structures,
- members of which can contain user pointers.
- Otherwise, same logic/requirements apply.
- */
+static __always_inline __must_check int +copy_struct_from_user_with_ptr(void *dst, size_t ksize, const void __user *src,
size_t usize)
+{
- size_t size = min(ksize, usize);
- int ret;
- ret = __copy_struct_from_user_prepare(dst, ksize, src, usize);
- return ret ?: (copy_from_user_with_ptr(dst, src, size) ? -EFAULT : 0);
} bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size);