compat_ioctl.c 11 KB

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