Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.5-rc6 261 lines 6.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0 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 8 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz) 9 * 10 * These routines maintain argument size conversion between 32bit and 64bit 11 * ioctls. 12 */ 13 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> 22#include <linux/if.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> 36 37#include "internal.h" 38 39#ifdef CONFIG_BLOCK 40#include <linux/cdrom.h> 41#include <linux/fd.h> 42#include <scsi/scsi.h> 43#include <scsi/scsi_ioctl.h> 44#include <scsi/sg.h> 45#endif 46 47#include <linux/uaccess.h> 48#include <linux/watchdog.h> 49 50#include <linux/hiddev.h> 51 52 53#include <linux/sort.h> 54 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) 60 61#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd), 62static unsigned int ioctl_pointer[] = { 63#ifdef CONFIG_BLOCK 64/* 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) 73#endif 74#ifdef CONFIG_BLOCK 75/* SG stuff */ 76COMPATIBLE_IOCTL(SG_IO) 77COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE) 78COMPATIBLE_IOCTL(SG_SET_TIMEOUT) 79COMPATIBLE_IOCTL(SG_GET_TIMEOUT) 80COMPATIBLE_IOCTL(SG_EMULATED_HOST) 81COMPATIBLE_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) 100#endif 101}; 102 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 */ 110static long do_ioctl_trans(unsigned int cmd, 111 unsigned long arg, struct file *file) 112{ 113 return -ENOIOCTLCMD; 114} 115 116static int compat_ioctl_check_table(unsigned int xcmd) 117{ 118#ifdef CONFIG_BLOCK 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; 137#else 138 return 0; 139#endif 140} 141 142COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, 143 compat_ulong_t, arg32) 144{ 145 unsigned long arg = arg32; 146 struct fd f = fdget(fd); 147 int error = -EBADF; 148 if (!f.file) 149 goto out; 150 151 /* RED-PEN how should LSM module know it's handling 32bit? */ 152 error = security_file_ioctl(f.file, cmd, arg); 153 if (error) 154 goto out_fput; 155 156 switch (cmd) { 157 /* these are never seen by ->ioctl(), no argument or int argument */ 158 case FIOCLEX: 159 case FIONCLEX: 160 case FIFREEZE: 161 case FITHAW: 162 case FICLONE: 163 goto do_ioctl; 164 /* these are never seen by ->ioctl(), pointer argument */ 165 case FIONBIO: 166 case FIOASYNC: 167 case FIOQSIZE: 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; 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)); 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)); 202 goto out_fput; 203#else 204 case FS_IOC_RESVSP: 205 case FS_IOC_RESVSP64: 206 case FS_IOC_UNRESVSP: 207 case FS_IOC_UNRESVSP64: 208 case FS_IOC_ZERO_RANGE: 209 goto found_handler; 210#endif 211 212 default: 213 if (f.file->f_op->compat_ioctl) { 214 error = f.file->f_op->compat_ioctl(f.file, cmd, arg); 215 if (error != -ENOIOCTLCMD) 216 goto out_fput; 217 } 218 219 if (!f.file->f_op->unlocked_ioctl) 220 goto do_ioctl; 221 break; 222 } 223 224 if (compat_ioctl_check_table(XFORM(cmd))) 225 goto found_handler; 226 227 error = do_ioctl_trans(cmd, arg, f.file); 228 if (error == -ENOIOCTLCMD) 229 error = -ENOTTY; 230 231 goto out_fput; 232 233 found_handler: 234 arg = (unsigned long)compat_ptr(arg); 235 do_ioctl: 236 error = do_vfs_ioctl(f.file, fd, cmd, arg); 237 out_fput: 238 fdput(f); 239 out: 240 return error; 241} 242 243static int __init init_sys32_ioctl_cmp(const void *p, const void *q) 244{ 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; 253} 254 255static int __init init_sys32_ioctl(void) 256{ 257 sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer), 258 init_sys32_ioctl_cmp, NULL); 259 return 0; 260} 261__initcall(init_sys32_ioctl);