1 // SPDX-License-Identifier: GPL-2.0
3 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
7 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
10 * These routines maintain argument size conversion between 32bit and 64bit
14 #include <linux/types.h>
15 #include <linux/compat.h>
16 #include <linux/kernel.h>
17 #include <linux/capability.h>
18 #include <linux/compiler.h>
19 #include <linux/sched.h>
20 #include <linux/smp.h>
21 #include <linux/ioctl.h>
23 #include <linux/raid/md_u.h>
24 #include <linux/falloc.h>
25 #include <linux/file.h>
26 #include <linux/ppp-ioctl.h>
27 #include <linux/if_pppox.h>
28 #include <linux/tty.h>
29 #include <linux/vt_kern.h>
30 #include <linux/blkdev.h>
31 #include <linux/serial.h>
32 #include <linux/ctype.h>
33 #include <linux/syscalls.h>
34 #include <linux/gfp.h>
35 #include <linux/cec.h>
40 #include <linux/cdrom.h>
42 #include <scsi/scsi.h>
43 #include <scsi/scsi_ioctl.h>
47 #include <linux/uaccess.h>
48 #include <linux/watchdog.h>
50 #include <linux/hiddev.h>
53 #include <linux/sort.h>
56 * simple reversible transform to make our table more evenly
57 * distributed after sorting.
59 #define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
61 #define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
62 static unsigned int ioctl_pointer[] = {
65 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
66 COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
67 COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
68 COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
69 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
70 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
71 COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
72 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
76 COMPATIBLE_IOCTL(SG_IO)
77 COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
78 COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
79 COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
80 COMPATIBLE_IOCTL(SG_EMULATED_HOST)
81 COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
82 COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
83 COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
84 COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
85 COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
86 COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
87 COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
88 COMPATIBLE_IOCTL(SG_GET_PACK_ID)
89 COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
90 COMPATIBLE_IOCTL(SG_SET_DEBUG)
91 COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
92 COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
93 COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
94 COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
95 COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
96 COMPATIBLE_IOCTL(SG_SCSI_RESET)
97 COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
98 COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
99 COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
104 * Convert common ioctl arguments based on their command number
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.
110 static long do_ioctl_trans(unsigned int cmd,
111 unsigned long arg, struct file *file)
116 static int compat_ioctl_check_table(unsigned int xcmd)
120 const int max = ARRAY_SIZE(ioctl_pointer) - 1;
122 BUILD_BUG_ON(max >= (1 << 16));
124 /* guess initial offset into table, assuming a
125 normalized distribution */
126 i = ((xcmd >> 16) * max) >> 16;
128 /* do linear search up first, until greater or equal */
129 while (ioctl_pointer[i] < xcmd && i < max)
132 /* then do linear search down */
133 while (ioctl_pointer[i] > xcmd && i > 0)
136 return ioctl_pointer[i] == xcmd;
142 COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
143 compat_ulong_t, arg32)
145 unsigned long arg = arg32;
146 struct fd f = fdget(fd);
151 /* RED-PEN how should LSM module know it's handling 32bit? */
152 error = security_file_ioctl(f.file, cmd, arg);
157 /* these are never seen by ->ioctl(), no argument or int argument */
164 /* these are never seen by ->ioctl(), pointer argument */
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.
182 /* pointer argument, never actually handled by ->ioctl() */
185 /* handled by some ->ioctl(); always a pointer to int */
188 /* these get messy on amd64 due to alignment differences */
189 #if defined(CONFIG_X86_64)
190 case FS_IOC_RESVSP_32:
191 case FS_IOC_RESVSP64_32:
192 error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
194 case FS_IOC_UNRESVSP_32:
195 case FS_IOC_UNRESVSP64_32:
196 error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
199 case FS_IOC_ZERO_RANGE_32:
200 error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
205 case FS_IOC_RESVSP64:
206 case FS_IOC_UNRESVSP:
207 case FS_IOC_UNRESVSP64:
208 case FS_IOC_ZERO_RANGE:
213 if (f.file->f_op->compat_ioctl) {
214 error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
215 if (error != -ENOIOCTLCMD)
219 if (!f.file->f_op->unlocked_ioctl)
224 if (compat_ioctl_check_table(XFORM(cmd)))
227 error = do_ioctl_trans(cmd, arg, f.file);
228 if (error == -ENOIOCTLCMD)
234 arg = (unsigned long)compat_ptr(arg);
236 error = do_vfs_ioctl(f.file, fd, cmd, arg);
243 static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
246 a = *(unsigned int *)p;
247 b = *(unsigned int *)q;
255 static int __init init_sys32_ioctl(void)
257 sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
258 init_sys32_ioctl_cmp, NULL);
261 __initcall(init_sys32_ioctl);