Linux Audio

Check our new training course

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