blob: 358ea2ecf36b2abfc300a94c9488755390d16d7d [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
4 *
5 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
6 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
7 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
Pavel Macheka2531292010-07-18 14:27:13 +02008 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * These routines maintain argument size conversion between 32bit and 64bit
11 * ioctls.
12 */
13
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/types.h>
15#include <linux/compat.h>
16#include <linux/kernel.h>
Randy Dunlap16f7e0f2006-01-11 12:17:46 -080017#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/compiler.h>
19#include <linux/sched.h>
20#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/ioctl.h>
22#include <linux/if.h>
NeilBrownbff61972009-03-31 14:33:13 +110023#include <linux/raid/md_u.h>
Ankit Jain3e63cbb2009-06-19 14:28:07 -040024#include <linux/falloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/file.h>
Paul Mackerras4b32da2b2012-03-04 12:56:55 +000026#include <linux/ppp-ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/if_pppox.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/tty.h>
29#include <linux/vt_kern.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/blkdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/syscalls.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/gfp.h>
Hans Verkuil594edf32015-11-11 08:26:12 -020035#include <linux/cec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Al Viro66cf1912016-01-07 09:53:30 -050037#include "internal.h"
38
Randy Dunlap3c3622d2008-07-16 08:52:00 -050039#ifdef CONFIG_BLOCK
Johannes Stezenbach390192b2011-07-01 22:32:26 +020040#include <linux/cdrom.h>
41#include <linux/fd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <scsi/scsi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <scsi/scsi_ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <scsi/sg.h>
Randy Dunlap3c3622d2008-07-16 08:52:00 -050045#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080047#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/watchdog.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/hiddev.h>
51
David S. Miller6e87abd2005-11-16 00:52:57 -080052
Arnd Bergmann661f6272009-11-05 19:52:55 +010053#include <linux/sort.h>
54
Arnd Bergmann661f6272009-11-05 19:52:55 +010055/*
56 * simple reversible transform to make our table more evenly
57 * distributed after sorting.
58 */
59#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
Christoph Hellwig6272e262007-05-08 00:29:21 -070060
Mark Charlebois9280cdd2017-04-28 15:15:12 -070061#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
Arnd Bergmann661f6272009-11-05 19:52:55 +010062static unsigned int ioctl_pointer[] = {
Randy Dunlap3c3622d2008-07-16 08:52:00 -050063#ifdef CONFIG_BLOCK
Christoph Hellwig644fd4f2007-05-08 00:29:07 -070064/* Big S */
65COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
66COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
67COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
68COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
69COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
70COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
71COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
72COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
Randy Dunlap3c3622d2008-07-16 08:52:00 -050073#endif
Randy Dunlap3c3622d2008-07-16 08:52:00 -050074#ifdef CONFIG_BLOCK
Christoph Hellwig644fd4f2007-05-08 00:29:07 -070075/* SG stuff */
Arnd Bergmann98aaaec2019-03-14 17:45:18 +010076COMPATIBLE_IOCTL(SG_IO)
Arnd Bergmannfd6c3d52018-08-24 14:53:13 +020077COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
Christoph Hellwig644fd4f2007-05-08 00:29:07 -070078COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
79COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
80COMPATIBLE_IOCTL(SG_EMULATED_HOST)
Christoph Hellwig644fd4f2007-05-08 00:29:07 -070081COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
82COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
83COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
84COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
85COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
86COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
87COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
88COMPATIBLE_IOCTL(SG_GET_PACK_ID)
89COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
90COMPATIBLE_IOCTL(SG_SET_DEBUG)
91COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
92COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
93COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
94COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
95COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
96COMPATIBLE_IOCTL(SG_SCSI_RESET)
97COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
98COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
99COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
Randy Dunlap3c3622d2008-07-16 08:52:00 -0500100#endif
Christoph Hellwige6a6d2e2006-01-09 20:52:14 -0800101};
David S. Miller6e87abd2005-11-16 00:52:57 -0800102
Arnd Bergmann5a07ea02009-05-21 22:04:16 +0000103/*
104 * Convert common ioctl arguments based on their command number
105 *
106 * Please do not add any code in here. Instead, implement
107 * a compat_ioctl operation in the place that handleѕ the
108 * ioctl for the native case.
109 */
Al Viro66cf1912016-01-07 09:53:30 -0500110static long do_ioctl_trans(unsigned int cmd,
Arnd Bergmann5a07ea02009-05-21 22:04:16 +0000111 unsigned long arg, struct file *file)
112{
Arnd Bergmann5a07ea02009-05-21 22:04:16 +0000113 return -ENOIOCTLCMD;
114}
115
Arnd Bergmann661f6272009-11-05 19:52:55 +0100116static int compat_ioctl_check_table(unsigned int xcmd)
117{
Arnd Bergmann8f5d9f22019-07-26 15:21:39 +0200118#ifdef CONFIG_BLOCK
Arnd Bergmann661f6272009-11-05 19:52:55 +0100119 int i;
120 const int max = ARRAY_SIZE(ioctl_pointer) - 1;
121
122 BUILD_BUG_ON(max >= (1 << 16));
123
124 /* guess initial offset into table, assuming a
125 normalized distribution */
126 i = ((xcmd >> 16) * max) >> 16;
127
128 /* do linear search up first, until greater or equal */
129 while (ioctl_pointer[i] < xcmd && i < max)
130 i++;
131
132 /* then do linear search down */
133 while (ioctl_pointer[i] > xcmd && i > 0)
134 i--;
135
136 return ioctl_pointer[i] == xcmd;
Arnd Bergmann8f5d9f22019-07-26 15:21:39 +0200137#else
138 return 0;
139#endif
Arnd Bergmann661f6272009-11-05 19:52:55 +0100140}
141
Heiko Carstens932602e2014-03-04 16:07:52 +0100142COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
143 compat_ulong_t, arg32)
Christoph Hellwig6272e262007-05-08 00:29:21 -0700144{
Heiko Carstens932602e2014-03-04 16:07:52 +0100145 unsigned long arg = arg32;
Al Viro2903ff02012-08-28 12:52:22 -0400146 struct fd f = fdget(fd);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700147 int error = -EBADF;
Al Viro2903ff02012-08-28 12:52:22 -0400148 if (!f.file)
Christoph Hellwig6272e262007-05-08 00:29:21 -0700149 goto out;
150
151 /* RED-PEN how should LSM module know it's handling 32bit? */
Al Viro2903ff02012-08-28 12:52:22 -0400152 error = security_file_ioctl(f.file, cmd, arg);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700153 if (error)
154 goto out_fput;
155
Christoph Hellwig6272e262007-05-08 00:29:21 -0700156 switch (cmd) {
Al Viro37ecf8b2019-04-21 20:43:10 -0400157 /* these are never seen by ->ioctl(), no argument or int argument */
Christoph Hellwig6272e262007-05-08 00:29:21 -0700158 case FIOCLEX:
159 case FIONCLEX:
Al Viro37ecf8b2019-04-21 20:43:10 -0400160 case FIFREEZE:
161 case FITHAW:
162 case FICLONE:
163 goto do_ioctl;
164 /* these are never seen by ->ioctl(), pointer argument */
Christoph Hellwig6272e262007-05-08 00:29:21 -0700165 case FIONBIO:
166 case FIOASYNC:
167 case FIOQSIZE:
Al Viro37ecf8b2019-04-21 20:43:10 -0400168 case FS_IOC_FIEMAP:
169 case FIGETBSZ:
170 case FICLONERANGE:
171 case FIDEDUPERANGE:
172 goto found_handler;
173 /*
174 * The next group is the stuff handled inside file_ioctl().
175 * For regular files these never reach ->ioctl(); for
176 * devices, sockets, etc. they do and one (FIONREAD) is
177 * even accepted in some cases. In all those cases
178 * argument has the same type, so we can handle these
179 * here, shunting them towards do_vfs_ioctl().
180 * ->compat_ioctl() will never see any of those.
181 */
182 /* pointer argument, never actually handled by ->ioctl() */
183 case FIBMAP:
184 goto found_handler;
185 /* handled by some ->ioctl(); always a pointer to int */
186 case FIONREAD:
187 goto found_handler;
Linus Torvalds97eeb4d2019-12-02 14:46:22 -0800188 /* these get messy on amd64 due to alignment differences */
Al Virobf0a1992019-04-21 19:10:09 -0400189#if defined(CONFIG_X86_64)
Ankit Jain3e63cbb2009-06-19 14:28:07 -0400190 case FS_IOC_RESVSP_32:
191 case FS_IOC_RESVSP64_32:
Christoph Hellwig837a6e72019-10-24 22:26:02 -0700192 error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
193 goto out_fput;
194 case FS_IOC_UNRESVSP_32:
195 case FS_IOC_UNRESVSP64_32:
196 error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
197 compat_ptr(arg));
198 goto out_fput;
199 case FS_IOC_ZERO_RANGE_32:
200 error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
201 compat_ptr(arg));
Ankit Jain3e63cbb2009-06-19 14:28:07 -0400202 goto out_fput;
203#else
204 case FS_IOC_RESVSP:
205 case FS_IOC_RESVSP64:
Christoph Hellwig837a6e72019-10-24 22:26:02 -0700206 case FS_IOC_UNRESVSP:
207 case FS_IOC_UNRESVSP64:
Christoph Hellwig837a6e72019-10-24 22:26:02 -0700208 case FS_IOC_ZERO_RANGE:
Al Viro6b2daec2019-04-21 18:53:50 -0400209 goto found_handler;
Al Viro37ecf8b2019-04-21 20:43:10 -0400210#endif
Christoph Hellwig6272e262007-05-08 00:29:21 -0700211
212 default:
Al Viro72c2d532013-09-22 16:27:52 -0400213 if (f.file->f_op->compat_ioctl) {
Al Viro2903ff02012-08-28 12:52:22 -0400214 error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700215 if (error != -ENOIOCTLCMD)
216 goto out_fput;
217 }
218
Al Viro72c2d532013-09-22 16:27:52 -0400219 if (!f.file->f_op->unlocked_ioctl)
Christoph Hellwig6272e262007-05-08 00:29:21 -0700220 goto do_ioctl;
221 break;
222 }
223
Arnd Bergmann661f6272009-11-05 19:52:55 +0100224 if (compat_ioctl_check_table(XFORM(cmd)))
225 goto found_handler;
Christoph Hellwig6272e262007-05-08 00:29:21 -0700226
Al Viro66cf1912016-01-07 09:53:30 -0500227 error = do_ioctl_trans(cmd, arg, f.file);
Linus Torvalds07d106d2012-01-05 15:40:12 -0800228 if (error == -ENOIOCTLCMD)
229 error = -ENOTTY;
Christoph Hellwig6272e262007-05-08 00:29:21 -0700230
231 goto out_fput;
232
233 found_handler:
Arnd Bergmann789f0f82009-11-05 19:13:51 +0100234 arg = (unsigned long)compat_ptr(arg);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700235 do_ioctl:
Al Viro2903ff02012-08-28 12:52:22 -0400236 error = do_vfs_ioctl(f.file, fd, cmd, arg);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700237 out_fput:
Al Viro2903ff02012-08-28 12:52:22 -0400238 fdput(f);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700239 out:
240 return error;
241}
242
Arnd Bergmann661f6272009-11-05 19:52:55 +0100243static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
Christoph Hellwig6272e262007-05-08 00:29:21 -0700244{
Arnd Bergmann661f6272009-11-05 19:52:55 +0100245 unsigned int a, b;
246 a = *(unsigned int *)p;
247 b = *(unsigned int *)q;
248 if (a > b)
249 return 1;
250 if (a < b)
251 return -1;
252 return 0;
Christoph Hellwig6272e262007-05-08 00:29:21 -0700253}
254
255static int __init init_sys32_ioctl(void)
256{
Arnd Bergmann661f6272009-11-05 19:52:55 +0100257 sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
258 init_sys32_ioctl_cmp, NULL);
Christoph Hellwig6272e262007-05-08 00:29:21 -0700259 return 0;
260}
261__initcall(init_sys32_ioctl);