diff options
-rw-r--r-- | drivers/infiniband/core/user_mad.c | 49 | ||||
-rw-r--r-- | include/rdma/ib_user_mad.h | 22 |
2 files changed, 61 insertions, 10 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index aee29139368c..b53eac4611de 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/poll.h> | 44 | #include <linux/poll.h> |
45 | #include <linux/rwsem.h> | 45 | #include <linux/rwsem.h> |
46 | #include <linux/kref.h> | 46 | #include <linux/kref.h> |
47 | #include <linux/compat.h> | ||
47 | 48 | ||
48 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
49 | #include <asm/semaphore.h> | 50 | #include <asm/semaphore.h> |
@@ -607,7 +608,8 @@ static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wa | |||
607 | return mask; | 608 | return mask; |
608 | } | 609 | } |
609 | 610 | ||
610 | static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) | 611 | static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, |
612 | int compat_method_mask) | ||
611 | { | 613 | { |
612 | struct ib_user_mad_reg_req ureq; | 614 | struct ib_user_mad_reg_req ureq; |
613 | struct ib_mad_reg_req req; | 615 | struct ib_mad_reg_req req; |
@@ -622,7 +624,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) | |||
622 | goto out; | 624 | goto out; |
623 | } | 625 | } |
624 | 626 | ||
625 | if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { | 627 | if (copy_from_user(&ureq, arg, sizeof ureq)) { |
626 | ret = -EFAULT; | 628 | ret = -EFAULT; |
627 | goto out; | 629 | goto out; |
628 | } | 630 | } |
@@ -643,8 +645,18 @@ found: | |||
643 | if (ureq.mgmt_class) { | 645 | if (ureq.mgmt_class) { |
644 | req.mgmt_class = ureq.mgmt_class; | 646 | req.mgmt_class = ureq.mgmt_class; |
645 | req.mgmt_class_version = ureq.mgmt_class_version; | 647 | req.mgmt_class_version = ureq.mgmt_class_version; |
646 | memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask); | 648 | memcpy(req.oui, ureq.oui, sizeof req.oui); |
647 | memcpy(req.oui, ureq.oui, sizeof req.oui); | 649 | |
650 | if (compat_method_mask) { | ||
651 | u32 *umm = (u32 *) ureq.method_mask; | ||
652 | int i; | ||
653 | |||
654 | for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i) | ||
655 | req.method_mask[i] = | ||
656 | umm[i * 2] | ((u64) umm[i * 2 + 1] << 32); | ||
657 | } else | ||
658 | memcpy(req.method_mask, ureq.method_mask, | ||
659 | sizeof req.method_mask); | ||
648 | } | 660 | } |
649 | 661 | ||
650 | agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, | 662 | agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, |
@@ -682,13 +694,13 @@ out: | |||
682 | return ret; | 694 | return ret; |
683 | } | 695 | } |
684 | 696 | ||
685 | static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) | 697 | static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) |
686 | { | 698 | { |
687 | struct ib_mad_agent *agent = NULL; | 699 | struct ib_mad_agent *agent = NULL; |
688 | u32 id; | 700 | u32 id; |
689 | int ret = 0; | 701 | int ret = 0; |
690 | 702 | ||
691 | if (get_user(id, (u32 __user *) arg)) | 703 | if (get_user(id, arg)) |
692 | return -EFAULT; | 704 | return -EFAULT; |
693 | 705 | ||
694 | down_write(&file->port->mutex); | 706 | down_write(&file->port->mutex); |
@@ -729,9 +741,9 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, | |||
729 | { | 741 | { |
730 | switch (cmd) { | 742 | switch (cmd) { |
731 | case IB_USER_MAD_REGISTER_AGENT: | 743 | case IB_USER_MAD_REGISTER_AGENT: |
732 | return ib_umad_reg_agent(filp->private_data, arg); | 744 | return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0); |
733 | case IB_USER_MAD_UNREGISTER_AGENT: | 745 | case IB_USER_MAD_UNREGISTER_AGENT: |
734 | return ib_umad_unreg_agent(filp->private_data, arg); | 746 | return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg); |
735 | case IB_USER_MAD_ENABLE_PKEY: | 747 | case IB_USER_MAD_ENABLE_PKEY: |
736 | return ib_umad_enable_pkey(filp->private_data); | 748 | return ib_umad_enable_pkey(filp->private_data); |
737 | default: | 749 | default: |
@@ -739,6 +751,23 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, | |||
739 | } | 751 | } |
740 | } | 752 | } |
741 | 753 | ||
754 | #ifdef CONFIG_COMPAT | ||
755 | static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd, | ||
756 | unsigned long arg) | ||
757 | { | ||
758 | switch (cmd) { | ||
759 | case IB_USER_MAD_REGISTER_AGENT: | ||
760 | return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1); | ||
761 | case IB_USER_MAD_UNREGISTER_AGENT: | ||
762 | return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg)); | ||
763 | case IB_USER_MAD_ENABLE_PKEY: | ||
764 | return ib_umad_enable_pkey(filp->private_data); | ||
765 | default: | ||
766 | return -ENOIOCTLCMD; | ||
767 | } | ||
768 | } | ||
769 | #endif | ||
770 | |||
742 | static int ib_umad_open(struct inode *inode, struct file *filp) | 771 | static int ib_umad_open(struct inode *inode, struct file *filp) |
743 | { | 772 | { |
744 | struct ib_umad_port *port; | 773 | struct ib_umad_port *port; |
@@ -826,7 +855,9 @@ static const struct file_operations umad_fops = { | |||
826 | .write = ib_umad_write, | 855 | .write = ib_umad_write, |
827 | .poll = ib_umad_poll, | 856 | .poll = ib_umad_poll, |
828 | .unlocked_ioctl = ib_umad_ioctl, | 857 | .unlocked_ioctl = ib_umad_ioctl, |
829 | .compat_ioctl = ib_umad_ioctl, | 858 | #ifdef CONFIG_COMPAT |
859 | .compat_ioctl = ib_umad_compat_ioctl, | ||
860 | #endif | ||
830 | .open = ib_umad_open, | 861 | .open = ib_umad_open, |
831 | .release = ib_umad_close | 862 | .release = ib_umad_close |
832 | }; | 863 | }; |
diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index 2a32043d1abd..29d2c7205a90 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h | |||
@@ -147,6 +147,26 @@ struct ib_user_mad { | |||
147 | __u64 data[0]; | 147 | __u64 data[0]; |
148 | }; | 148 | }; |
149 | 149 | ||
150 | /* | ||
151 | * Earlier versions of this interface definition declared the | ||
152 | * method_mask[] member as an array of __u32 but treated it as a | ||
153 | * bitmap made up of longs in the kernel. This ambiguity meant that | ||
154 | * 32-bit big-endian applications that can run on both 32-bit and | ||
155 | * 64-bit kernels had no consistent ABI to rely on, and 64-bit | ||
156 | * big-endian applications that treated method_mask as being made up | ||
157 | * of 32-bit words would have their bitmap misinterpreted. | ||
158 | * | ||
159 | * To clear up this confusion, we change the declaration of | ||
160 | * method_mask[] to use unsigned long and handle the conversion from | ||
161 | * 32-bit userspace to 64-bit kernel for big-endian systems in the | ||
162 | * compat_ioctl method. Unfortunately, to keep the structure layout | ||
163 | * the same, we need the method_mask[] array to be aligned only to 4 | ||
164 | * bytes even when long is 64 bits, which forces us into this ugly | ||
165 | * typedef. | ||
166 | */ | ||
167 | typedef unsigned long __attribute__((aligned(4))) packed_ulong; | ||
168 | #define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof (long))) | ||
169 | |||
150 | /** | 170 | /** |
151 | * ib_user_mad_reg_req - MAD registration request | 171 | * ib_user_mad_reg_req - MAD registration request |
152 | * @id - Set by the kernel; used to identify agent in future requests. | 172 | * @id - Set by the kernel; used to identify agent in future requests. |
@@ -165,7 +185,7 @@ struct ib_user_mad { | |||
165 | */ | 185 | */ |
166 | struct ib_user_mad_reg_req { | 186 | struct ib_user_mad_reg_req { |
167 | __u32 id; | 187 | __u32 id; |
168 | __u32 method_mask[4]; | 188 | packed_ulong method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK]; |
169 | __u8 qpn; | 189 | __u8 qpn; |
170 | __u8 mgmt_class; | 190 | __u8 mgmt_class; |
171 | __u8 mgmt_class_version; | 191 | __u8 mgmt_class_version; |