compat_ioctl.c 11 KB

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