diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2009-08-24 18:42:56 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2010-10-19 05:29:54 -0400 |
commit | c4a047272566b44b44222369d50a307c708c4f74 (patch) | |
tree | 05f3883b35741afb8afec90c61891f8a1b2c8da9 /fs/compat_ioctl.c | |
parent | 9a181c58617134822ae596339dbea076ef9b5cf7 (diff) |
fix rawctl compat ioctls breakage on amd64 and itanic
RAW_SETBIND and RAW_GETBIND 32bit versions are fscked in interesting ways.
1) fs/compat_ioctl.c has COMPATIBLE_IOCTL(RAW_SETBIND) followed by
HANDLE_IOCTL(RAW_SETBIND, raw_ioctl). The latter is ignored.
2) on amd64 (and itanic) the damn thing is broken - we have int + u64 + u64
and layouts on i386 and amd64 are _not_ the same. raw_ioctl() would
work there, but it's never called due to (1). As it is, i386 /sbin/raw
definitely doesn't work on amd64 boxen.
3) switching to raw_ioctl() as is would *not* work on e.g. sparc64 and ppc64,
which would be rather sad, seeing that normal userland there is 32bit.
The thing is, slapping __packed on the struct in question does not DTRT -
it eliminates *all* padding. The real solution is to use compat_u64.
4) of course, all that stuff has no business being outside of raw.c in the
first place - there should be ->compat_ioctl() for /dev/rawctl instead of
messing with compat_ioctl.c.
[akpm@linux-foundation.org: coding-style fixes]
[arnd@arndb.de: port to 2.6.36]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'fs/compat_ioctl.c')
-rw-r--r-- | fs/compat_ioctl.c | 70 |
1 files changed, 0 insertions, 70 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 03e59aa318eb..d0ad09d57789 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -599,69 +599,6 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, | |||
599 | #define HIDPGETCONNLIST _IOR('H', 210, int) | 599 | #define HIDPGETCONNLIST _IOR('H', 210, int) |
600 | #define HIDPGETCONNINFO _IOR('H', 211, int) | 600 | #define HIDPGETCONNINFO _IOR('H', 211, int) |
601 | 601 | ||
602 | #ifdef CONFIG_BLOCK | ||
603 | struct raw32_config_request | ||
604 | { | ||
605 | compat_int_t raw_minor; | ||
606 | __u64 block_major; | ||
607 | __u64 block_minor; | ||
608 | } __attribute__((packed)); | ||
609 | |||
610 | static int get_raw32_request(struct raw_config_request *req, struct raw32_config_request __user *user_req) | ||
611 | { | ||
612 | int ret; | ||
613 | |||
614 | if (!access_ok(VERIFY_READ, user_req, sizeof(struct raw32_config_request))) | ||
615 | return -EFAULT; | ||
616 | |||
617 | ret = __get_user(req->raw_minor, &user_req->raw_minor); | ||
618 | ret |= __get_user(req->block_major, &user_req->block_major); | ||
619 | ret |= __get_user(req->block_minor, &user_req->block_minor); | ||
620 | |||
621 | return ret ? -EFAULT : 0; | ||
622 | } | ||
623 | |||
624 | static int set_raw32_request(struct raw_config_request *req, struct raw32_config_request __user *user_req) | ||
625 | { | ||
626 | int ret; | ||
627 | |||
628 | if (!access_ok(VERIFY_WRITE, user_req, sizeof(struct raw32_config_request))) | ||
629 | return -EFAULT; | ||
630 | |||
631 | ret = __put_user(req->raw_minor, &user_req->raw_minor); | ||
632 | ret |= __put_user(req->block_major, &user_req->block_major); | ||
633 | ret |= __put_user(req->block_minor, &user_req->block_minor); | ||
634 | |||
635 | return ret ? -EFAULT : 0; | ||
636 | } | ||
637 | |||
638 | static int raw_ioctl(unsigned fd, unsigned cmd, | ||
639 | struct raw32_config_request __user *user_req) | ||
640 | { | ||
641 | int ret; | ||
642 | |||
643 | switch (cmd) { | ||
644 | case RAW_SETBIND: | ||
645 | default: { /* RAW_GETBIND */ | ||
646 | struct raw_config_request req; | ||
647 | mm_segment_t oldfs = get_fs(); | ||
648 | |||
649 | if ((ret = get_raw32_request(&req, user_req))) | ||
650 | return ret; | ||
651 | |||
652 | set_fs(KERNEL_DS); | ||
653 | ret = sys_ioctl(fd,cmd,(unsigned long)&req); | ||
654 | set_fs(oldfs); | ||
655 | |||
656 | if ((!ret) && (cmd == RAW_GETBIND)) { | ||
657 | ret = set_raw32_request(&req, user_req); | ||
658 | } | ||
659 | break; | ||
660 | } | ||
661 | } | ||
662 | return ret; | ||
663 | } | ||
664 | #endif /* CONFIG_BLOCK */ | ||
665 | 602 | ||
666 | struct serial_struct32 { | 603 | struct serial_struct32 { |
667 | compat_int_t type; | 604 | compat_int_t type; |
@@ -1262,9 +1199,6 @@ COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5) | |||
1262 | COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) | 1199 | COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) |
1263 | COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) | 1200 | COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) |
1264 | COMPATIBLE_IOCTL(OSS_GETVERSION) | 1201 | COMPATIBLE_IOCTL(OSS_GETVERSION) |
1265 | /* Raw devices */ | ||
1266 | COMPATIBLE_IOCTL(RAW_SETBIND) | ||
1267 | COMPATIBLE_IOCTL(RAW_GETBIND) | ||
1268 | /* SMB ioctls which do not need any translations */ | 1202 | /* SMB ioctls which do not need any translations */ |
1269 | COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) | 1203 | COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) |
1270 | /* Watchdog */ | 1204 | /* Watchdog */ |
@@ -1523,10 +1457,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd, | |||
1523 | case MTIOCGET32: | 1457 | case MTIOCGET32: |
1524 | case MTIOCPOS32: | 1458 | case MTIOCPOS32: |
1525 | return mt_ioctl_trans(fd, cmd, argp); | 1459 | return mt_ioctl_trans(fd, cmd, argp); |
1526 | /* Raw devices */ | ||
1527 | case RAW_SETBIND: | ||
1528 | case RAW_GETBIND: | ||
1529 | return raw_ioctl(fd, cmd, argp); | ||
1530 | #endif | 1460 | #endif |
1531 | /* One SMB ioctl needs translations. */ | 1461 | /* One SMB ioctl needs translations. */ |
1532 | #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) | 1462 | #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) |