Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | /* |
| 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 Machek | a253129 | 2010-07-18 14:27:13 +0200 | [diff] [blame] | 8 | * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | * |
| 10 | * These routines maintain argument size conversion between 32bit and 64bit |
| 11 | * ioctls. |
| 12 | */ |
| 13 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | #include <linux/types.h> |
| 15 | #include <linux/compat.h> |
| 16 | #include <linux/kernel.h> |
Randy Dunlap | 16f7e0f | 2006-01-11 12:17:46 -0800 | [diff] [blame] | 17 | #include <linux/capability.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | #include <linux/compiler.h> |
| 19 | #include <linux/sched.h> |
| 20 | #include <linux/smp.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 | #include <linux/ioctl.h> |
| 22 | #include <linux/if.h> |
NeilBrown | bff6197 | 2009-03-31 14:33:13 +1100 | [diff] [blame] | 23 | #include <linux/raid/md_u.h> |
Ankit Jain | 3e63cbb | 2009-06-19 14:28:07 -0400 | [diff] [blame] | 24 | #include <linux/falloc.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | #include <linux/file.h> |
Paul Mackerras | 4b32da2b | 2012-03-04 12:56:55 +0000 | [diff] [blame] | 26 | #include <linux/ppp-ioctl.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | #include <linux/if_pppox.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | #include <linux/tty.h> |
| 29 | #include <linux/vt_kern.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | #include <linux/blkdev.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | #include <linux/serial.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 | #include <linux/ctype.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | #include <linux/syscalls.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 34 | #include <linux/gfp.h> |
Hans Verkuil | 594edf3 | 2015-11-11 08:26:12 -0200 | [diff] [blame] | 35 | #include <linux/cec.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | |
Al Viro | 66cf191 | 2016-01-07 09:53:30 -0500 | [diff] [blame] | 37 | #include "internal.h" |
| 38 | |
Randy Dunlap | 3c3622d | 2008-07-16 08:52:00 -0500 | [diff] [blame] | 39 | #ifdef CONFIG_BLOCK |
Johannes Stezenbach | 390192b | 2011-07-01 22:32:26 +0200 | [diff] [blame] | 40 | #include <linux/cdrom.h> |
| 41 | #include <linux/fd.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | #include <scsi/scsi.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | #include <scsi/scsi_ioctl.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | #include <scsi/sg.h> |
Randy Dunlap | 3c3622d | 2008-07-16 08:52:00 -0500 | [diff] [blame] | 45 | #endif |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 | |
Linus Torvalds | 7c0f6ba | 2016-12-24 11:46:01 -0800 | [diff] [blame] | 47 | #include <linux/uaccess.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 48 | #include <linux/watchdog.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 49 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 | #include <linux/hiddev.h> |
| 51 | |
David S. Miller | 6e87abd | 2005-11-16 00:52:57 -0800 | [diff] [blame] | 52 | |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 53 | #include <linux/sort.h> |
| 54 | |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 55 | /* |
| 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 Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 60 | |
Mark Charlebois | 9280cdd | 2017-04-28 15:15:12 -0700 | [diff] [blame] | 61 | #define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd), |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 62 | static unsigned int ioctl_pointer[] = { |
Randy Dunlap | 3c3622d | 2008-07-16 08:52:00 -0500 | [diff] [blame] | 63 | #ifdef CONFIG_BLOCK |
Christoph Hellwig | 644fd4f | 2007-05-08 00:29:07 -0700 | [diff] [blame] | 64 | /* Big S */ |
| 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) |
Randy Dunlap | 3c3622d | 2008-07-16 08:52:00 -0500 | [diff] [blame] | 73 | #endif |
Randy Dunlap | 3c3622d | 2008-07-16 08:52:00 -0500 | [diff] [blame] | 74 | #ifdef CONFIG_BLOCK |
Christoph Hellwig | 644fd4f | 2007-05-08 00:29:07 -0700 | [diff] [blame] | 75 | /* SG stuff */ |
Arnd Bergmann | 98aaaec | 2019-03-14 17:45:18 +0100 | [diff] [blame] | 76 | COMPATIBLE_IOCTL(SG_IO) |
Arnd Bergmann | fd6c3d5 | 2018-08-24 14:53:13 +0200 | [diff] [blame] | 77 | COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE) |
Christoph Hellwig | 644fd4f | 2007-05-08 00:29:07 -0700 | [diff] [blame] | 78 | COMPATIBLE_IOCTL(SG_SET_TIMEOUT) |
| 79 | COMPATIBLE_IOCTL(SG_GET_TIMEOUT) |
| 80 | COMPATIBLE_IOCTL(SG_EMULATED_HOST) |
Christoph Hellwig | 644fd4f | 2007-05-08 00:29:07 -0700 | [diff] [blame] | 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) |
Randy Dunlap | 3c3622d | 2008-07-16 08:52:00 -0500 | [diff] [blame] | 100 | #endif |
Christoph Hellwig | e6a6d2e | 2006-01-09 20:52:14 -0800 | [diff] [blame] | 101 | }; |
David S. Miller | 6e87abd | 2005-11-16 00:52:57 -0800 | [diff] [blame] | 102 | |
Arnd Bergmann | 5a07ea0 | 2009-05-21 22:04:16 +0000 | [diff] [blame] | 103 | /* |
| 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 Viro | 66cf191 | 2016-01-07 09:53:30 -0500 | [diff] [blame] | 110 | static long do_ioctl_trans(unsigned int cmd, |
Arnd Bergmann | 5a07ea0 | 2009-05-21 22:04:16 +0000 | [diff] [blame] | 111 | unsigned long arg, struct file *file) |
| 112 | { |
Arnd Bergmann | 5a07ea0 | 2009-05-21 22:04:16 +0000 | [diff] [blame] | 113 | return -ENOIOCTLCMD; |
| 114 | } |
| 115 | |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 116 | static int compat_ioctl_check_table(unsigned int xcmd) |
| 117 | { |
Arnd Bergmann | 8f5d9f2 | 2019-07-26 15:21:39 +0200 | [diff] [blame] | 118 | #ifdef CONFIG_BLOCK |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 119 | 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 Bergmann | 8f5d9f2 | 2019-07-26 15:21:39 +0200 | [diff] [blame] | 137 | #else |
| 138 | return 0; |
| 139 | #endif |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 140 | } |
| 141 | |
Heiko Carstens | 932602e | 2014-03-04 16:07:52 +0100 | [diff] [blame] | 142 | COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, |
| 143 | compat_ulong_t, arg32) |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 144 | { |
Heiko Carstens | 932602e | 2014-03-04 16:07:52 +0100 | [diff] [blame] | 145 | unsigned long arg = arg32; |
Al Viro | 2903ff0 | 2012-08-28 12:52:22 -0400 | [diff] [blame] | 146 | struct fd f = fdget(fd); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 147 | int error = -EBADF; |
Al Viro | 2903ff0 | 2012-08-28 12:52:22 -0400 | [diff] [blame] | 148 | if (!f.file) |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 149 | goto out; |
| 150 | |
| 151 | /* RED-PEN how should LSM module know it's handling 32bit? */ |
Al Viro | 2903ff0 | 2012-08-28 12:52:22 -0400 | [diff] [blame] | 152 | error = security_file_ioctl(f.file, cmd, arg); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 153 | if (error) |
| 154 | goto out_fput; |
| 155 | |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 156 | switch (cmd) { |
Al Viro | 37ecf8b | 2019-04-21 20:43:10 -0400 | [diff] [blame] | 157 | /* these are never seen by ->ioctl(), no argument or int argument */ |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 158 | case FIOCLEX: |
| 159 | case FIONCLEX: |
Al Viro | 37ecf8b | 2019-04-21 20:43:10 -0400 | [diff] [blame] | 160 | case FIFREEZE: |
| 161 | case FITHAW: |
| 162 | case FICLONE: |
| 163 | goto do_ioctl; |
| 164 | /* these are never seen by ->ioctl(), pointer argument */ |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 165 | case FIONBIO: |
| 166 | case FIOASYNC: |
| 167 | case FIOQSIZE: |
Al Viro | 37ecf8b | 2019-04-21 20:43:10 -0400 | [diff] [blame] | 168 | 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 Torvalds | 97eeb4d | 2019-12-02 14:46:22 -0800 | [diff] [blame] | 188 | /* these get messy on amd64 due to alignment differences */ |
Al Viro | bf0a199 | 2019-04-21 19:10:09 -0400 | [diff] [blame] | 189 | #if defined(CONFIG_X86_64) |
Ankit Jain | 3e63cbb | 2009-06-19 14:28:07 -0400 | [diff] [blame] | 190 | case FS_IOC_RESVSP_32: |
| 191 | case FS_IOC_RESVSP64_32: |
Christoph Hellwig | 837a6e7 | 2019-10-24 22:26:02 -0700 | [diff] [blame] | 192 | 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 Jain | 3e63cbb | 2009-06-19 14:28:07 -0400 | [diff] [blame] | 202 | goto out_fput; |
| 203 | #else |
| 204 | case FS_IOC_RESVSP: |
| 205 | case FS_IOC_RESVSP64: |
Christoph Hellwig | 837a6e7 | 2019-10-24 22:26:02 -0700 | [diff] [blame] | 206 | case FS_IOC_UNRESVSP: |
| 207 | case FS_IOC_UNRESVSP64: |
Christoph Hellwig | 837a6e7 | 2019-10-24 22:26:02 -0700 | [diff] [blame] | 208 | case FS_IOC_ZERO_RANGE: |
Al Viro | 6b2daec | 2019-04-21 18:53:50 -0400 | [diff] [blame] | 209 | goto found_handler; |
Al Viro | 37ecf8b | 2019-04-21 20:43:10 -0400 | [diff] [blame] | 210 | #endif |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 211 | |
| 212 | default: |
Al Viro | 72c2d53 | 2013-09-22 16:27:52 -0400 | [diff] [blame] | 213 | if (f.file->f_op->compat_ioctl) { |
Al Viro | 2903ff0 | 2012-08-28 12:52:22 -0400 | [diff] [blame] | 214 | error = f.file->f_op->compat_ioctl(f.file, cmd, arg); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 215 | if (error != -ENOIOCTLCMD) |
| 216 | goto out_fput; |
| 217 | } |
| 218 | |
Al Viro | 72c2d53 | 2013-09-22 16:27:52 -0400 | [diff] [blame] | 219 | if (!f.file->f_op->unlocked_ioctl) |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 220 | goto do_ioctl; |
| 221 | break; |
| 222 | } |
| 223 | |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 224 | if (compat_ioctl_check_table(XFORM(cmd))) |
| 225 | goto found_handler; |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 226 | |
Al Viro | 66cf191 | 2016-01-07 09:53:30 -0500 | [diff] [blame] | 227 | error = do_ioctl_trans(cmd, arg, f.file); |
Linus Torvalds | 07d106d | 2012-01-05 15:40:12 -0800 | [diff] [blame] | 228 | if (error == -ENOIOCTLCMD) |
| 229 | error = -ENOTTY; |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 230 | |
| 231 | goto out_fput; |
| 232 | |
| 233 | found_handler: |
Arnd Bergmann | 789f0f8 | 2009-11-05 19:13:51 +0100 | [diff] [blame] | 234 | arg = (unsigned long)compat_ptr(arg); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 235 | do_ioctl: |
Al Viro | 2903ff0 | 2012-08-28 12:52:22 -0400 | [diff] [blame] | 236 | error = do_vfs_ioctl(f.file, fd, cmd, arg); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 237 | out_fput: |
Al Viro | 2903ff0 | 2012-08-28 12:52:22 -0400 | [diff] [blame] | 238 | fdput(f); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 239 | out: |
| 240 | return error; |
| 241 | } |
| 242 | |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 243 | static int __init init_sys32_ioctl_cmp(const void *p, const void *q) |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 244 | { |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 245 | 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 Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 253 | } |
| 254 | |
| 255 | static int __init init_sys32_ioctl(void) |
| 256 | { |
Arnd Bergmann | 661f627 | 2009-11-05 19:52:55 +0100 | [diff] [blame] | 257 | sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer), |
| 258 | init_sys32_ioctl_cmp, NULL); |
Christoph Hellwig | 6272e26 | 2007-05-08 00:29:21 -0700 | [diff] [blame] | 259 | return 0; |
| 260 | } |
| 261 | __initcall(init_sys32_ioctl); |