summaryrefslogtreecommitdiff
path: root/drivers/firewire/core-cdev.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2011-08-11 00:06:04 +0200
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-08-12 15:30:08 +0200
commit9c1176b6a28850703ea6e3a0f0c703f6d6c61cd3 (patch)
tree5e51f0e7e36c78ae63e3128125cb008bcc442aa0 /drivers/firewire/core-cdev.c
parent9a00c24ae7cb08dcd46edf1327a47871e8466444 (diff)
downloadlwn-9c1176b6a28850703ea6e3a0f0c703f6d6c61cd3.tar.gz
lwn-9c1176b6a28850703ea6e3a0f0c703f6d6c61cd3.zip
firewire: cdev: fix 32 bit userland on 64 bit kernel compat corner cases
Clemens points out that we need to use compat_ptr() in order to safely cast from u64 to addresses of a 32-bit usermode client. Before, our conversion went wrong - in practice if the client cast from pointer to integer such that sign-extension happened, (libraw1394 and libdc1394 at least were not doing that, IOW were not affected) or - in theory on s390 (which doesn't have FireWire though) and on the tile architecture, regardless of what the client does. The bug would usually be observed as the initial get_info ioctl failing with "Bad address" (EFAULT). Reported-by: Carl Karsten <carl@personnelware.com> Reported-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/core-cdev.c')
-rw-r--r--drivers/firewire/core-cdev.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index e6ad3bb6c1a6..4799393247c8 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -216,15 +216,33 @@ struct inbound_phy_packet_event {
struct fw_cdev_event_phy_packet phy_packet;
};
-static inline void __user *u64_to_uptr(__u64 value)
+#ifdef CONFIG_COMPAT
+static void __user *u64_to_uptr(u64 value)
+{
+ if (is_compat_task())
+ return compat_ptr(value);
+ else
+ return (void __user *)(unsigned long)value;
+}
+
+static u64 uptr_to_u64(void __user *ptr)
+{
+ if (is_compat_task())
+ return ptr_to_compat(ptr);
+ else
+ return (u64)(unsigned long)ptr;
+}
+#else
+static inline void __user *u64_to_uptr(u64 value)
{
return (void __user *)(unsigned long)value;
}
-static inline __u64 uptr_to_u64(void __user *ptr)
+static inline u64 uptr_to_u64(void __user *ptr)
{
- return (__u64)(unsigned long)ptr;
+ return (u64)(unsigned long)ptr;
}
+#endif /* CONFIG_COMPAT */
static int fw_device_op_open(struct inode *inode, struct file *file)
{