Commit 1df23c6f authored by Arnd Bergmann's avatar Arnd Bergmann

compat_ioctl: move HDIO ioctl handling into drivers/ide

Most of the HDIO ioctls are only used by the obsolete drivers/ide
subsystem, these can be handled by changing ide_cmd_ioctl() to be aware
of compat mode and doing the correct transformations in place and using
it as both native and compat handlers for all drivers.

The SCSI drivers implementing the same commands are already doing
this in the drivers, so the compat_blkdev_driver_ioctl() function
is no longer needed now.

The BLKSECTSET and HDIO_GETGEO_BIG ioctls are not implemented
in any driver any more and no longer need any conversion.
Reviewed-by: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent 75c0b0e1
...@@ -78,24 +78,6 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev, ...@@ -78,24 +78,6 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
return ret; return ret;
} }
static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
unsigned long __user *p;
int error;
p = compat_alloc_user_space(sizeof(unsigned long));
error = __blkdev_driver_ioctl(bdev, mode,
cmd, (unsigned long)p);
if (error == 0) {
unsigned int __user *uvp = compat_ptr(arg);
unsigned long v;
if (get_user(v, p) || put_user(v, uvp))
error = -EFAULT;
}
return error;
}
struct compat_blkpg_ioctl_arg { struct compat_blkpg_ioctl_arg {
compat_int_t op; compat_int_t op;
compat_int_t flags; compat_int_t flags;
...@@ -129,61 +111,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -129,61 +111,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
#define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKBSZSET_32 _IOW(0x12, 113, int)
#define BLKGETSIZE64_32 _IOR(0x12, 114, int) #define BLKGETSIZE64_32 _IOR(0x12, 114, int)
static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
switch (cmd) {
case HDIO_GET_UNMASKINTR:
case HDIO_GET_MULTCOUNT:
case HDIO_GET_KEEPSETTINGS:
case HDIO_GET_32BIT:
case HDIO_GET_NOWERR:
case HDIO_GET_DMA:
case HDIO_GET_NICE:
case HDIO_GET_WCACHE:
case HDIO_GET_ACOUSTIC:
case HDIO_GET_ADDRESS:
case HDIO_GET_BUSSTATE:
return compat_hdio_ioctl(bdev, mode, cmd, arg);
/*
* No handler required for the ones below, we just need to
* convert arg to a 64 bit pointer.
*/
case BLKSECTSET:
/*
* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
* Some need translations, these do not.
*/
case HDIO_GET_IDENTITY:
case HDIO_DRIVE_TASK:
case HDIO_DRIVE_CMD:
/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
case 0x330:
arg = (unsigned long)compat_ptr(arg);
/* These intepret arg as an unsigned long, not as a pointer,
* so we must not do compat_ptr() conversion. */
case HDIO_SET_MULTCOUNT:
case HDIO_SET_UNMASKINTR:
case HDIO_SET_KEEPSETTINGS:
case HDIO_SET_32BIT:
case HDIO_SET_NOWERR:
case HDIO_SET_DMA:
case HDIO_SET_PIO_MODE:
case HDIO_SET_NICE:
case HDIO_SET_WCACHE:
case HDIO_SET_ACOUSTIC:
case HDIO_SET_BUSSTATE:
case HDIO_SET_ADDRESS:
break;
default:
/* unknown ioctl number */
return -ENOIOCTLCMD;
}
return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
}
/* Most of the generic ioctls are handled in the normal fallback path. /* Most of the generic ioctls are handled in the normal fallback path.
This assumes the blkdev's low level compat_ioctl always returns This assumes the blkdev's low level compat_ioctl always returns
ENOIOCTLCMD for unknown ioctls. */ ENOIOCTLCMD for unknown ioctls. */
...@@ -294,8 +221,6 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) ...@@ -294,8 +221,6 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
default: default:
if (disk->fops->compat_ioctl) if (disk->fops->compat_ioctl)
ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg); ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
if (ret == -ENOIOCTLCMD)
ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
return ret; return ret;
} }
} }
...@@ -1711,7 +1711,6 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -1711,7 +1711,6 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT
static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode, static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
...@@ -1728,8 +1727,12 @@ static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -1728,8 +1727,12 @@ static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
break; break;
} }
return cdrom_ioctl(&info->devinfo, bdev, mode, cmd, err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
(unsigned long)argp); if (err == -EINVAL)
err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
(unsigned long)argp);
return err;
} }
static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode, static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
...@@ -1743,7 +1746,6 @@ static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -1743,7 +1746,6 @@ static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
return ret; return ret;
} }
#endif
static unsigned int idecd_check_events(struct gendisk *disk, static unsigned int idecd_check_events(struct gendisk *disk,
unsigned int clearing) unsigned int clearing)
...@@ -1766,9 +1768,8 @@ static const struct block_device_operations idecd_ops = { ...@@ -1766,9 +1768,8 @@ static const struct block_device_operations idecd_ops = {
.open = idecd_open, .open = idecd_open,
.release = idecd_release, .release = idecd_release,
.ioctl = idecd_ioctl, .ioctl = idecd_ioctl,
#ifdef CONFIG_COMPAT .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
.compat_ioctl = idecd_compat_ioctl, idecd_compat_ioctl : NULL,
#endif
.check_events = idecd_check_events, .check_events = idecd_check_events,
.revalidate_disk = idecd_revalidate_disk .revalidate_disk = idecd_revalidate_disk
}; };
......
...@@ -794,4 +794,5 @@ const struct ide_disk_ops ide_ata_disk_ops = { ...@@ -794,4 +794,5 @@ const struct ide_disk_ops ide_ata_disk_ops = {
.set_doorlock = ide_disk_set_doorlock, .set_doorlock = ide_disk_set_doorlock,
.do_request = ide_do_rw_disk, .do_request = ide_do_rw_disk,
.ioctl = ide_disk_ioctl, .ioctl = ide_disk_ioctl,
.compat_ioctl = ide_disk_ioctl,
}; };
...@@ -329,10 +329,9 @@ int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -329,10 +329,9 @@ int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
/* if (err == -ENOTTY)
* there is no generic_ide_compat_ioctl(), that is handled err = generic_ide_ioctl(drive, bdev, cmd, arg);
* through compat_blkdev_ioctl().
*/
out: out:
mutex_unlock(&ide_floppy_ioctl_mutex); mutex_unlock(&ide_floppy_ioctl_mutex);
return err; return err;
......
...@@ -3,11 +3,20 @@ ...@@ -3,11 +3,20 @@
* IDE ioctls handling. * IDE ioctls handling.
*/ */
#include <linux/compat.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/ide.h> #include <linux/ide.h>
#include <linux/slab.h> #include <linux/slab.h>
static int put_user_long(long val, unsigned long arg)
{
if (in_compat_syscall())
return put_user(val, (compat_long_t __user *)compat_ptr(arg));
return put_user(val, (long __user *)arg);
}
static const struct ide_ioctl_devset ide_ioctl_settings[] = { static const struct ide_ioctl_devset ide_ioctl_settings[] = {
{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit }, { HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings }, { HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
...@@ -37,7 +46,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -37,7 +46,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
mutex_lock(&ide_setting_mtx); mutex_lock(&ide_setting_mtx);
err = ds->get(drive); err = ds->get(drive);
mutex_unlock(&ide_setting_mtx); mutex_unlock(&ide_setting_mtx);
return err >= 0 ? put_user(err, (long __user *)arg) : err; return err >= 0 ? put_user_long(err, arg) : err;
set_val: set_val:
if (bdev != bdev->bd_contains) if (bdev != bdev->bd_contains)
...@@ -56,7 +65,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -56,7 +65,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
EXPORT_SYMBOL_GPL(ide_setting_ioctl); EXPORT_SYMBOL_GPL(ide_setting_ioctl);
static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
unsigned long arg) void __user *argp)
{ {
u16 *id = NULL; u16 *id = NULL;
int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142; int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
...@@ -77,7 +86,7 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, ...@@ -77,7 +86,7 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
memcpy(id, drive->id, size); memcpy(id, drive->id, size);
ata_id_to_hd_driveid(id); ata_id_to_hd_driveid(id);
if (copy_to_user((void __user *)arg, id, size)) if (copy_to_user(argp, id, size))
rc = -EFAULT; rc = -EFAULT;
kfree(id); kfree(id);
...@@ -87,10 +96,10 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, ...@@ -87,10 +96,10 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg) static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
{ {
return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
<< IDE_NICE_DSC_OVERLAP) | << IDE_NICE_DSC_OVERLAP) |
(!!(drive->dev_flags & IDE_DFLAG_NICE1) (!!(drive->dev_flags & IDE_DFLAG_NICE1)
<< IDE_NICE_1), (long __user *)arg); << IDE_NICE_1), arg);
} }
static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg) static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
...@@ -115,7 +124,7 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg) ...@@ -115,7 +124,7 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
return 0; return 0;
} }
static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
{ {
u8 *buf = NULL; u8 *buf = NULL;
int bufsize = 0, err = 0; int bufsize = 0, err = 0;
...@@ -123,7 +132,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) ...@@ -123,7 +132,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
struct ide_cmd cmd; struct ide_cmd cmd;
struct ide_taskfile *tf = &cmd.tf; struct ide_taskfile *tf = &cmd.tf;
if (NULL == (void *) arg) { if (NULL == argp) {
struct request *rq; struct request *rq;
rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
...@@ -135,7 +144,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) ...@@ -135,7 +144,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
return err; return err;
} }
if (copy_from_user(args, (void __user *)arg, 4)) if (copy_from_user(args, argp, 4))
return -EFAULT; return -EFAULT;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
...@@ -181,19 +190,18 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) ...@@ -181,19 +190,18 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
args[1] = tf->error; args[1] = tf->error;
args[2] = tf->nsect; args[2] = tf->nsect;
abort: abort:
if (copy_to_user((void __user *)arg, &args, 4)) if (copy_to_user(argp, &args, 4))
err = -EFAULT; err = -EFAULT;
if (buf) { if (buf) {
if (copy_to_user((void __user *)(arg + 4), buf, bufsize)) if (copy_to_user((argp + 4), buf, bufsize))
err = -EFAULT; err = -EFAULT;
kfree(buf); kfree(buf);
} }
return err; return err;
} }
static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg) static int ide_task_ioctl(ide_drive_t *drive, void __user *p)
{ {
void __user *p = (void __user *)arg;
int err = 0; int err = 0;
u8 args[7]; u8 args[7];
struct ide_cmd cmd; struct ide_cmd cmd;
...@@ -237,6 +245,10 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -237,6 +245,10 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int err; int err;
void __user *argp = (void __user *)arg;
if (in_compat_syscall())
argp = compat_ptr(arg);
err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings); err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
if (err != -EOPNOTSUPP) if (err != -EOPNOTSUPP)
...@@ -247,7 +259,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -247,7 +259,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
case HDIO_GET_IDENTITY: case HDIO_GET_IDENTITY:
if (bdev != bdev->bd_contains) if (bdev != bdev->bd_contains)
return -EINVAL; return -EINVAL;
return ide_get_identity_ioctl(drive, cmd, arg); return ide_get_identity_ioctl(drive, cmd, argp);
case HDIO_GET_NICE: case HDIO_GET_NICE:
return ide_get_nice_ioctl(drive, arg); return ide_get_nice_ioctl(drive, arg);
case HDIO_SET_NICE: case HDIO_SET_NICE:
...@@ -258,6 +270,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -258,6 +270,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
case HDIO_DRIVE_TASKFILE: case HDIO_DRIVE_TASKFILE:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES; return -EACCES;
/* missing compat handler for HDIO_DRIVE_TASKFILE */
if (in_compat_syscall())
return -ENOTTY;
if (drive->media == ide_disk) if (drive->media == ide_disk)
return ide_taskfile_ioctl(drive, arg); return ide_taskfile_ioctl(drive, arg);
return -ENOMSG; return -ENOMSG;
...@@ -265,11 +280,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -265,11 +280,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
case HDIO_DRIVE_CMD: case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_RAWIO))
return -EACCES; return -EACCES;
return ide_cmd_ioctl(drive, arg); return ide_cmd_ioctl(drive, argp);
case HDIO_DRIVE_TASK: case HDIO_DRIVE_TASK:
if (!capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_RAWIO))
return -EACCES; return -EACCES;
return ide_task_ioctl(drive, arg); return ide_task_ioctl(drive, argp);
case HDIO_DRIVE_RESET: case HDIO_DRIVE_RESET:
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
...@@ -277,7 +292,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, ...@@ -277,7 +292,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
case HDIO_GET_BUSSTATE: case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
if (put_user(BUSSTATE_ON, (long __user *)arg)) if (put_user_long(BUSSTATE_ON, arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
case HDIO_SET_BUSSTATE: case HDIO_SET_BUSSTATE:
......
...@@ -1945,11 +1945,22 @@ static int idetape_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -1945,11 +1945,22 @@ static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
return err; return err;
} }
static int idetape_compat_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
if (cmd == 0x0340 || cmd == 0x350)
arg = (unsigned long)compat_ptr(arg);
return idetape_ioctl(bdev, mode, cmd, arg);
}
static const struct block_device_operations idetape_block_ops = { static const struct block_device_operations idetape_block_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = idetape_open, .open = idetape_open,
.release = idetape_release, .release = idetape_release,
.ioctl = idetape_ioctl, .ioctl = idetape_ioctl,
.compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
idetape_compat_ioctl : NULL,
}; };
static int ide_tape_probe(ide_drive_t *drive) static int ide_tape_probe(ide_drive_t *drive)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment