IB/uverbs: Use u64_to_user_ptr() not a union
authorJason Gunthorpe <jgg@mellanox.com>
Tue, 13 Feb 2018 10:18:31 +0000 (12:18 +0200)
committerJason Gunthorpe <jgg@mellanox.com>
Thu, 15 Feb 2018 21:59:45 +0000 (14:59 -0700)
The union approach will get the endianness wrong sometimes if the kernel's
pointer size is 32 bits resulting in EFAULTs when trying to copy to/from
user.

Signed-off-by: Leon Romanovsky <leon@kernel.org>
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/uverbs_std_types.c
include/rdma/uverbs_ioctl.h

index 7b0e4d778d794bb2fd734cc5fd0e26a6a9d2f503..df1360e6774f4e3d05631b353cf0f4352037832f 100644 (file)
@@ -238,14 +238,14 @@ static void create_udata(struct uverbs_attr_bundle *ctx,
                if (uverbs_attr_ptr_is_inline(uhw_in))
                        udata->inbuf = &uhw_in->uattr->data;
                else
-                       udata->inbuf = uhw_in->ptr_attr.ptr;
+                       udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data);
        } else {
                udata->inbuf = NULL;
                udata->inlen = 0;
        }
 
        if (!IS_ERR(uhw_out)) {
-               udata->outbuf = uhw_out->ptr_attr.ptr;
+               udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data);
                udata->outlen = uhw_out->ptr_attr.len;
        } else {
                udata->outbuf = NULL;
index 32cb14703914bc6df7dd058089730eef6e030749..38287d9d23a1f90b4e03f023db0fa2d5fa2175fd 100644 (file)
@@ -276,10 +276,7 @@ struct uverbs_object_tree_def {
  */
 
 struct uverbs_ptr_attr {
-       union {
-               u64             data;
-               void    __user *ptr;
-       };
+       u64             data;
        u16             len;
        /* Combination of bits from enum UVERBS_ATTR_F_XXXX */
        u16             flags;
@@ -361,7 +358,7 @@ static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle,
                return PTR_ERR(attr);
 
        min_size = min_t(size_t, attr->ptr_attr.len, size);
-       if (copy_to_user(attr->ptr_attr.ptr, from, min_size))
+       if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
                return -EFAULT;
 
        flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT;
@@ -396,7 +393,8 @@ static inline int _uverbs_copy_from(void *to,
 
        if (uverbs_attr_ptr_is_inline(attr))
                memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len);
-       else if (copy_from_user(to, attr->ptr_attr.ptr, attr->ptr_attr.len))
+       else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data),
+                               attr->ptr_attr.len))
                return -EFAULT;
 
        return 0;