Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

compat_ioctl: move tape handling into drivers

MTIOCPOS and MTIOCGET are incompatible between 32-bit and 64-bit user
space, and traditionally have been translated in fs/compat_ioctl.c.

To get rid of that translation handler, move a corresponding
implementation into each of the four drivers implementing those commands.

The interesting part of that is now in a new linux/mtio.h header that
wraps the existing uapi/linux/mtio.h header and provides an abstraction
to let drivers handle both cases easily. Using an in_compat_syscall()
check, the caller does not have to keep track of whether this was
called through .unlocked_ioctl() or .compat_ioctl().

Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: "Kai Mäkisara" <Kai.Makisara@kolumbus.fi>
Cc: linux-scsi@vger.kernel.org
Cc: "James E.J. Bottomley" <jejb@linux.ibm.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+114 -115
+21 -6
drivers/ide/ide-tape.c
··· 19 19 20 20 #define IDETAPE_VERSION "1.20" 21 21 22 + #include <linux/compat.h> 22 23 #include <linux/module.h> 23 24 #include <linux/types.h> 24 25 #include <linux/string.h> ··· 1408 1407 if (tape->drv_write_prot) 1409 1408 mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); 1410 1409 1411 - if (copy_to_user(argp, &mtget, sizeof(struct mtget))) 1412 - return -EFAULT; 1413 - return 0; 1410 + return put_user_mtget(argp, &mtget); 1414 1411 case MTIOCPOS: 1415 1412 mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; 1416 - if (copy_to_user(argp, &mtpos, sizeof(struct mtpos))) 1417 - return -EFAULT; 1418 - return 0; 1413 + return put_user_mtpos(argp, &mtpos); 1419 1414 default: 1420 1415 if (tape->chrdev_dir == IDETAPE_DIR_READ) 1421 1416 ide_tape_discard_merge_buffer(drive, 1); ··· 1423 1426 unsigned int cmd, unsigned long arg) 1424 1427 { 1425 1428 long ret; 1429 + mutex_lock(&ide_tape_mutex); 1430 + ret = do_idetape_chrdev_ioctl(file, cmd, arg); 1431 + mutex_unlock(&ide_tape_mutex); 1432 + return ret; 1433 + } 1434 + 1435 + static long idetape_chrdev_compat_ioctl(struct file *file, 1436 + unsigned int cmd, unsigned long arg) 1437 + { 1438 + long ret; 1439 + 1440 + if (cmd == MTIOCPOS32) 1441 + cmd = MTIOCPOS; 1442 + else if (cmd == MTIOCGET32) 1443 + cmd = MTIOCGET; 1444 + 1426 1445 mutex_lock(&ide_tape_mutex); 1427 1446 ret = do_idetape_chrdev_ioctl(file, cmd, arg); 1428 1447 mutex_unlock(&ide_tape_mutex); ··· 1899 1886 .read = idetape_chrdev_read, 1900 1887 .write = idetape_chrdev_write, 1901 1888 .unlocked_ioctl = idetape_chrdev_ioctl, 1889 + .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ? 1890 + idetape_chrdev_compat_ioctl : NULL, 1902 1891 .open = idetape_chrdev_open, 1903 1892 .release = idetape_chrdev_release, 1904 1893 .llseek = noop_llseek,
+15 -26
drivers/s390/char/tape_char.c
··· 341 341 */ 342 342 static int 343 343 __tapechar_ioctl(struct tape_device *device, 344 - unsigned int no, unsigned long data) 344 + unsigned int no, void __user *data) 345 345 { 346 346 int rc; 347 347 348 348 if (no == MTIOCTOP) { 349 349 struct mtop op; 350 350 351 - if (copy_from_user(&op, (char __user *) data, sizeof(op)) != 0) 351 + if (copy_from_user(&op, data, sizeof(op)) != 0) 352 352 return -EFAULT; 353 353 if (op.mt_count < 0) 354 354 return -EINVAL; ··· 392 392 if (rc < 0) 393 393 return rc; 394 394 pos.mt_blkno = rc; 395 - if (copy_to_user((char __user *) data, &pos, sizeof(pos)) != 0) 396 - return -EFAULT; 397 - return 0; 395 + return put_user_mtpos(data, &pos); 398 396 } 399 397 if (no == MTIOCGET) { 400 398 /* MTIOCGET: query the tape drive status. */ ··· 422 424 get.mt_blkno = rc; 423 425 } 424 426 425 - if (copy_to_user((char __user *) data, &get, sizeof(get)) != 0) 426 - return -EFAULT; 427 - 428 - return 0; 427 + return put_user_mtget(data, &get); 429 428 } 430 429 /* Try the discipline ioctl function. */ 431 430 if (device->discipline->ioctl_fn == NULL) 432 431 return -EINVAL; 433 - return device->discipline->ioctl_fn(device, no, data); 432 + return device->discipline->ioctl_fn(device, no, (unsigned long)data); 434 433 } 435 434 436 435 static long ··· 440 445 441 446 device = (struct tape_device *) filp->private_data; 442 447 mutex_lock(&device->mutex); 443 - rc = __tapechar_ioctl(device, no, data); 448 + rc = __tapechar_ioctl(device, no, (void __user *)data); 444 449 mutex_unlock(&device->mutex); 445 450 return rc; 446 451 } ··· 450 455 tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data) 451 456 { 452 457 struct tape_device *device = filp->private_data; 453 - int rval = -ENOIOCTLCMD; 454 - unsigned long argp; 458 + long rc; 455 459 456 - /* The 'arg' argument of any ioctl function may only be used for 457 - * pointers because of the compat pointer conversion. 458 - * Consider this when adding new ioctls. 459 - */ 460 - argp = (unsigned long) compat_ptr(data); 461 - if (device->discipline->ioctl_fn) { 462 - mutex_lock(&device->mutex); 463 - rval = device->discipline->ioctl_fn(device, no, argp); 464 - mutex_unlock(&device->mutex); 465 - if (rval == -EINVAL) 466 - rval = -ENOIOCTLCMD; 467 - } 460 + if (no == MTIOCPOS32) 461 + no = MTIOCPOS; 462 + else if (no == MTIOCGET32) 463 + no = MTIOCGET; 468 464 469 - return rval; 465 + mutex_lock(&device->mutex); 466 + rc = __tapechar_ioctl(device, no, compat_ptr(data)); 467 + mutex_unlock(&device->mutex); 468 + return rc; 470 469 } 471 470 #endif /* CONFIG_COMPAT */ 472 471
+18 -10
drivers/scsi/st.c
··· 22 22 23 23 #include <linux/module.h> 24 24 25 + #include <linux/compat.h> 25 26 #include <linux/fs.h> 26 27 #include <linux/kernel.h> 27 28 #include <linux/sched/signal.h> ··· 3801 3800 if (STp->cleaning_req) 3802 3801 mt_status.mt_gstat |= GMT_CLN(0xffffffff); 3803 3802 3804 - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); 3805 - if (i) { 3806 - retval = (-EFAULT); 3803 + retval = put_user_mtget(p, &mt_status); 3804 + if (retval) 3807 3805 goto out; 3808 - } 3809 3806 3810 3807 STp->recover_reg = 0; /* Clear after read */ 3811 - retval = 0; 3812 3808 goto out; 3813 3809 } /* End of MTIOCGET */ 3814 3810 if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { ··· 3819 3821 goto out; 3820 3822 } 3821 3823 mt_pos.mt_blkno = blk; 3822 - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); 3823 - if (i) 3824 - retval = (-EFAULT); 3824 + retval = put_user_mtpos(p, &mt_pos); 3825 3825 goto out; 3826 3826 } 3827 3827 mutex_unlock(&STp->lock); ··· 3853 3857 } 3854 3858 3855 3859 #ifdef CONFIG_COMPAT 3856 - static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 3860 + static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) 3857 3861 { 3862 + void __user *p = compat_ptr(arg); 3858 3863 struct scsi_tape *STp = file->private_data; 3859 3864 struct scsi_device *sdev = STp->device; 3860 3865 int ret = -ENOIOCTLCMD; 3866 + 3867 + /* argument conversion is handled using put_user_mtpos/put_user_mtget */ 3868 + switch (cmd_in) { 3869 + case MTIOCTOP: 3870 + return st_ioctl(file, MTIOCTOP, (unsigned long)p); 3871 + case MTIOCPOS32: 3872 + return st_ioctl(file, MTIOCPOS, (unsigned long)p); 3873 + case MTIOCGET32: 3874 + return st_ioctl(file, MTIOCGET, (unsigned long)p); 3875 + } 3876 + 3861 3877 if (sdev->host->hostt->compat_ioctl) { 3862 3878 3863 - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); 3879 + ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); 3864 3880 3865 3881 } 3866 3882 return ret;
-73
fs/compat_ioctl.c
··· 27 27 #include <linux/file.h> 28 28 #include <linux/ppp-ioctl.h> 29 29 #include <linux/if_pppox.h> 30 - #include <linux/mtio.h> 31 30 #include <linux/tty.h> 32 31 #include <linux/vt_kern.h> 33 32 #include <linux/raw.h> ··· 360 361 return do_ioctl(file, PPPIOCSCOMPRESS, (unsigned long) odata); 361 362 } 362 363 363 - #ifdef CONFIG_BLOCK 364 - struct mtget32 { 365 - compat_long_t mt_type; 366 - compat_long_t mt_resid; 367 - compat_long_t mt_dsreg; 368 - compat_long_t mt_gstat; 369 - compat_long_t mt_erreg; 370 - compat_daddr_t mt_fileno; 371 - compat_daddr_t mt_blkno; 372 - }; 373 - #define MTIOCGET32 _IOR('m', 2, struct mtget32) 374 - 375 - struct mtpos32 { 376 - compat_long_t mt_blkno; 377 - }; 378 - #define MTIOCPOS32 _IOR('m', 3, struct mtpos32) 379 - 380 - static int mt_ioctl_trans(struct file *file, 381 - unsigned int cmd, void __user *argp) 382 - { 383 - /* NULL initialization to make gcc shut up */ 384 - struct mtget __user *get = NULL; 385 - struct mtget32 __user *umget32; 386 - struct mtpos __user *pos = NULL; 387 - struct mtpos32 __user *upos32; 388 - unsigned long kcmd; 389 - void *karg; 390 - int err = 0; 391 - 392 - switch(cmd) { 393 - case MTIOCPOS32: 394 - kcmd = MTIOCPOS; 395 - pos = compat_alloc_user_space(sizeof(*pos)); 396 - karg = pos; 397 - break; 398 - default: /* MTIOCGET32 */ 399 - kcmd = MTIOCGET; 400 - get = compat_alloc_user_space(sizeof(*get)); 401 - karg = get; 402 - break; 403 - } 404 - if (karg == NULL) 405 - return -EFAULT; 406 - err = do_ioctl(file, kcmd, (unsigned long)karg); 407 - if (err) 408 - return err; 409 - switch (cmd) { 410 - case MTIOCPOS32: 411 - upos32 = argp; 412 - err = convert_in_user(&pos->mt_blkno, &upos32->mt_blkno); 413 - break; 414 - case MTIOCGET32: 415 - umget32 = argp; 416 - err = convert_in_user(&get->mt_type, &umget32->mt_type); 417 - err |= convert_in_user(&get->mt_resid, &umget32->mt_resid); 418 - err |= convert_in_user(&get->mt_dsreg, &umget32->mt_dsreg); 419 - err |= convert_in_user(&get->mt_gstat, &umget32->mt_gstat); 420 - err |= convert_in_user(&get->mt_erreg, &umget32->mt_erreg); 421 - err |= convert_in_user(&get->mt_fileno, &umget32->mt_fileno); 422 - err |= convert_in_user(&get->mt_blkno, &umget32->mt_blkno); 423 - break; 424 - } 425 - return err ? -EFAULT: 0; 426 - } 427 - 428 - #endif /* CONFIG_BLOCK */ 429 - 430 364 /* Bluetooth ioctls */ 431 365 #define HCIUARTSETPROTO _IOW('U', 200, int) 432 366 #define HCIUARTGETPROTO _IOR('U', 201, int) ··· 411 479 */ 412 480 COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ 413 481 COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ 414 - /* Little m */ 415 - COMPATIBLE_IOCTL(MTIOCTOP) 416 482 #ifdef CONFIG_BLOCK 417 483 /* md calls this on random blockdevs */ 418 484 IGNORE_IOCTL(RAID_VERSION) ··· 776 846 return sg_ioctl_trans(file, cmd, argp); 777 847 case SG_GET_REQUEST_TABLE: 778 848 return sg_grt_trans(file, cmd, argp); 779 - case MTIOCGET32: 780 - case MTIOCPOS32: 781 - return mt_ioctl_trans(file, cmd, argp); 782 849 #endif 783 850 } 784 851
+60
include/linux/mtio.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_MTIO_COMPAT_H 3 + #define _LINUX_MTIO_COMPAT_H 4 + 5 + #include <linux/compat.h> 6 + #include <uapi/linux/mtio.h> 7 + #include <linux/uaccess.h> 8 + 9 + /* 10 + * helper functions for implementing compat ioctls on the four tape 11 + * drivers: we define the 32-bit layout of each incompatible structure, 12 + * plus a wrapper function to copy it to user space in either format. 13 + */ 14 + 15 + struct mtget32 { 16 + s32 mt_type; 17 + s32 mt_resid; 18 + s32 mt_dsreg; 19 + s32 mt_gstat; 20 + s32 mt_erreg; 21 + s32 mt_fileno; 22 + s32 mt_blkno; 23 + }; 24 + #define MTIOCGET32 _IOR('m', 2, struct mtget32) 25 + 26 + struct mtpos32 { 27 + s32 mt_blkno; 28 + }; 29 + #define MTIOCPOS32 _IOR('m', 3, struct mtpos32) 30 + 31 + static inline int put_user_mtget(void __user *u, struct mtget *k) 32 + { 33 + struct mtget32 k32 = { 34 + .mt_type = k->mt_type, 35 + .mt_resid = k->mt_resid, 36 + .mt_dsreg = k->mt_dsreg, 37 + .mt_gstat = k->mt_gstat, 38 + .mt_erreg = k->mt_erreg, 39 + .mt_fileno = k->mt_fileno, 40 + .mt_blkno = k->mt_blkno, 41 + }; 42 + int ret; 43 + 44 + if (in_compat_syscall()) 45 + ret = copy_to_user(u, &k32, sizeof(k32)); 46 + else 47 + ret = copy_to_user(u, k, sizeof(*k)); 48 + 49 + return ret ? -EFAULT : 0; 50 + } 51 + 52 + static inline int put_user_mtpos(void __user *u, struct mtpos *k) 53 + { 54 + if (in_compat_syscall()) 55 + return put_user(k->mt_blkno, (u32 __user *)u); 56 + else 57 + return put_user(k->mt_blkno, (long __user *)u); 58 + } 59 + 60 + #endif