1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/linkage.h>
19#include <linux/compat.h>
20#include <linux/errno.h>
21#include <linux/time.h>
22#include <linux/fs.h>
23#include <linux/fcntl.h>
24#include <linux/namei.h>
25#include <linux/file.h>
26#include <linux/vfs.h>
27#include <linux/ioctl32.h>
28#include <linux/init.h>
29#include <linux/sockios.h>
30#include <linux/smp_lock.h>
31#include <linux/ctype.h>
32#include <linux/module.h>
33#include <net/sock.h>
34
35#include <asm/uaccess.h>
36
37
38
39
40
41asmlinkage long compat_sys_utime(char *filename, struct compat_utimbuf *t)
42{
43 struct timeval tv[2];
44
45 if (t) {
46 if (get_user(tv[0].tv_sec, &t->actime) ||
47 get_user(tv[1].tv_sec, &t->modtime))
48 return -EFAULT;
49 tv[0].tv_usec = 0;
50 tv[1].tv_usec = 0;
51 }
52 return do_utimes(filename, t ? tv : NULL);
53}
54
55asmlinkage long compat_sys_utimes(char *filename, struct compat_timeval *t)
56{
57 struct timeval tv[2];
58
59 if (t) {
60 if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
61 get_user(tv[0].tv_usec, &t[0].tv_usec) ||
62 get_user(tv[1].tv_sec, &t[1].tv_sec) ||
63 get_user(tv[1].tv_usec, &t[1].tv_usec))
64 return -EFAULT;
65 }
66 return do_utimes(filename, t ? tv : NULL);
67}
68
69asmlinkage long compat_sys_newstat(char * filename,
70 struct compat_stat *statbuf)
71{
72 struct kstat stat;
73 int error = vfs_stat(filename, &stat);
74
75 if (!error)
76 error = cp_compat_stat(&stat, statbuf);
77 return error;
78}
79
80asmlinkage long compat_sys_newlstat(char * filename,
81 struct compat_stat *statbuf)
82{
83 struct kstat stat;
84 int error = vfs_lstat(filename, &stat);
85
86 if (!error)
87 error = cp_compat_stat(&stat, statbuf);
88 return error;
89}
90
91asmlinkage long compat_sys_newfstat(unsigned int fd,
92 struct compat_stat * statbuf)
93{
94 struct kstat stat;
95 int error = vfs_fstat(fd, &stat);
96
97 if (!error)
98 error = cp_compat_stat(&stat, statbuf);
99 return error;
100}
101
102static int put_compat_statfs(struct compat_statfs *ubuf, struct kstatfs *kbuf)
103{
104
105 if (sizeof ubuf->f_blocks == 4) {
106 if ((kbuf->f_blocks | kbuf->f_bfree |
107 kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
108 0xffffffff00000000ULL)
109 return -EOVERFLOW;
110 }
111 if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
112 __put_user(kbuf->f_type, &ubuf->f_type) ||
113 __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
114 __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
115 __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
116 __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
117 __put_user(kbuf->f_files, &ubuf->f_files) ||
118 __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
119 __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
120 __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
121 __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
122 __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
123 __put_user(0, &ubuf->f_spare[0]) ||
124 __put_user(0, &ubuf->f_spare[1]) ||
125 __put_user(0, &ubuf->f_spare[2]) ||
126 __put_user(0, &ubuf->f_spare[3]) ||
127 __put_user(0, &ubuf->f_spare[4]))
128 return -EFAULT;
129 return 0;
130}
131
132
133
134
135
136asmlinkage long compat_sys_statfs(const char *path, struct compat_statfs *buf)
137{
138 struct nameidata nd;
139 int error;
140
141 error = user_path_walk(path, &nd);
142 if (!error) {
143 struct kstatfs tmp;
144 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
145 if (!error && put_compat_statfs(buf, &tmp))
146 error = -EFAULT;
147 path_release(&nd);
148 }
149 return error;
150}
151
152asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs *buf)
153{
154 struct file * file;
155 struct kstatfs tmp;
156 int error;
157
158 error = -EBADF;
159 file = fget(fd);
160 if (!file)
161 goto out;
162 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
163 if (!error && put_compat_statfs(buf, &tmp))
164 error = -EFAULT;
165 fput(file);
166out:
167 return error;
168}
169
170static int put_compat_statfs64(struct compat_statfs64 *ubuf, struct kstatfs *kbuf)
171{
172 if (sizeof ubuf->f_blocks == 4) {
173 if ((kbuf->f_blocks | kbuf->f_bfree |
174 kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
175 0xffffffff00000000ULL)
176 return -EOVERFLOW;
177 }
178 if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
179 __put_user(kbuf->f_type, &ubuf->f_type) ||
180 __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
181 __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
182 __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
183 __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
184 __put_user(kbuf->f_files, &ubuf->f_files) ||
185 __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
186 __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
187 __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
188 __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
189 __put_user(kbuf->f_frsize, &ubuf->f_frsize))
190 return -EFAULT;
191 return 0;
192}
193
194asmlinkage long compat_statfs64(const char *path, compat_size_t sz, struct compat_statfs64 *buf)
195{
196 struct nameidata nd;
197 int error;
198
199 if (sz != sizeof(*buf))
200 return -EINVAL;
201
202 error = user_path_walk(path, &nd);
203 if (!error) {
204 struct kstatfs tmp;
205 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
206 if (!error && put_compat_statfs64(buf, &tmp))
207 error = -EFAULT;
208 path_release(&nd);
209 }
210 return error;
211}
212
213asmlinkage long compat_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 *buf)
214{
215 struct file * file;
216 struct kstatfs tmp;
217 int error;
218
219 if (sz != sizeof(*buf))
220 return -EINVAL;
221
222 error = -EBADF;
223 file = fget(fd);
224 if (!file)
225 goto out;
226 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
227 if (!error && put_compat_statfs64(buf, &tmp))
228 error = -EFAULT;
229 fput(file);
230out:
231 return error;
232}
233
234
235
236#define IOCTL_HASHSIZE 256
237struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
238
239extern struct ioctl_trans ioctl_start[];
240extern int ioctl_table_size;
241
242static inline unsigned long ioctl32_hash(unsigned long cmd)
243{
244 return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
245}
246
247static void ioctl32_insert_translation(struct ioctl_trans *trans)
248{
249 unsigned long hash;
250 struct ioctl_trans *t;
251
252 hash = ioctl32_hash (trans->cmd);
253 if (!ioctl32_hash_table[hash])
254 ioctl32_hash_table[hash] = trans;
255 else {
256 t = ioctl32_hash_table[hash];
257 while (t->next)
258 t = t->next;
259 trans->next = 0;
260 t->next = trans;
261 }
262}
263
264static int __init init_sys32_ioctl(void)
265{
266 int i;
267
268 for (i = 0; i < ioctl_table_size; i++) {
269 if (ioctl_start[i].next != 0) {
270 printk("ioctl translation %d bad\n",i);
271 return -1;
272 }
273
274 ioctl32_insert_translation(&ioctl_start[i]);
275 }
276 return 0;
277}
278
279__initcall(init_sys32_ioctl);
280
281static struct ioctl_trans *ioctl_free_list;
282
283
284
285static void free_ioctl(struct ioctl_trans *t)
286{
287 t->cmd = 0;
288 mb();
289 t->next = ioctl_free_list;
290 ioctl_free_list = t;
291}
292
293int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
294{
295 struct ioctl_trans *t;
296 unsigned long hash = ioctl32_hash(cmd);
297
298 lock_kernel();
299 for (t = (struct ioctl_trans *)ioctl32_hash_table[hash];
300 t;
301 t = t->next) {
302 if (t->cmd == cmd) {
303 printk("Trying to register duplicated ioctl32 handler %x\n", cmd);
304 unlock_kernel();
305 return -EINVAL;
306 }
307 }
308
309 if (ioctl_free_list) {
310 t = ioctl_free_list;
311 ioctl_free_list = t->next;
312 } else {
313 t = kmalloc(sizeof(struct ioctl_trans), GFP_KERNEL);
314 if (!t) {
315 unlock_kernel();
316 return -ENOMEM;
317 }
318 }
319
320 t->next = NULL;
321 t->cmd = cmd;
322 t->handler = handler;
323 ioctl32_insert_translation(t);
324
325 unlock_kernel();
326 return 0;
327}
328
329static inline int builtin_ioctl(struct ioctl_trans *t)
330{
331 return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
332}
333
334
335
336
337
338
339int unregister_ioctl32_conversion(unsigned int cmd)
340{
341 unsigned long hash = ioctl32_hash(cmd);
342 struct ioctl_trans *t, *t1;
343
344 lock_kernel();
345
346 t = (struct ioctl_trans *)ioctl32_hash_table[hash];
347 if (!t) {
348 unlock_kernel();
349 return -EINVAL;
350 }
351
352 if (t->cmd == cmd) {
353 if (builtin_ioctl(t)) {
354 printk("%p tried to unregister builtin ioctl %x\n",
355 __builtin_return_address(0), cmd);
356 } else {
357 ioctl32_hash_table[hash] = t->next;
358 free_ioctl(t);
359 unlock_kernel();
360 return 0;
361 }
362 }
363 while (t->next) {
364 t1 = (struct ioctl_trans *)(long)t->next;
365 if (t1->cmd == cmd) {
366 if (builtin_ioctl(t1)) {
367 printk("%p tried to unregister builtin ioctl %x\n",
368 __builtin_return_address(0), cmd);
369 goto out;
370 } else {
371 t->next = t1->next;
372 free_ioctl(t1);
373 unlock_kernel();
374 return 0;
375 }
376 }
377 t = t1;
378 }
379 printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd);
380 out:
381 unlock_kernel();
382 return -EINVAL;
383}
384
385EXPORT_SYMBOL(register_ioctl32_conversion);
386EXPORT_SYMBOL(unregister_ioctl32_conversion);
387
388asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
389{
390 struct file * filp;
391 int error = -EBADF;
392 struct ioctl_trans *t;
393
394 filp = fget(fd);
395 if(!filp)
396 goto out2;
397
398 if (!filp->f_op || !filp->f_op->ioctl) {
399 error = sys_ioctl (fd, cmd, arg);
400 goto out;
401 }
402
403 t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)];
404
405 while (t && t->cmd != cmd)
406 t = (struct ioctl_trans *)t->next;
407 if (t) {
408 if (t->handler)
409 error = t->handler(fd, cmd, arg, filp);
410 else
411 error = sys_ioctl(fd, cmd, arg);
412 } else if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
413 error = siocdevprivate_ioctl(fd, cmd, arg);
414 } else {
415 static int count;
416 if (++count <= 50) {
417 char buf[10];
418 char *path = (char *)__get_free_page(GFP_KERNEL), *fn = "?";
419
420
421 if (path) {
422 fn = d_path(filp->f_dentry, filp->f_vfsmnt,
423 path, PAGE_SIZE);
424 }
425
426 sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
427 if (!isprint(buf[1]))
428 sprintf(buf, "%02x", buf[1]);
429 printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
430 "cmd(%08x){%s} arg(%08x) on %s\n",
431 current->comm, current->pid,
432 (int)fd, (unsigned int)cmd, buf, (unsigned int)arg,
433 fn);
434 if (path)
435 free_page((unsigned long)path);
436 }
437 error = -EINVAL;
438 }
439out:
440 fput(filp);
441out2:
442 return error;
443}
444
445static int get_compat_flock(struct flock *kfl, struct compat_flock *ufl)
446{
447 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
448 __get_user(kfl->l_type, &ufl->l_type) ||
449 __get_user(kfl->l_whence, &ufl->l_whence) ||
450 __get_user(kfl->l_start, &ufl->l_start) ||
451 __get_user(kfl->l_len, &ufl->l_len) ||
452 __get_user(kfl->l_pid, &ufl->l_pid))
453 return -EFAULT;
454 return 0;
455}
456
457static int put_compat_flock(struct flock *kfl, struct compat_flock *ufl)
458{
459 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
460 __put_user(kfl->l_type, &ufl->l_type) ||
461 __put_user(kfl->l_whence, &ufl->l_whence) ||
462 __put_user(kfl->l_start, &ufl->l_start) ||
463 __put_user(kfl->l_len, &ufl->l_len) ||
464 __put_user(kfl->l_pid, &ufl->l_pid))
465 return -EFAULT;
466 return 0;
467}
468
469#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
470static int get_compat_flock64(struct flock *kfl, struct compat_flock64 *ufl)
471{
472 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
473 __get_user(kfl->l_type, &ufl->l_type) ||
474 __get_user(kfl->l_whence, &ufl->l_whence) ||
475 __get_user(kfl->l_start, &ufl->l_start) ||
476 __get_user(kfl->l_len, &ufl->l_len) ||
477 __get_user(kfl->l_pid, &ufl->l_pid))
478 return -EFAULT;
479 return 0;
480}
481#endif
482
483#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
484static int put_compat_flock64(struct flock *kfl, struct compat_flock64 *ufl)
485{
486 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
487 __put_user(kfl->l_type, &ufl->l_type) ||
488 __put_user(kfl->l_whence, &ufl->l_whence) ||
489 __put_user(kfl->l_start, &ufl->l_start) ||
490 __put_user(kfl->l_len, &ufl->l_len) ||
491 __put_user(kfl->l_pid, &ufl->l_pid))
492 return -EFAULT;
493 return 0;
494}
495#endif
496
497extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
498
499asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
500 unsigned long arg)
501{
502 mm_segment_t old_fs;
503 struct flock f;
504 long ret;
505
506 switch (cmd) {
507 case F_GETLK:
508 case F_SETLK:
509 case F_SETLKW:
510 ret = get_compat_flock(&f, compat_ptr(arg));
511 if (ret != 0)
512 break;
513 old_fs = get_fs();
514 set_fs(KERNEL_DS);
515 ret = sys_fcntl(fd, cmd, (unsigned long)&f);
516 set_fs(old_fs);
517 if ((cmd == F_GETLK) && (ret == 0)) {
518 if ((f.l_start >= COMPAT_OFF_T_MAX) ||
519 ((f.l_start + f.l_len) >= COMPAT_OFF_T_MAX))
520 ret = -EOVERFLOW;
521 if (ret == 0)
522 ret = put_compat_flock(&f, compat_ptr(arg));
523 }
524 break;
525
526 case F_GETLK64:
527 case F_SETLK64:
528 case F_SETLKW64:
529 ret = get_compat_flock64(&f, compat_ptr(arg));
530 if (ret != 0)
531 break;
532 old_fs = get_fs();
533 set_fs(KERNEL_DS);
534 ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK :
535 ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW),
536 (unsigned long)&f);
537 set_fs(old_fs);
538 if ((cmd == F_GETLK64) && (ret == 0)) {
539 if ((f.l_start >= COMPAT_LOFF_T_MAX) ||
540 ((f.l_start + f.l_len) >= COMPAT_LOFF_T_MAX))
541 ret = -EOVERFLOW;
542 if (ret == 0)
543 ret = put_compat_flock64(&f, compat_ptr(arg));
544 }
545 break;
546
547 default:
548 ret = sys_fcntl(fd, cmd, arg);
549 break;
550 }
551 return ret;
552}
553
554asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
555 unsigned long arg)
556{
557 if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
558 return -EINVAL;
559 return compat_sys_fcntl64(fd, cmd, arg);
560}
561
562extern asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
563
564asmlinkage long
565compat_sys_io_setup(unsigned nr_reqs, u32 *ctx32p)
566{
567 long ret;
568 aio_context_t ctx64;
569
570 mm_segment_t oldfs = get_fs();
571 if (unlikely(get_user(ctx64, ctx32p)))
572 return -EFAULT;
573
574 set_fs(KERNEL_DS);
575 ret = sys_io_setup(nr_reqs, &ctx64);
576 set_fs(oldfs);
577
578 if (!ret)
579 ret = put_user((u32) ctx64, ctx32p);
580 return ret;
581}
582
583extern asmlinkage long sys_io_getevents(aio_context_t ctx_id,
584 long min_nr,
585 long nr,
586 struct io_event *events,
587 struct timespec *timeout);
588
589asmlinkage long
590compat_sys_io_getevents(aio_context_t ctx_id,
591 unsigned long min_nr,
592 unsigned long nr,
593 struct io_event *events,
594 struct compat_timespec *timeout)
595{
596 long ret;
597 struct timespec t;
598 struct timespec *ut = NULL;
599
600 ret = -EFAULT;
601 if (unlikely(!access_ok(VERIFY_WRITE, events,
602 nr * sizeof(struct io_event))))
603 goto out;
604 if (timeout) {
605 if (get_compat_timespec(&t, timeout))
606 goto out;
607
608 ut = compat_alloc_user_space(sizeof(*ut));
609 if (copy_to_user(ut, &t, sizeof(t)) )
610 goto out;
611 }
612 ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
613out:
614 return ret;
615}
616
617extern asmlinkage long sys_io_submit(aio_context_t, long,
618 struct iocb __user **);
619
620static inline long
621copy_iocb(long nr, u32 *ptr32, u64 *ptr64)
622{
623 compat_uptr_t uptr;
624 int i;
625
626 for (i = 0; i < nr; ++i) {
627 if (get_user(uptr, ptr32 + i))
628 return -EFAULT;
629 if (put_user((u64)compat_ptr(uptr), ptr64 + i))
630 return -EFAULT;
631 }
632 return 0;
633}
634
635#define MAX_AIO_SUBMITS (PAGE_SIZE/sizeof(struct iocb *))
636
637asmlinkage long
638compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 *iocb)
639{
640 struct iocb **iocb64;
641 long ret;
642
643 if (unlikely(nr < 0))
644 return -EINVAL;
645
646 if (nr > MAX_AIO_SUBMITS)
647 nr = MAX_AIO_SUBMITS;
648
649 iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
650 ret = copy_iocb(nr, iocb, (u64 *) iocb64);
651 if (!ret)
652 ret = sys_io_submit(ctx_id, nr, iocb64);
653 return ret;
654}
655