compat_ioctl: handle PPPIOCGIDLE for 64-bit time_t
[linux-block.git] / fs / compat_ioctl.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
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
a2531293 8 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
1da177e4
LT
9 *
10 * These routines maintain argument size conversion between 32bit and 64bit
11 * ioctls.
12 */
13
1da177e4
LT
14#include <linux/types.h>
15#include <linux/compat.h>
16#include <linux/kernel.h>
16f7e0fe 17#include <linux/capability.h>
1da177e4
LT
18#include <linux/compiler.h>
19#include <linux/sched.h>
20#include <linux/smp.h>
1da177e4
LT
21#include <linux/ioctl.h>
22#include <linux/if.h>
bff61975 23#include <linux/raid/md_u.h>
3e63cbb1 24#include <linux/falloc.h>
1da177e4 25#include <linux/file.h>
4b32da2b 26#include <linux/ppp-ioctl.h>
1da177e4 27#include <linux/if_pppox.h>
1da177e4
LT
28#include <linux/tty.h>
29#include <linux/vt_kern.h>
1da177e4 30#include <linux/blkdev.h>
1da177e4 31#include <linux/serial.h>
1da177e4 32#include <linux/ctype.h>
1da177e4 33#include <linux/syscalls.h>
5a0e3ad6 34#include <linux/gfp.h>
594edf39 35#include <linux/cec.h>
1da177e4 36
66cf191f
AV
37#include "internal.h"
38
3c3622dc 39#ifdef CONFIG_BLOCK
390192b3
JS
40#include <linux/cdrom.h>
41#include <linux/fd.h>
1da177e4 42#include <scsi/scsi.h>
1da177e4 43#include <scsi/scsi_ioctl.h>
1da177e4 44#include <scsi/sg.h>
3c3622dc 45#endif
1da177e4 46
7c0f6ba6 47#include <linux/uaccess.h>
1da177e4 48#include <linux/watchdog.h>
1da177e4 49
1da177e4
LT
50#include <linux/hiddev.h>
51
6e87abd0 52
661f627d
AB
53#include <linux/sort.h>
54
17c7e7f4 55#ifdef CONFIG_BLOCK
66cf191f 56static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
b4341721
JH
57{
58 int err;
59
60 err = security_file_ioctl(file, cmd, arg);
61 if (err)
62 return err;
63
66cf191f 64 return vfs_ioctl(file, cmd, arg);
b4341721
JH
65}
66
2966387b
AK
67struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
68 char req_state;
69 char orphan;
70 char sg_io_owned;
71 char problem;
72 int pack_id;
73 compat_uptr_t usr_ptr;
74 unsigned int duration;
75 int unused;
76};
77
66cf191f 78static int sg_grt_trans(struct file *file,
b4341721 79 unsigned int cmd, struct compat_sg_req_info __user *o)
2966387b
AK
80{
81 int err, i;
6b2b4e5a 82 sg_req_info_t __user *r;
2966387b 83 r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE);
66cf191f 84 err = do_ioctl(file, cmd, (unsigned long)r);
2966387b
AK
85 if (err < 0)
86 return err;
87 for (i = 0; i < SG_MAX_QUEUE; i++) {
88 void __user *ptr;
89 int d;
90
91 if (copy_in_user(o + i, r + i, offsetof(sg_req_info_t, usr_ptr)) ||
92 get_user(ptr, &r[i].usr_ptr) ||
93 get_user(d, &r[i].duration) ||
94 put_user((u32)(unsigned long)(ptr), &o[i].usr_ptr) ||
95 put_user(d, &o[i].duration))
96 return -EFAULT;
97 }
98 return err;
99}
9361401e 100#endif /* CONFIG_BLOCK */
2966387b 101
661f627d
AB
102/*
103 * simple reversible transform to make our table more evenly
104 * distributed after sorting.
105 */
106#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
6272e266 107
9280cdd6 108#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
661f627d 109static unsigned int ioctl_pointer[] = {
3c3622dc 110#ifdef CONFIG_BLOCK
644fd4f5
CH
111/* Big S */
112COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
113COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
114COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
115COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
116COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
117COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
118COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
119COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
3c3622dc 120#endif
3c3622dc 121#ifdef CONFIG_BLOCK
644fd4f5 122/* SG stuff */
98aaaec4 123COMPATIBLE_IOCTL(SG_IO)
644fd4f5
CH
124COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
125COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
126COMPATIBLE_IOCTL(SG_EMULATED_HOST)
644fd4f5
CH
127COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
128COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
129COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
130COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
131COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
132COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
133COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
134COMPATIBLE_IOCTL(SG_GET_PACK_ID)
135COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
136COMPATIBLE_IOCTL(SG_SET_DEBUG)
137COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
138COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
139COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
140COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
141COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
142COMPATIBLE_IOCTL(SG_SCSI_RESET)
143COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
144COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
145COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
3c3622dc 146#endif
644fd4f5
CH
147/* PPP stuff */
148COMPATIBLE_IOCTL(PPPIOCGFLAGS)
149COMPATIBLE_IOCTL(PPPIOCSFLAGS)
150COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
151COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
152COMPATIBLE_IOCTL(PPPIOCGUNIT)
153COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
154COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
155COMPATIBLE_IOCTL(PPPIOCGMRU)
156COMPATIBLE_IOCTL(PPPIOCSMRU)
157COMPATIBLE_IOCTL(PPPIOCSMAXCID)
158COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
159COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
160COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
161/* PPPIOCSCOMPRESS is translated */
162COMPATIBLE_IOCTL(PPPIOCGNPMODE)
163COMPATIBLE_IOCTL(PPPIOCSNPMODE)
164COMPATIBLE_IOCTL(PPPIOCGDEBUG)
165COMPATIBLE_IOCTL(PPPIOCSDEBUG)
166/* PPPIOCSPASS is translated */
167/* PPPIOCSACTIVE is translated */
17c7e7f4
AB
168COMPATIBLE_IOCTL(PPPIOCGIDLE32)
169COMPATIBLE_IOCTL(PPPIOCGIDLE64)
644fd4f5
CH
170COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
171COMPATIBLE_IOCTL(PPPIOCATTACH)
172COMPATIBLE_IOCTL(PPPIOCDETACH)
173COMPATIBLE_IOCTL(PPPIOCSMRRU)
174COMPATIBLE_IOCTL(PPPIOCCONNECT)
175COMPATIBLE_IOCTL(PPPIOCDISCONN)
176COMPATIBLE_IOCTL(PPPIOCATTCHAN)
177COMPATIBLE_IOCTL(PPPIOCGCHAN)
8bab6f14 178COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
e6a6d2ef 179};
6e87abd0 180
5a07ea0b
AB
181/*
182 * Convert common ioctl arguments based on their command number
183 *
184 * Please do not add any code in here. Instead, implement
185 * a compat_ioctl operation in the place that handleѕ the
186 * ioctl for the native case.
187 */
66cf191f 188static long do_ioctl_trans(unsigned int cmd,
5a07ea0b
AB
189 unsigned long arg, struct file *file)
190{
17c7e7f4 191#ifdef CONFIG_BLOCK
43c6e7b9
AB
192 void __user *argp = compat_ptr(arg);
193
5a07ea0b 194 switch (cmd) {
5a07ea0b 195 case SG_GET_REQUEST_TABLE:
66cf191f 196 return sg_grt_trans(file, cmd, argp);
5a07ea0b 197 }
17c7e7f4 198#endif
789f0f89 199
5a07ea0b
AB
200 return -ENOIOCTLCMD;
201}
202
661f627d
AB
203static int compat_ioctl_check_table(unsigned int xcmd)
204{
205 int i;
206 const int max = ARRAY_SIZE(ioctl_pointer) - 1;
207
208 BUILD_BUG_ON(max >= (1 << 16));
209
210 /* guess initial offset into table, assuming a
211 normalized distribution */
212 i = ((xcmd >> 16) * max) >> 16;
213
214 /* do linear search up first, until greater or equal */
215 while (ioctl_pointer[i] < xcmd && i < max)
216 i++;
217
218 /* then do linear search down */
219 while (ioctl_pointer[i] > xcmd && i > 0)
220 i--;
221
222 return ioctl_pointer[i] == xcmd;
223}
224
932602e2
HC
225COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
226 compat_ulong_t, arg32)
6272e266 227{
932602e2 228 unsigned long arg = arg32;
2903ff01 229 struct fd f = fdget(fd);
6272e266 230 int error = -EBADF;
2903ff01 231 if (!f.file)
6272e266
CH
232 goto out;
233
234 /* RED-PEN how should LSM module know it's handling 32bit? */
2903ff01 235 error = security_file_ioctl(f.file, cmd, arg);
6272e266
CH
236 if (error)
237 goto out_fput;
238
6272e266 239 switch (cmd) {
37ecf8b2 240 /* these are never seen by ->ioctl(), no argument or int argument */
6272e266
CH
241 case FIOCLEX:
242 case FIONCLEX:
37ecf8b2
AV
243 case FIFREEZE:
244 case FITHAW:
245 case FICLONE:
246 goto do_ioctl;
247 /* these are never seen by ->ioctl(), pointer argument */
6272e266
CH
248 case FIONBIO:
249 case FIOASYNC:
250 case FIOQSIZE:
37ecf8b2
AV
251 case FS_IOC_FIEMAP:
252 case FIGETBSZ:
253 case FICLONERANGE:
254 case FIDEDUPERANGE:
255 goto found_handler;
256 /*
257 * The next group is the stuff handled inside file_ioctl().
258 * For regular files these never reach ->ioctl(); for
259 * devices, sockets, etc. they do and one (FIONREAD) is
260 * even accepted in some cases. In all those cases
261 * argument has the same type, so we can handle these
262 * here, shunting them towards do_vfs_ioctl().
263 * ->compat_ioctl() will never see any of those.
264 */
265 /* pointer argument, never actually handled by ->ioctl() */
266 case FIBMAP:
267 goto found_handler;
268 /* handled by some ->ioctl(); always a pointer to int */
269 case FIONREAD:
270 goto found_handler;
271 /* these two get messy on amd64 due to alignment differences */
bf0a199b 272#if defined(CONFIG_X86_64)
3e63cbb1
AJ
273 case FS_IOC_RESVSP_32:
274 case FS_IOC_RESVSP64_32:
2903ff01 275 error = compat_ioctl_preallocate(f.file, compat_ptr(arg));
3e63cbb1
AJ
276 goto out_fput;
277#else
278 case FS_IOC_RESVSP:
279 case FS_IOC_RESVSP64:
6b2daec1 280 goto found_handler;
37ecf8b2 281#endif
6272e266
CH
282
283 default:
72c2d531 284 if (f.file->f_op->compat_ioctl) {
2903ff01 285 error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
6272e266
CH
286 if (error != -ENOIOCTLCMD)
287 goto out_fput;
288 }
289
72c2d531 290 if (!f.file->f_op->unlocked_ioctl)
6272e266
CH
291 goto do_ioctl;
292 break;
293 }
294
661f627d
AB
295 if (compat_ioctl_check_table(XFORM(cmd)))
296 goto found_handler;
6272e266 297
66cf191f 298 error = do_ioctl_trans(cmd, arg, f.file);
07d106d0
LT
299 if (error == -ENOIOCTLCMD)
300 error = -ENOTTY;
6272e266
CH
301
302 goto out_fput;
303
304 found_handler:
789f0f89 305 arg = (unsigned long)compat_ptr(arg);
6272e266 306 do_ioctl:
2903ff01 307 error = do_vfs_ioctl(f.file, fd, cmd, arg);
6272e266 308 out_fput:
2903ff01 309 fdput(f);
6272e266
CH
310 out:
311 return error;
312}
313
661f627d 314static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
6272e266 315{
661f627d
AB
316 unsigned int a, b;
317 a = *(unsigned int *)p;
318 b = *(unsigned int *)q;
319 if (a > b)
320 return 1;
321 if (a < b)
322 return -1;
323 return 0;
6272e266
CH
324}
325
326static int __init init_sys32_ioctl(void)
327{
661f627d
AB
328 sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
329 init_sys32_ioctl_cmp, NULL);
6272e266
CH
330 return 0;
331}
332__initcall(init_sys32_ioctl);