root/block/compat_ioctl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. compat_put_ushort
  2. compat_put_int
  3. compat_put_uint
  4. compat_put_long
  5. compat_put_ulong
  6. compat_put_u64
  7. compat_hdio_getgeo
  8. compat_hdio_ioctl
  9. compat_cdrom_read_audio
  10. compat_cdrom_generic_command
  11. compat_blkpg_ioctl
  12. compat_blkdev_driver_ioctl
  13. compat_blkdev_ioctl

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/blkdev.h>
   3 #include <linux/blkpg.h>
   4 #include <linux/blktrace_api.h>
   5 #include <linux/cdrom.h>
   6 #include <linux/compat.h>
   7 #include <linux/elevator.h>
   8 #include <linux/hdreg.h>
   9 #include <linux/pr.h>
  10 #include <linux/slab.h>
  11 #include <linux/syscalls.h>
  12 #include <linux/types.h>
  13 #include <linux/uaccess.h>
  14 
  15 static int compat_put_ushort(unsigned long arg, unsigned short val)
  16 {
  17         return put_user(val, (unsigned short __user *)compat_ptr(arg));
  18 }
  19 
  20 static int compat_put_int(unsigned long arg, int val)
  21 {
  22         return put_user(val, (compat_int_t __user *)compat_ptr(arg));
  23 }
  24 
  25 static int compat_put_uint(unsigned long arg, unsigned int val)
  26 {
  27         return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
  28 }
  29 
  30 static int compat_put_long(unsigned long arg, long val)
  31 {
  32         return put_user(val, (compat_long_t __user *)compat_ptr(arg));
  33 }
  34 
  35 static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
  36 {
  37         return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
  38 }
  39 
  40 static int compat_put_u64(unsigned long arg, u64 val)
  41 {
  42         return put_user(val, (compat_u64 __user *)compat_ptr(arg));
  43 }
  44 
  45 struct compat_hd_geometry {
  46         unsigned char heads;
  47         unsigned char sectors;
  48         unsigned short cylinders;
  49         u32 start;
  50 };
  51 
  52 static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
  53                         struct compat_hd_geometry __user *ugeo)
  54 {
  55         struct hd_geometry geo;
  56         int ret;
  57 
  58         if (!ugeo)
  59                 return -EINVAL;
  60         if (!disk->fops->getgeo)
  61                 return -ENOTTY;
  62 
  63         memset(&geo, 0, sizeof(geo));
  64         /*
  65          * We need to set the startsect first, the driver may
  66          * want to override it.
  67          */
  68         geo.start = get_start_sect(bdev);
  69         ret = disk->fops->getgeo(bdev, &geo);
  70         if (ret)
  71                 return ret;
  72 
  73         ret = copy_to_user(ugeo, &geo, 4);
  74         ret |= put_user(geo.start, &ugeo->start);
  75         if (ret)
  76                 ret = -EFAULT;
  77 
  78         return ret;
  79 }
  80 
  81 static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
  82                 unsigned int cmd, unsigned long arg)
  83 {
  84         unsigned long __user *p;
  85         int error;
  86 
  87         p = compat_alloc_user_space(sizeof(unsigned long));
  88         error = __blkdev_driver_ioctl(bdev, mode,
  89                                 cmd, (unsigned long)p);
  90         if (error == 0) {
  91                 unsigned int __user *uvp = compat_ptr(arg);
  92                 unsigned long v;
  93                 if (get_user(v, p) || put_user(v, uvp))
  94                         error = -EFAULT;
  95         }
  96         return error;
  97 }
  98 
  99 struct compat_cdrom_read_audio {
 100         union cdrom_addr        addr;
 101         u8                      addr_format;
 102         compat_int_t            nframes;
 103         compat_caddr_t          buf;
 104 };
 105 
 106 struct compat_cdrom_generic_command {
 107         unsigned char   cmd[CDROM_PACKET_SIZE];
 108         compat_caddr_t  buffer;
 109         compat_uint_t   buflen;
 110         compat_int_t    stat;
 111         compat_caddr_t  sense;
 112         unsigned char   data_direction;
 113         compat_int_t    quiet;
 114         compat_int_t    timeout;
 115         compat_caddr_t  reserved[1];
 116 };
 117 
 118 static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
 119                 unsigned int cmd, unsigned long arg)
 120 {
 121         struct cdrom_read_audio __user *cdread_audio;
 122         struct compat_cdrom_read_audio __user *cdread_audio32;
 123         __u32 data;
 124         void __user *datap;
 125 
 126         cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
 127         cdread_audio32 = compat_ptr(arg);
 128 
 129         if (copy_in_user(&cdread_audio->addr,
 130                          &cdread_audio32->addr,
 131                          (sizeof(*cdread_audio32) -
 132                           sizeof(compat_caddr_t))))
 133                 return -EFAULT;
 134 
 135         if (get_user(data, &cdread_audio32->buf))
 136                 return -EFAULT;
 137         datap = compat_ptr(data);
 138         if (put_user(datap, &cdread_audio->buf))
 139                 return -EFAULT;
 140 
 141         return __blkdev_driver_ioctl(bdev, mode, cmd,
 142                         (unsigned long)cdread_audio);
 143 }
 144 
 145 static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
 146                 unsigned int cmd, unsigned long arg)
 147 {
 148         struct cdrom_generic_command __user *cgc;
 149         struct compat_cdrom_generic_command __user *cgc32;
 150         u32 data;
 151         unsigned char dir;
 152         int itmp;
 153 
 154         cgc = compat_alloc_user_space(sizeof(*cgc));
 155         cgc32 = compat_ptr(arg);
 156 
 157         if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
 158             get_user(data, &cgc32->buffer) ||
 159             put_user(compat_ptr(data), &cgc->buffer) ||
 160             copy_in_user(&cgc->buflen, &cgc32->buflen,
 161                          (sizeof(unsigned int) + sizeof(int))) ||
 162             get_user(data, &cgc32->sense) ||
 163             put_user(compat_ptr(data), &cgc->sense) ||
 164             get_user(dir, &cgc32->data_direction) ||
 165             put_user(dir, &cgc->data_direction) ||
 166             get_user(itmp, &cgc32->quiet) ||
 167             put_user(itmp, &cgc->quiet) ||
 168             get_user(itmp, &cgc32->timeout) ||
 169             put_user(itmp, &cgc->timeout) ||
 170             get_user(data, &cgc32->reserved[0]) ||
 171             put_user(compat_ptr(data), &cgc->reserved[0]))
 172                 return -EFAULT;
 173 
 174         return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
 175 }
 176 
 177 struct compat_blkpg_ioctl_arg {
 178         compat_int_t op;
 179         compat_int_t flags;
 180         compat_int_t datalen;
 181         compat_caddr_t data;
 182 };
 183 
 184 static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
 185                 unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
 186 {
 187         struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
 188         compat_caddr_t udata;
 189         compat_int_t n;
 190         int err;
 191 
 192         err = get_user(n, &ua32->op);
 193         err |= put_user(n, &a->op);
 194         err |= get_user(n, &ua32->flags);
 195         err |= put_user(n, &a->flags);
 196         err |= get_user(n, &ua32->datalen);
 197         err |= put_user(n, &a->datalen);
 198         err |= get_user(udata, &ua32->data);
 199         err |= put_user(compat_ptr(udata), &a->data);
 200         if (err)
 201                 return err;
 202 
 203         return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
 204 }
 205 
 206 #define BLKBSZGET_32            _IOR(0x12, 112, int)
 207 #define BLKBSZSET_32            _IOW(0x12, 113, int)
 208 #define BLKGETSIZE64_32         _IOR(0x12, 114, int)
 209 
 210 static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
 211                         unsigned cmd, unsigned long arg)
 212 {
 213         switch (cmd) {
 214         case HDIO_GET_UNMASKINTR:
 215         case HDIO_GET_MULTCOUNT:
 216         case HDIO_GET_KEEPSETTINGS:
 217         case HDIO_GET_32BIT:
 218         case HDIO_GET_NOWERR:
 219         case HDIO_GET_DMA:
 220         case HDIO_GET_NICE:
 221         case HDIO_GET_WCACHE:
 222         case HDIO_GET_ACOUSTIC:
 223         case HDIO_GET_ADDRESS:
 224         case HDIO_GET_BUSSTATE:
 225                 return compat_hdio_ioctl(bdev, mode, cmd, arg);
 226         case CDROMREADAUDIO:
 227                 return compat_cdrom_read_audio(bdev, mode, cmd, arg);
 228         case CDROM_SEND_PACKET:
 229                 return compat_cdrom_generic_command(bdev, mode, cmd, arg);
 230 
 231         /*
 232          * No handler required for the ones below, we just need to
 233          * convert arg to a 64 bit pointer.
 234          */
 235         case BLKSECTSET:
 236         /*
 237          * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
 238          *         Some need translations, these do not.
 239          */
 240         case HDIO_GET_IDENTITY:
 241         case HDIO_DRIVE_TASK:
 242         case HDIO_DRIVE_CMD:
 243         /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
 244         case 0x330:
 245         /* CDROM stuff */
 246         case CDROMPAUSE:
 247         case CDROMRESUME:
 248         case CDROMPLAYMSF:
 249         case CDROMPLAYTRKIND:
 250         case CDROMREADTOCHDR:
 251         case CDROMREADTOCENTRY:
 252         case CDROMSTOP:
 253         case CDROMSTART:
 254         case CDROMEJECT:
 255         case CDROMVOLCTRL:
 256         case CDROMSUBCHNL:
 257         case CDROMMULTISESSION:
 258         case CDROM_GET_MCN:
 259         case CDROMRESET:
 260         case CDROMVOLREAD:
 261         case CDROMSEEK:
 262         case CDROMPLAYBLK:
 263         case CDROMCLOSETRAY:
 264         case CDROM_DISC_STATUS:
 265         case CDROM_CHANGER_NSLOTS:
 266         case CDROM_GET_CAPABILITY:
 267         /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
 268          * not take a struct cdrom_read, instead they take a struct cdrom_msf
 269          * which is compatible.
 270          */
 271         case CDROMREADMODE2:
 272         case CDROMREADMODE1:
 273         case CDROMREADRAW:
 274         case CDROMREADCOOKED:
 275         case CDROMREADALL:
 276         /* DVD ioctls */
 277         case DVD_READ_STRUCT:
 278         case DVD_WRITE_STRUCT:
 279         case DVD_AUTH:
 280                 arg = (unsigned long)compat_ptr(arg);
 281         /* These intepret arg as an unsigned long, not as a pointer,
 282          * so we must not do compat_ptr() conversion. */
 283         case HDIO_SET_MULTCOUNT:
 284         case HDIO_SET_UNMASKINTR:
 285         case HDIO_SET_KEEPSETTINGS:
 286         case HDIO_SET_32BIT:
 287         case HDIO_SET_NOWERR:
 288         case HDIO_SET_DMA:
 289         case HDIO_SET_PIO_MODE:
 290         case HDIO_SET_NICE:
 291         case HDIO_SET_WCACHE:
 292         case HDIO_SET_ACOUSTIC:
 293         case HDIO_SET_BUSSTATE:
 294         case HDIO_SET_ADDRESS:
 295         case CDROMEJECT_SW:
 296         case CDROM_SET_OPTIONS:
 297         case CDROM_CLEAR_OPTIONS:
 298         case CDROM_SELECT_SPEED:
 299         case CDROM_SELECT_DISC:
 300         case CDROM_MEDIA_CHANGED:
 301         case CDROM_DRIVE_STATUS:
 302         case CDROM_LOCKDOOR:
 303         case CDROM_DEBUG:
 304                 break;
 305         default:
 306                 /* unknown ioctl number */
 307                 return -ENOIOCTLCMD;
 308         }
 309 
 310         return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 311 }
 312 
 313 /* Most of the generic ioctls are handled in the normal fallback path.
 314    This assumes the blkdev's low level compat_ioctl always returns
 315    ENOIOCTLCMD for unknown ioctls. */
 316 long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 317 {
 318         int ret = -ENOIOCTLCMD;
 319         struct inode *inode = file->f_mapping->host;
 320         struct block_device *bdev = inode->i_bdev;
 321         struct gendisk *disk = bdev->bd_disk;
 322         fmode_t mode = file->f_mode;
 323         loff_t size;
 324         unsigned int max_sectors;
 325 
 326         /*
 327          * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
 328          * to updated it before every ioctl.
 329          */
 330         if (file->f_flags & O_NDELAY)
 331                 mode |= FMODE_NDELAY;
 332         else
 333                 mode &= ~FMODE_NDELAY;
 334 
 335         switch (cmd) {
 336         case HDIO_GETGEO:
 337                 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
 338         case BLKPBSZGET:
 339                 return compat_put_uint(arg, bdev_physical_block_size(bdev));
 340         case BLKIOMIN:
 341                 return compat_put_uint(arg, bdev_io_min(bdev));
 342         case BLKIOOPT:
 343                 return compat_put_uint(arg, bdev_io_opt(bdev));
 344         case BLKALIGNOFF:
 345                 return compat_put_int(arg, bdev_alignment_offset(bdev));
 346         case BLKDISCARDZEROES:
 347                 return compat_put_uint(arg, 0);
 348         case BLKFLSBUF:
 349         case BLKROSET:
 350         case BLKDISCARD:
 351         case BLKSECDISCARD:
 352         case BLKZEROOUT:
 353         /*
 354          * the ones below are implemented in blkdev_locked_ioctl,
 355          * but we call blkdev_ioctl, which gets the lock for us
 356          */
 357         case BLKRRPART:
 358         case BLKREPORTZONE:
 359         case BLKRESETZONE:
 360         case BLKGETZONESZ:
 361         case BLKGETNRZONES:
 362                 return blkdev_ioctl(bdev, mode, cmd,
 363                                 (unsigned long)compat_ptr(arg));
 364         case BLKBSZSET_32:
 365                 return blkdev_ioctl(bdev, mode, BLKBSZSET,
 366                                 (unsigned long)compat_ptr(arg));
 367         case BLKPG:
 368                 return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
 369         case BLKRAGET:
 370         case BLKFRAGET:
 371                 if (!arg)
 372                         return -EINVAL;
 373                 return compat_put_long(arg,
 374                                (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
 375         case BLKROGET: /* compatible */
 376                 return compat_put_int(arg, bdev_read_only(bdev) != 0);
 377         case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
 378                 return compat_put_int(arg, block_size(bdev));
 379         case BLKSSZGET: /* get block device hardware sector size */
 380                 return compat_put_int(arg, bdev_logical_block_size(bdev));
 381         case BLKSECTGET:
 382                 max_sectors = min_t(unsigned int, USHRT_MAX,
 383                                     queue_max_sectors(bdev_get_queue(bdev)));
 384                 return compat_put_ushort(arg, max_sectors);
 385         case BLKROTATIONAL:
 386                 return compat_put_ushort(arg,
 387                                          !blk_queue_nonrot(bdev_get_queue(bdev)));
 388         case BLKRASET: /* compatible, but no compat_ptr (!) */
 389         case BLKFRASET:
 390                 if (!capable(CAP_SYS_ADMIN))
 391                         return -EACCES;
 392                 bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
 393                 return 0;
 394         case BLKGETSIZE:
 395                 size = i_size_read(bdev->bd_inode);
 396                 if ((size >> 9) > ~0UL)
 397                         return -EFBIG;
 398                 return compat_put_ulong(arg, size >> 9);
 399 
 400         case BLKGETSIZE64_32:
 401                 return compat_put_u64(arg, i_size_read(bdev->bd_inode));
 402 
 403         case BLKTRACESETUP32:
 404         case BLKTRACESTART: /* compatible */
 405         case BLKTRACESTOP:  /* compatible */
 406         case BLKTRACETEARDOWN: /* compatible */
 407                 ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
 408                 return ret;
 409         case IOC_PR_REGISTER:
 410         case IOC_PR_RESERVE:
 411         case IOC_PR_RELEASE:
 412         case IOC_PR_PREEMPT:
 413         case IOC_PR_PREEMPT_ABORT:
 414         case IOC_PR_CLEAR:
 415                 return blkdev_ioctl(bdev, mode, cmd,
 416                                 (unsigned long)compat_ptr(arg));
 417         default:
 418                 if (disk->fops->compat_ioctl)
 419                         ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
 420                 if (ret == -ENOIOCTLCMD)
 421                         ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
 422                 return ret;
 423         }
 424 }

/* [<][>][^][v][top][bottom][index][help] */