diff options
| author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-08-11 00:06:04 +0200 | 
|---|---|---|
| committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-08-12 15:30:08 +0200 | 
| commit | 9c1176b6a28850703ea6e3a0f0c703f6d6c61cd3 (patch) | |
| tree | 5e51f0e7e36c78ae63e3128125cb008bcc442aa0 /drivers/firewire/core-cdev.c | |
| parent | 9a00c24ae7cb08dcd46edf1327a47871e8466444 (diff) | |
| download | olio-linux-3.10-9c1176b6a28850703ea6e3a0f0c703f6d6c61cd3.tar.xz olio-linux-3.10-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.c | 24 | 
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index e6ad3bb6c1a..4799393247c 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)  {  |