diff options
| author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-08-10 18:06:04 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-19 11:57:43 -0400 |
| commit | 4995a6913d6ada9672179736affd5606f2281edb (patch) | |
| tree | 9b52054a57787d48f497ff85c6fb950eb426245a /drivers/firewire | |
| parent | 9217bfbbade56ef9dfee88773c2105e619028fa1 (diff) | |
firewire: cdev: fix 32 bit userland on 64 bit kernel compat corner cases
commit 9c1176b6a28850703ea6e3a0f0c703f6d6c61cd3 upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/firewire')
| -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 { | |||
| 216 | struct fw_cdev_event_phy_packet phy_packet; | 216 | struct fw_cdev_event_phy_packet phy_packet; |
| 217 | }; | 217 | }; |
| 218 | 218 | ||
| 219 | static inline void __user *u64_to_uptr(__u64 value) | 219 | #ifdef CONFIG_COMPAT |
| 220 | static void __user *u64_to_uptr(u64 value) | ||
| 221 | { | ||
| 222 | if (is_compat_task()) | ||
| 223 | return compat_ptr(value); | ||
| 224 | else | ||
| 225 | return (void __user *)(unsigned long)value; | ||
| 226 | } | ||
| 227 | |||
| 228 | static u64 uptr_to_u64(void __user *ptr) | ||
| 229 | { | ||
| 230 | if (is_compat_task()) | ||
| 231 | return ptr_to_compat(ptr); | ||
| 232 | else | ||
| 233 | return (u64)(unsigned long)ptr; | ||
| 234 | } | ||
| 235 | #else | ||
| 236 | static inline void __user *u64_to_uptr(u64 value) | ||
| 220 | { | 237 | { |
| 221 | return (void __user *)(unsigned long)value; | 238 | return (void __user *)(unsigned long)value; |
| 222 | } | 239 | } |
| 223 | 240 | ||
| 224 | static inline __u64 uptr_to_u64(void __user *ptr) | 241 | static inline u64 uptr_to_u64(void __user *ptr) |
| 225 | { | 242 | { |
| 226 | return (__u64)(unsigned long)ptr; | 243 | return (u64)(unsigned long)ptr; |
| 227 | } | 244 | } |
| 245 | #endif /* CONFIG_COMPAT */ | ||
| 228 | 246 | ||
| 229 | static int fw_device_op_open(struct inode *inode, struct file *file) | 247 | static int fw_device_op_open(struct inode *inode, struct file *file) |
| 230 | { | 248 | { |
