]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
RDMA/ucma: Fix uABI structure layouts for 32/64 compat
authorJason Gunthorpe <jgg@mellanox.com>
Tue, 20 Mar 2018 20:19:47 +0000 (14:19 -0600)
committerJason Gunthorpe <jgg@mellanox.com>
Tue, 27 Mar 2018 20:25:08 +0000 (14:25 -0600)
The rdma_ucm_event_resp is a different length on 32 and 64 bit compiles.

The kernel requires it to be the expected length or longer so 32 bit
builds running on a 64 bit kernel will not work.

Retain full compat by having all kernels accept a struct with or without
the trailing reserved field.

Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/ucma.c
include/uapi/rdma/rdma_user_cm.h

index 4bb5bed596c9d875521da1ad84c630570e39795b..db4190b2ed27416d1ca379076e79825f0d86c271 100644 (file)
@@ -382,7 +382,11 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf,
        struct ucma_event *uevent;
        int ret = 0;
 
-       if (out_len < sizeof uevent->resp)
+       /*
+        * Old 32 bit user space does not send the 4 byte padding in the
+        * reserved field. We don't care, allow it to keep working.
+        */
+       if (out_len < sizeof(uevent->resp) - sizeof(uevent->resp.reserved))
                return -ENOSPC;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
@@ -417,7 +421,8 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf,
        }
 
        if (copy_to_user((void __user *)(unsigned long)cmd.response,
-                        &uevent->resp, sizeof uevent->resp)) {
+                        &uevent->resp,
+                        min_t(size_t, out_len, sizeof(uevent->resp)))) {
                ret = -EFAULT;
                goto done;
        }
index c83ef0026079c8e427c46e0beaee7e6e56a63311..65399c837762f5a1eb437d16130ff797d9f022b1 100644 (file)
@@ -270,10 +270,15 @@ struct rdma_ucm_event_resp {
        __u32 id;
        __u32 event;
        __u32 status;
+       /*
+        * NOTE: This union is not aligned to 8 bytes so none of the union
+        * members may contain a u64 or anything with higher alignment than 4.
+        */
        union {
                struct rdma_ucm_conn_param conn;
                struct rdma_ucm_ud_param   ud;
        } param;
+       __u32 reserved;
 };
 
 /* Option levels */