compat_ioctl.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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/fd.h>
  8. #include <linux/hdreg.h>
  9. #include <linux/syscalls.h>
  10. #include <linux/smp_lock.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_long(unsigned long arg, long val)
  22. {
  23. return put_user(val, (compat_long_t __user *)compat_ptr(arg));
  24. }
  25. static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
  26. {
  27. return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
  28. }
  29. static int compat_put_u64(unsigned long arg, u64 val)
  30. {
  31. return put_user(val, (compat_u64 __user *)compat_ptr(arg));
  32. }
  33. struct compat_hd_geometry {
  34. unsigned char heads;
  35. unsigned char sectors;
  36. unsigned short cylinders;
  37. u32 start;
  38. };
  39. static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
  40. struct compat_hd_geometry __user *ugeo)
  41. {
  42. struct hd_geometry geo;
  43. int ret;
  44. if (!ugeo)
  45. return -EINVAL;
  46. if (!disk->fops->getgeo)
  47. return -ENOTTY;
  48. /*
  49. * We need to set the startsect first, the driver may
  50. * want to override it.
  51. */
  52. geo.start = get_start_sect(bdev);
  53. ret = disk->fops->getgeo(bdev, &geo);
  54. if (ret)
  55. return ret;
  56. ret = copy_to_user(ugeo, &geo, 4);
  57. ret |= __put_user(geo.start, &ugeo->start);
  58. if (ret)
  59. ret = -EFAULT;
  60. return ret;
  61. }
  62. static int compat_hdio_ioctl(struct inode *inode, struct file *file,
  63. struct gendisk *disk, unsigned int cmd, unsigned long arg)
  64. {
  65. mm_segment_t old_fs = get_fs();
  66. unsigned long kval;
  67. unsigned int __user *uvp;
  68. int error;
  69. set_fs(KERNEL_DS);
  70. error = blkdev_driver_ioctl(inode, file, disk,
  71. cmd, (unsigned long)(&kval));
  72. set_fs(old_fs);
  73. if (error == 0) {
  74. uvp = compat_ptr(arg);
  75. if (put_user(kval, uvp))
  76. error = -EFAULT;
  77. }
  78. return error;
  79. }
  80. struct compat_blkpg_ioctl_arg {
  81. compat_int_t op;
  82. compat_int_t flags;
  83. compat_int_t datalen;
  84. compat_caddr_t data;
  85. };
  86. static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
  87. unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
  88. {
  89. struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
  90. compat_caddr_t udata;
  91. compat_int_t n;
  92. int err;
  93. err = get_user(n, &ua32->op);
  94. err |= put_user(n, &a->op);
  95. err |= get_user(n, &ua32->flags);
  96. err |= put_user(n, &a->flags);
  97. err |= get_user(n, &ua32->datalen);
  98. err |= put_user(n, &a->datalen);
  99. err |= get_user(udata, &ua32->data);
  100. err |= put_user(compat_ptr(udata), &a->data);
  101. if (err)
  102. return err;
  103. return blkdev_ioctl(inode, file, cmd, (unsigned long)a);
  104. }
  105. #define BLKBSZGET_32 _IOR(0x12, 112, int)
  106. #define BLKBSZSET_32 _IOW(0x12, 113, int)
  107. #define BLKGETSIZE64_32 _IOR(0x12, 114, int)
  108. struct compat_blk_user_trace_setup {
  109. char name[32];
  110. u16 act_mask;
  111. u32 buf_size;
  112. u32 buf_nr;
  113. compat_u64 start_lba;
  114. compat_u64 end_lba;
  115. u32 pid;
  116. };
  117. #define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
  118. static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
  119. {
  120. struct blk_user_trace_setup buts;
  121. struct compat_blk_user_trace_setup cbuts;
  122. struct request_queue *q;
  123. int ret;
  124. q = bdev_get_queue(bdev);
  125. if (!q)
  126. return -ENXIO;
  127. if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
  128. return -EFAULT;
  129. buts = (struct blk_user_trace_setup) {
  130. .act_mask = cbuts.act_mask,
  131. .buf_size = cbuts.buf_size,
  132. .buf_nr = cbuts.buf_nr,
  133. .start_lba = cbuts.start_lba,
  134. .end_lba = cbuts.end_lba,
  135. .pid = cbuts.pid,
  136. };
  137. memcpy(&buts.name, &cbuts.name, 32);
  138. mutex_lock(&bdev->bd_mutex);
  139. ret = do_blk_trace_setup(q, bdev, &buts);
  140. mutex_unlock(&bdev->bd_mutex);
  141. if (ret)
  142. return ret;
  143. if (copy_to_user(arg, &buts.name, 32))
  144. return -EFAULT;
  145. return 0;
  146. }
  147. static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
  148. struct gendisk *disk, unsigned cmd, unsigned long arg)
  149. {
  150. int ret;
  151. switch (arg) {
  152. case HDIO_GET_UNMASKINTR:
  153. case HDIO_GET_MULTCOUNT:
  154. case HDIO_GET_KEEPSETTINGS:
  155. case HDIO_GET_32BIT:
  156. case HDIO_GET_NOWERR:
  157. case HDIO_GET_DMA:
  158. case HDIO_GET_NICE:
  159. case HDIO_GET_WCACHE:
  160. case HDIO_GET_ACOUSTIC:
  161. case HDIO_GET_ADDRESS:
  162. case HDIO_GET_BUSSTATE:
  163. return compat_hdio_ioctl(inode, file, disk, cmd, arg);
  164. /*
  165. * No handler required for the ones below, we just need to
  166. * convert arg to a 64 bit pointer.
  167. */
  168. case BLKSECTSET:
  169. /*
  170. * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
  171. * Some need translations, these do not.
  172. */
  173. case HDIO_GET_IDENTITY:
  174. case HDIO_DRIVE_TASK:
  175. case HDIO_DRIVE_CMD:
  176. case HDIO_SCAN_HWIF:
  177. /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
  178. case 0x330:
  179. /* 0x02 -- Floppy ioctls */
  180. case FDMSGON:
  181. case FDMSGOFF:
  182. case FDSETEMSGTRESH:
  183. case FDFLUSH:
  184. case FDWERRORCLR:
  185. case FDSETMAXERRS:
  186. case FDGETMAXERRS:
  187. case FDGETDRVTYP:
  188. case FDEJECT:
  189. case FDCLRPRM:
  190. case FDFMTBEG:
  191. case FDFMTEND:
  192. case FDRESET:
  193. case FDTWADDLE:
  194. case FDFMTTRK:
  195. case FDRAWCMD:
  196. /* CDROM stuff */
  197. case CDROMPAUSE:
  198. case CDROMRESUME:
  199. case CDROMPLAYMSF:
  200. case CDROMPLAYTRKIND:
  201. case CDROMREADTOCHDR:
  202. case CDROMREADTOCENTRY:
  203. case CDROMSTOP:
  204. case CDROMSTART:
  205. case CDROMEJECT:
  206. case CDROMVOLCTRL:
  207. case CDROMSUBCHNL:
  208. case CDROMMULTISESSION:
  209. case CDROM_GET_MCN:
  210. case CDROMRESET:
  211. case CDROMVOLREAD:
  212. case CDROMSEEK:
  213. case CDROMPLAYBLK:
  214. case CDROMCLOSETRAY:
  215. case CDROM_DISC_STATUS:
  216. case CDROM_CHANGER_NSLOTS:
  217. case CDROM_GET_CAPABILITY:
  218. /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
  219. * not take a struct cdrom_read, instead they take a struct cdrom_msf
  220. * which is compatible.
  221. */
  222. case CDROMREADMODE2:
  223. case CDROMREADMODE1:
  224. case CDROMREADRAW:
  225. case CDROMREADCOOKED:
  226. case CDROMREADALL:
  227. /* DVD ioctls */
  228. case DVD_READ_STRUCT:
  229. case DVD_WRITE_STRUCT:
  230. case DVD_AUTH:
  231. arg = (unsigned long)compat_ptr(arg);
  232. /* These intepret arg as an unsigned long, not as a pointer,
  233. * so we must not do compat_ptr() conversion. */
  234. case HDIO_SET_MULTCOUNT:
  235. case HDIO_SET_UNMASKINTR:
  236. case HDIO_SET_KEEPSETTINGS:
  237. case HDIO_SET_32BIT:
  238. case HDIO_SET_NOWERR:
  239. case HDIO_SET_DMA:
  240. case HDIO_SET_PIO_MODE:
  241. case HDIO_SET_NICE:
  242. case HDIO_SET_WCACHE:
  243. case HDIO_SET_ACOUSTIC:
  244. case HDIO_SET_BUSSTATE:
  245. case HDIO_SET_ADDRESS:
  246. case CDROMEJECT_SW:
  247. case CDROM_SET_OPTIONS:
  248. case CDROM_CLEAR_OPTIONS:
  249. case CDROM_SELECT_SPEED:
  250. case CDROM_SELECT_DISC:
  251. case CDROM_MEDIA_CHANGED:
  252. case CDROM_DRIVE_STATUS:
  253. case CDROM_LOCKDOOR:
  254. case CDROM_DEBUG:
  255. break;
  256. default:
  257. /* unknown ioctl number */
  258. return -ENOIOCTLCMD;
  259. }
  260. if (disk->fops->unlocked_ioctl)
  261. return disk->fops->unlocked_ioctl(file, cmd, arg);
  262. if (disk->fops->ioctl) {
  263. lock_kernel();
  264. ret = disk->fops->ioctl(inode, file, cmd, arg);
  265. unlock_kernel();
  266. return ret;
  267. }
  268. return -ENOTTY;
  269. }
  270. static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
  271. struct block_device *bdev,
  272. unsigned cmd, unsigned long arg)
  273. {
  274. struct backing_dev_info *bdi;
  275. switch (cmd) {
  276. case BLKRAGET:
  277. case BLKFRAGET:
  278. if (!arg)
  279. return -EINVAL;
  280. bdi = blk_get_backing_dev_info(bdev);
  281. if (bdi == NULL)
  282. return -ENOTTY;
  283. return compat_put_long(arg,
  284. (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
  285. case BLKROGET: /* compatible */
  286. return compat_put_int(arg, bdev_read_only(bdev) != 0);
  287. case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
  288. return compat_put_int(arg, block_size(bdev));
  289. case BLKSSZGET: /* get block device hardware sector size */
  290. return compat_put_int(arg, bdev_hardsect_size(bdev));
  291. case BLKSECTGET:
  292. return compat_put_ushort(arg,
  293. bdev_get_queue(bdev)->max_sectors);
  294. case BLKRASET: /* compatible, but no compat_ptr (!) */
  295. case BLKFRASET:
  296. if (!capable(CAP_SYS_ADMIN))
  297. return -EACCES;
  298. bdi = blk_get_backing_dev_info(bdev);
  299. if (bdi == NULL)
  300. return -ENOTTY;
  301. bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
  302. return 0;
  303. case BLKGETSIZE:
  304. if ((bdev->bd_inode->i_size >> 9) > ~0UL)
  305. return -EFBIG;
  306. return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
  307. case BLKGETSIZE64_32:
  308. return compat_put_u64(arg, bdev->bd_inode->i_size);
  309. case BLKTRACESETUP32:
  310. return compat_blk_trace_setup(bdev, compat_ptr(arg));
  311. case BLKTRACESTART: /* compatible */
  312. case BLKTRACESTOP: /* compatible */
  313. case BLKTRACETEARDOWN: /* compatible */
  314. return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
  315. }
  316. return -ENOIOCTLCMD;
  317. }
  318. /* Most of the generic ioctls are handled in the normal fallback path.
  319. This assumes the blkdev's low level compat_ioctl always returns
  320. ENOIOCTLCMD for unknown ioctls. */
  321. long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
  322. {
  323. int ret = -ENOIOCTLCMD;
  324. struct inode *inode = file->f_mapping->host;
  325. struct block_device *bdev = inode->i_bdev;
  326. struct gendisk *disk = bdev->bd_disk;
  327. switch (cmd) {
  328. case HDIO_GETGEO:
  329. return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
  330. case BLKFLSBUF:
  331. case BLKROSET:
  332. /*
  333. * the ones below are implemented in blkdev_locked_ioctl,
  334. * but we call blkdev_ioctl, which gets the lock for us
  335. */
  336. case BLKRRPART:
  337. return blkdev_ioctl(inode, file, cmd,
  338. (unsigned long)compat_ptr(arg));
  339. case BLKBSZSET_32:
  340. return blkdev_ioctl(inode, file, BLKBSZSET,
  341. (unsigned long)compat_ptr(arg));
  342. case BLKPG:
  343. return compat_blkpg_ioctl(inode, file, cmd, compat_ptr(arg));
  344. }
  345. lock_kernel();
  346. ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
  347. /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
  348. if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
  349. ret = disk->fops->compat_ioctl(file, cmd, arg);
  350. unlock_kernel();
  351. if (ret != -ENOIOCTLCMD)
  352. return ret;
  353. return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
  354. }