[PATCH] DVB: misc. updates to the dvb-core
[linux-2.6/history.git] / fs / compat.c
blob7257be91b4bd250ae10fe4379128412fd0cb3393
1 /*
2 * linux/fs/compat.c
4 * Kernel compatibililty routines for e.g. 32 bit syscall support
5 * on 64 bit kernels.
7 * Copyright (C) 2002 Stephen Rothwell, IBM Corporation
8 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
9 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
10 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
11 * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
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> /* for SIOCDEVPRIVATE */
30 #include <linux/smb.h>
31 #include <linux/smb_mount.h>
32 #include <linux/ncp_mount.h>
33 #include <linux/smp_lock.h>
34 #include <linux/syscalls.h>
35 #include <linux/ctype.h>
36 #include <linux/module.h>
37 #include <linux/dirent.h>
38 #include <linux/dnotify.h>
39 #include <linux/highuid.h>
40 #include <linux/sunrpc/svc.h>
41 #include <linux/nfsd/nfsd.h>
42 #include <linux/nfsd/syscall.h>
43 #include <linux/personality.h>
44 #include <linux/rwsem.h>
46 #include <net/sock.h> /* siocdevprivate_ioctl */
48 #include <asm/uaccess.h>
49 #include <asm/mmu_context.h>
52 * Not all architectures have sys_utime, so implement this in terms
53 * of sys_utimes.
55 asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
57 struct timeval tv[2];
59 if (t) {
60 if (get_user(tv[0].tv_sec, &t->actime) ||
61 get_user(tv[1].tv_sec, &t->modtime))
62 return -EFAULT;
63 tv[0].tv_usec = 0;
64 tv[1].tv_usec = 0;
66 return do_utimes(filename, t ? tv : NULL);
69 asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
71 struct timeval tv[2];
73 if (t) {
74 if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
75 get_user(tv[0].tv_usec, &t[0].tv_usec) ||
76 get_user(tv[1].tv_sec, &t[1].tv_sec) ||
77 get_user(tv[1].tv_usec, &t[1].tv_usec))
78 return -EFAULT;
80 return do_utimes(filename, t ? tv : NULL);
83 asmlinkage long compat_sys_newstat(char __user * filename,
84 struct compat_stat __user *statbuf)
86 struct kstat stat;
87 int error = vfs_stat(filename, &stat);
89 if (!error)
90 error = cp_compat_stat(&stat, statbuf);
91 return error;
94 asmlinkage long compat_sys_newlstat(char __user * filename,
95 struct compat_stat __user *statbuf)
97 struct kstat stat;
98 int error = vfs_lstat(filename, &stat);
100 if (!error)
101 error = cp_compat_stat(&stat, statbuf);
102 return error;
105 asmlinkage long compat_sys_newfstat(unsigned int fd,
106 struct compat_stat __user * statbuf)
108 struct kstat stat;
109 int error = vfs_fstat(fd, &stat);
111 if (!error)
112 error = cp_compat_stat(&stat, statbuf);
113 return error;
116 static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
119 if (sizeof ubuf->f_blocks == 4) {
120 if ((kbuf->f_blocks | kbuf->f_bfree |
121 kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
122 0xffffffff00000000ULL)
123 return -EOVERFLOW;
125 if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
126 __put_user(kbuf->f_type, &ubuf->f_type) ||
127 __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
128 __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
129 __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
130 __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
131 __put_user(kbuf->f_files, &ubuf->f_files) ||
132 __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
133 __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
134 __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
135 __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
136 __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
137 __put_user(0, &ubuf->f_spare[0]) ||
138 __put_user(0, &ubuf->f_spare[1]) ||
139 __put_user(0, &ubuf->f_spare[2]) ||
140 __put_user(0, &ubuf->f_spare[3]) ||
141 __put_user(0, &ubuf->f_spare[4]))
142 return -EFAULT;
143 return 0;
147 * The following statfs calls are copies of code from fs/open.c and
148 * should be checked against those from time to time
150 asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf)
152 struct nameidata nd;
153 int error;
155 error = user_path_walk(path, &nd);
156 if (!error) {
157 struct kstatfs tmp;
158 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
159 if (!error && put_compat_statfs(buf, &tmp))
160 error = -EFAULT;
161 path_release(&nd);
163 return error;
166 asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
168 struct file * file;
169 struct kstatfs tmp;
170 int error;
172 error = -EBADF;
173 file = fget(fd);
174 if (!file)
175 goto out;
176 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
177 if (!error && put_compat_statfs(buf, &tmp))
178 error = -EFAULT;
179 fput(file);
180 out:
181 return error;
184 static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
186 if (sizeof ubuf->f_blocks == 4) {
187 if ((kbuf->f_blocks | kbuf->f_bfree |
188 kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
189 0xffffffff00000000ULL)
190 return -EOVERFLOW;
192 if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
193 __put_user(kbuf->f_type, &ubuf->f_type) ||
194 __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
195 __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
196 __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
197 __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
198 __put_user(kbuf->f_files, &ubuf->f_files) ||
199 __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
200 __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
201 __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
202 __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
203 __put_user(kbuf->f_frsize, &ubuf->f_frsize))
204 return -EFAULT;
205 return 0;
208 asmlinkage long compat_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf)
210 struct nameidata nd;
211 int error;
213 if (sz != sizeof(*buf))
214 return -EINVAL;
216 error = user_path_walk(path, &nd);
217 if (!error) {
218 struct kstatfs tmp;
219 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
220 if (!error && put_compat_statfs64(buf, &tmp))
221 error = -EFAULT;
222 path_release(&nd);
224 return error;
227 asmlinkage long compat_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
229 struct file * file;
230 struct kstatfs tmp;
231 int error;
233 if (sz != sizeof(*buf))
234 return -EINVAL;
236 error = -EBADF;
237 file = fget(fd);
238 if (!file)
239 goto out;
240 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
241 if (!error && put_compat_statfs64(buf, &tmp))
242 error = -EFAULT;
243 fput(file);
244 out:
245 return error;
248 /* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */
250 #define IOCTL_HASHSIZE 256
251 static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
252 static DECLARE_RWSEM(ioctl32_sem);
254 extern struct ioctl_trans ioctl_start[];
255 extern int ioctl_table_size;
257 static inline unsigned long ioctl32_hash(unsigned long cmd)
259 return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
262 static void ioctl32_insert_translation(struct ioctl_trans *trans)
264 unsigned long hash;
265 struct ioctl_trans *t;
267 hash = ioctl32_hash (trans->cmd);
268 if (!ioctl32_hash_table[hash])
269 ioctl32_hash_table[hash] = trans;
270 else {
271 t = ioctl32_hash_table[hash];
272 while (t->next)
273 t = t->next;
274 trans->next = NULL;
275 t->next = trans;
279 static int __init init_sys32_ioctl(void)
281 int i;
283 for (i = 0; i < ioctl_table_size; i++) {
284 if (ioctl_start[i].next != 0) {
285 printk("ioctl translation %d bad\n",i);
286 return -1;
289 ioctl32_insert_translation(&ioctl_start[i]);
291 return 0;
294 __initcall(init_sys32_ioctl);
296 int register_ioctl32_conversion(unsigned int cmd,
297 ioctl_trans_handler_t handler)
299 struct ioctl_trans *t;
300 struct ioctl_trans *new_t;
301 unsigned long hash = ioctl32_hash(cmd);
303 new_t = kmalloc(sizeof(*new_t), GFP_KERNEL);
304 if (!new_t)
305 return -ENOMEM;
307 down_write(&ioctl32_sem);
308 for (t = ioctl32_hash_table[hash]; t; t = t->next) {
309 if (t->cmd == cmd) {
310 printk(KERN_ERR "Trying to register duplicated ioctl32 "
311 "handler %x\n", cmd);
312 up_write(&ioctl32_sem);
313 kfree(new_t);
314 return -EINVAL;
317 new_t->next = NULL;
318 new_t->cmd = cmd;
319 new_t->handler = handler;
320 ioctl32_insert_translation(new_t);
322 up_write(&ioctl32_sem);
323 return 0;
325 EXPORT_SYMBOL(register_ioctl32_conversion);
327 static inline int builtin_ioctl(struct ioctl_trans *t)
329 return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
332 /* Problem:
333 This function cannot unregister duplicate ioctls, because they are not
334 unique.
335 When they happen we need to extend the prototype to pass the handler too. */
337 int unregister_ioctl32_conversion(unsigned int cmd)
339 unsigned long hash = ioctl32_hash(cmd);
340 struct ioctl_trans *t, *t1;
342 down_write(&ioctl32_sem);
344 t = ioctl32_hash_table[hash];
345 if (!t) {
346 up_write(&ioctl32_sem);
347 return -EINVAL;
350 if (t->cmd == cmd) {
351 if (builtin_ioctl(t)) {
352 printk("%p tried to unregister builtin ioctl %x\n",
353 __builtin_return_address(0), cmd);
354 } else {
355 ioctl32_hash_table[hash] = t->next;
356 up_write(&ioctl32_sem);
357 kfree(t);
358 return 0;
361 while (t->next) {
362 t1 = t->next;
363 if (t1->cmd == cmd) {
364 if (builtin_ioctl(t1)) {
365 printk("%p tried to unregister builtin "
366 "ioctl %x\n",
367 __builtin_return_address(0), cmd);
368 goto out;
369 } else {
370 t->next = t1->next;
371 up_write(&ioctl32_sem);
372 kfree(t1);
373 return 0;
376 t = t1;
378 printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n",
379 cmd);
380 out:
381 up_write(&ioctl32_sem);
382 return -EINVAL;
384 EXPORT_SYMBOL(unregister_ioctl32_conversion);
386 asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
387 unsigned long arg)
389 struct file * filp;
390 int error = -EBADF;
391 struct ioctl_trans *t;
393 filp = fget(fd);
394 if(!filp)
395 goto out2;
397 if (!filp->f_op || !filp->f_op->ioctl) {
398 error = sys_ioctl (fd, cmd, arg);
399 goto out;
402 down_read(&ioctl32_sem);
404 t = ioctl32_hash_table[ioctl32_hash (cmd)];
406 while (t && t->cmd != cmd)
407 t = t->next;
408 if (t) {
409 if (t->handler) {
410 lock_kernel();
411 error = t->handler(fd, cmd, arg, filp);
412 unlock_kernel();
413 up_read(&ioctl32_sem);
414 } else {
415 up_read(&ioctl32_sem);
416 error = sys_ioctl(fd, cmd, arg);
418 } else {
419 up_read(&ioctl32_sem);
420 if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
421 error = siocdevprivate_ioctl(fd, cmd, arg);
422 } else {
423 static int count;
424 if (++count <= 50) {
425 char buf[10];
426 char *fn = "?";
427 char *path;
429 path = (char *)__get_free_page(GFP_KERNEL);
431 /* find the name of the device. */
432 if (path) {
433 fn = d_path(filp->f_dentry,
434 filp->f_vfsmnt, path,
435 PAGE_SIZE);
436 if (IS_ERR(fn))
437 fn = "?";
440 sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
441 if (!isprint(buf[1]))
442 sprintf(buf, "%02x", buf[1]);
443 printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
444 "cmd(%08x){%s} arg(%08x) on %s\n",
445 current->comm, current->pid,
446 (int)fd, (unsigned int)cmd, buf,
447 (unsigned int)arg, fn);
448 if (path)
449 free_page((unsigned long)path);
451 error = -EINVAL;
454 out:
455 fput(filp);
456 out2:
457 return error;
460 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
462 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
463 __get_user(kfl->l_type, &ufl->l_type) ||
464 __get_user(kfl->l_whence, &ufl->l_whence) ||
465 __get_user(kfl->l_start, &ufl->l_start) ||
466 __get_user(kfl->l_len, &ufl->l_len) ||
467 __get_user(kfl->l_pid, &ufl->l_pid))
468 return -EFAULT;
469 return 0;
472 static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
474 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
475 __put_user(kfl->l_type, &ufl->l_type) ||
476 __put_user(kfl->l_whence, &ufl->l_whence) ||
477 __put_user(kfl->l_start, &ufl->l_start) ||
478 __put_user(kfl->l_len, &ufl->l_len) ||
479 __put_user(kfl->l_pid, &ufl->l_pid))
480 return -EFAULT;
481 return 0;
484 #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
485 static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
487 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
488 __get_user(kfl->l_type, &ufl->l_type) ||
489 __get_user(kfl->l_whence, &ufl->l_whence) ||
490 __get_user(kfl->l_start, &ufl->l_start) ||
491 __get_user(kfl->l_len, &ufl->l_len) ||
492 __get_user(kfl->l_pid, &ufl->l_pid))
493 return -EFAULT;
494 return 0;
496 #endif
498 #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
499 static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
501 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
502 __put_user(kfl->l_type, &ufl->l_type) ||
503 __put_user(kfl->l_whence, &ufl->l_whence) ||
504 __put_user(kfl->l_start, &ufl->l_start) ||
505 __put_user(kfl->l_len, &ufl->l_len) ||
506 __put_user(kfl->l_pid, &ufl->l_pid))
507 return -EFAULT;
508 return 0;
510 #endif
512 asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
513 unsigned long arg)
515 mm_segment_t old_fs;
516 struct flock f;
517 long ret;
519 switch (cmd) {
520 case F_GETLK:
521 case F_SETLK:
522 case F_SETLKW:
523 ret = get_compat_flock(&f, compat_ptr(arg));
524 if (ret != 0)
525 break;
526 old_fs = get_fs();
527 set_fs(KERNEL_DS);
528 ret = sys_fcntl(fd, cmd, (unsigned long)&f);
529 set_fs(old_fs);
530 if ((cmd == F_GETLK) && (ret == 0)) {
531 /* POSIX-2001 now defines negative l_len */
532 if (f.l_len < 0) {
533 f.l_start += f.l_len;
534 f.l_len = -f.l_len;
536 if (f.l_start < 0)
537 return -EINVAL;
538 if ((f.l_start >= COMPAT_OFF_T_MAX) ||
539 ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX))
540 ret = -EOVERFLOW;
541 if (ret == 0)
542 ret = put_compat_flock(&f, compat_ptr(arg));
544 break;
546 case F_GETLK64:
547 case F_SETLK64:
548 case F_SETLKW64:
549 ret = get_compat_flock64(&f, compat_ptr(arg));
550 if (ret != 0)
551 break;
552 old_fs = get_fs();
553 set_fs(KERNEL_DS);
554 ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK :
555 ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW),
556 (unsigned long)&f);
557 set_fs(old_fs);
558 if ((cmd == F_GETLK64) && (ret == 0)) {
559 /* POSIX-2001 now defines negative l_len */
560 if (f.l_len < 0) {
561 f.l_start += f.l_len;
562 f.l_len = -f.l_len;
564 if (f.l_start < 0)
565 return -EINVAL;
566 if ((f.l_start >= COMPAT_LOFF_T_MAX) ||
567 ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX))
568 ret = -EOVERFLOW;
569 if (ret == 0)
570 ret = put_compat_flock64(&f, compat_ptr(arg));
572 break;
574 default:
575 ret = sys_fcntl(fd, cmd, arg);
576 break;
578 return ret;
581 asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
582 unsigned long arg)
584 if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
585 return -EINVAL;
586 return compat_sys_fcntl64(fd, cmd, arg);
589 asmlinkage long
590 compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
592 long ret;
593 aio_context_t ctx64;
595 mm_segment_t oldfs = get_fs();
596 if (unlikely(get_user(ctx64, ctx32p)))
597 return -EFAULT;
599 set_fs(KERNEL_DS);
600 /* The __user pointer cast is valid because of the set_fs() */
601 ret = sys_io_setup(nr_reqs, (aio_context_t __user *) &ctx64);
602 set_fs(oldfs);
603 /* truncating is ok because it's a user address */
604 if (!ret)
605 ret = put_user((u32) ctx64, ctx32p);
606 return ret;
609 asmlinkage long
610 compat_sys_io_getevents(aio_context_t ctx_id,
611 unsigned long min_nr,
612 unsigned long nr,
613 struct io_event __user *events,
614 struct compat_timespec __user *timeout)
616 long ret;
617 struct timespec t;
618 struct timespec __user *ut = NULL;
620 ret = -EFAULT;
621 if (unlikely(!access_ok(VERIFY_WRITE, events,
622 nr * sizeof(struct io_event))))
623 goto out;
624 if (timeout) {
625 if (get_compat_timespec(&t, timeout))
626 goto out;
628 ut = compat_alloc_user_space(sizeof(*ut));
629 if (copy_to_user(ut, &t, sizeof(t)) )
630 goto out;
632 ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
633 out:
634 return ret;
637 static inline long
638 copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
640 compat_uptr_t uptr;
641 int i;
643 for (i = 0; i < nr; ++i) {
644 if (get_user(uptr, ptr32 + i))
645 return -EFAULT;
646 if (put_user(compat_ptr(uptr), ptr64 + i))
647 return -EFAULT;
649 return 0;
652 #define MAX_AIO_SUBMITS (PAGE_SIZE/sizeof(struct iocb *))
654 asmlinkage long
655 compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
657 struct iocb __user * __user *iocb64;
658 long ret;
660 if (unlikely(nr < 0))
661 return -EINVAL;
663 if (nr > MAX_AIO_SUBMITS)
664 nr = MAX_AIO_SUBMITS;
666 iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
667 ret = copy_iocb(nr, iocb, iocb64);
668 if (!ret)
669 ret = sys_io_submit(ctx_id, nr, iocb64);
670 return ret;
673 struct compat_ncp_mount_data {
674 compat_int_t version;
675 compat_uint_t ncp_fd;
676 compat_uid_t mounted_uid;
677 compat_pid_t wdog_pid;
678 unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
679 compat_uint_t time_out;
680 compat_uint_t retry_count;
681 compat_uint_t flags;
682 compat_uid_t uid;
683 compat_gid_t gid;
684 compat_mode_t file_mode;
685 compat_mode_t dir_mode;
688 struct compat_ncp_mount_data_v4 {
689 compat_int_t version;
690 compat_ulong_t flags;
691 compat_ulong_t mounted_uid;
692 compat_long_t wdog_pid;
693 compat_uint_t ncp_fd;
694 compat_uint_t time_out;
695 compat_uint_t retry_count;
696 compat_ulong_t uid;
697 compat_ulong_t gid;
698 compat_ulong_t file_mode;
699 compat_ulong_t dir_mode;
702 static void *do_ncp_super_data_conv(void *raw_data)
704 int version = *(unsigned int *)raw_data;
706 if (version == 3) {
707 struct compat_ncp_mount_data *c_n = raw_data;
708 struct ncp_mount_data *n = raw_data;
710 n->dir_mode = c_n->dir_mode;
711 n->file_mode = c_n->file_mode;
712 n->gid = c_n->gid;
713 n->uid = c_n->uid;
714 memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
715 n->wdog_pid = c_n->wdog_pid;
716 n->mounted_uid = c_n->mounted_uid;
717 } else if (version == 4) {
718 struct compat_ncp_mount_data_v4 *c_n = raw_data;
719 struct ncp_mount_data_v4 *n = raw_data;
721 n->dir_mode = c_n->dir_mode;
722 n->file_mode = c_n->file_mode;
723 n->gid = c_n->gid;
724 n->uid = c_n->uid;
725 n->retry_count = c_n->retry_count;
726 n->time_out = c_n->time_out;
727 n->ncp_fd = c_n->ncp_fd;
728 n->wdog_pid = c_n->wdog_pid;
729 n->mounted_uid = c_n->mounted_uid;
730 n->flags = c_n->flags;
731 } else if (version != 5) {
732 return NULL;
735 return raw_data;
738 struct compat_smb_mount_data {
739 compat_int_t version;
740 compat_uid_t mounted_uid;
741 compat_uid_t uid;
742 compat_gid_t gid;
743 compat_mode_t file_mode;
744 compat_mode_t dir_mode;
747 static void *do_smb_super_data_conv(void *raw_data)
749 struct smb_mount_data *s = raw_data;
750 struct compat_smb_mount_data *c_s = raw_data;
752 if (c_s->version != SMB_MOUNT_OLDVERSION)
753 goto out;
754 s->dir_mode = c_s->dir_mode;
755 s->file_mode = c_s->file_mode;
756 s->gid = c_s->gid;
757 s->uid = c_s->uid;
758 s->mounted_uid = c_s->mounted_uid;
759 out:
760 return raw_data;
763 extern int copy_mount_options (const void __user *, unsigned long *);
765 #define SMBFS_NAME "smbfs"
766 #define NCPFS_NAME "ncpfs"
768 asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
769 char __user * type, unsigned long flags,
770 void __user * data)
772 unsigned long type_page;
773 unsigned long data_page;
774 unsigned long dev_page;
775 char *dir_page;
776 int retval;
778 retval = copy_mount_options (type, &type_page);
779 if (retval < 0)
780 goto out;
782 dir_page = getname(dir_name);
783 retval = PTR_ERR(dir_page);
784 if (IS_ERR(dir_page))
785 goto out1;
787 retval = copy_mount_options (dev_name, &dev_page);
788 if (retval < 0)
789 goto out2;
791 retval = copy_mount_options (data, &data_page);
792 if (retval < 0)
793 goto out3;
795 retval = -EINVAL;
797 if (type_page) {
798 if (!strcmp((char *)type_page, SMBFS_NAME)) {
799 do_smb_super_data_conv((void *)data_page);
800 } else if (!strcmp((char *)type_page, NCPFS_NAME)) {
801 do_ncp_super_data_conv((void *)data_page);
805 lock_kernel();
806 retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
807 flags, (void*)data_page);
808 unlock_kernel();
810 free_page(data_page);
811 out3:
812 free_page(dev_page);
813 out2:
814 putname(dir_page);
815 out1:
816 free_page(type_page);
817 out:
818 return retval;
821 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
822 #define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & \
823 ~(sizeof(compat_long_t)-1))
825 struct compat_old_linux_dirent {
826 compat_ulong_t d_ino;
827 compat_ulong_t d_offset;
828 unsigned short d_namlen;
829 char d_name[1];
832 struct compat_readdir_callback {
833 struct compat_old_linux_dirent __user *dirent;
834 int result;
837 static int compat_fillonedir(void *__buf, const char *name, int namlen,
838 loff_t offset, ino_t ino, unsigned int d_type)
840 struct compat_readdir_callback *buf = __buf;
841 struct compat_old_linux_dirent __user *dirent;
843 if (buf->result)
844 return -EINVAL;
845 buf->result++;
846 dirent = buf->dirent;
847 if (!access_ok(VERIFY_WRITE, dirent,
848 (unsigned long)(dirent->d_name + namlen + 1) -
849 (unsigned long)dirent))
850 goto efault;
851 if ( __put_user(ino, &dirent->d_ino) ||
852 __put_user(offset, &dirent->d_offset) ||
853 __put_user(namlen, &dirent->d_namlen) ||
854 __copy_to_user(dirent->d_name, name, namlen) ||
855 __put_user(0, dirent->d_name + namlen))
856 goto efault;
857 return 0;
858 efault:
859 buf->result = -EFAULT;
860 return -EFAULT;
863 asmlinkage long compat_old_readdir(unsigned int fd,
864 struct compat_old_linux_dirent __user *dirent, unsigned int count)
866 int error;
867 struct file *file;
868 struct compat_readdir_callback buf;
870 error = -EBADF;
871 file = fget(fd);
872 if (!file)
873 goto out;
875 buf.result = 0;
876 buf.dirent = dirent;
878 error = vfs_readdir(file, compat_fillonedir, &buf);
879 if (error >= 0)
880 error = buf.result;
882 fput(file);
883 out:
884 return error;
887 struct compat_linux_dirent {
888 compat_ulong_t d_ino;
889 compat_ulong_t d_off;
890 unsigned short d_reclen;
891 char d_name[1];
894 struct compat_getdents_callback {
895 struct compat_linux_dirent __user *current_dir;
896 struct compat_linux_dirent __user *previous;
897 int count;
898 int error;
901 static int compat_filldir(void *__buf, const char *name, int namlen,
902 loff_t offset, ino_t ino, unsigned int d_type)
904 struct compat_linux_dirent __user * dirent;
905 struct compat_getdents_callback *buf = __buf;
906 int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
908 buf->error = -EINVAL; /* only used if we fail.. */
909 if (reclen > buf->count)
910 return -EINVAL;
911 dirent = buf->previous;
912 if (dirent) {
913 if (__put_user(offset, &dirent->d_off))
914 goto efault;
916 dirent = buf->current_dir;
917 if (__put_user(ino, &dirent->d_ino))
918 goto efault;
919 if (__put_user(reclen, &dirent->d_reclen))
920 goto efault;
921 if (copy_to_user(dirent->d_name, name, namlen))
922 goto efault;
923 if (__put_user(0, dirent->d_name + namlen))
924 goto efault;
925 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
926 goto efault;
927 buf->previous = dirent;
928 dirent = (void __user *)dirent + reclen;
929 buf->current_dir = dirent;
930 buf->count -= reclen;
931 return 0;
932 efault:
933 buf->error = -EFAULT;
934 return -EFAULT;
937 asmlinkage long compat_sys_getdents(unsigned int fd,
938 struct compat_linux_dirent __user *dirent, unsigned int count)
940 struct file * file;
941 struct compat_linux_dirent __user * lastdirent;
942 struct compat_getdents_callback buf;
943 int error;
945 error = -EFAULT;
946 if (!access_ok(VERIFY_WRITE, dirent, count))
947 goto out;
949 error = -EBADF;
950 file = fget(fd);
951 if (!file)
952 goto out;
954 buf.current_dir = dirent;
955 buf.previous = NULL;
956 buf.count = count;
957 buf.error = 0;
959 error = vfs_readdir(file, compat_filldir, &buf);
960 if (error < 0)
961 goto out_putf;
962 error = buf.error;
963 lastdirent = buf.previous;
964 if (lastdirent) {
965 if (put_user(file->f_pos, &lastdirent->d_off))
966 error = -EFAULT;
967 else
968 error = count - buf.count;
971 out_putf:
972 fput(file);
973 out:
974 return error;
977 #ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
978 #define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
980 struct compat_getdents_callback64 {
981 struct linux_dirent64 __user *current_dir;
982 struct linux_dirent64 __user *previous;
983 int count;
984 int error;
987 static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
988 ino_t ino, unsigned int d_type)
990 struct linux_dirent64 __user *dirent;
991 struct compat_getdents_callback64 *buf = __buf;
992 int jj = NAME_OFFSET(dirent);
993 int reclen = COMPAT_ROUND_UP64(jj + namlen + 1);
994 u64 off;
996 buf->error = -EINVAL; /* only used if we fail.. */
997 if (reclen > buf->count)
998 return -EINVAL;
999 dirent = buf->previous;
1001 if (dirent) {
1002 if (__put_user_unaligned(offset, &dirent->d_off))
1003 goto efault;
1005 dirent = buf->current_dir;
1006 if (__put_user_unaligned(ino, &dirent->d_ino))
1007 goto efault;
1008 off = 0;
1009 if (__put_user_unaligned(off, &dirent->d_off))
1010 goto efault;
1011 if (__put_user(reclen, &dirent->d_reclen))
1012 goto efault;
1013 if (__put_user(d_type, &dirent->d_type))
1014 goto efault;
1015 if (copy_to_user(dirent->d_name, name, namlen))
1016 goto efault;
1017 if (__put_user(0, dirent->d_name + namlen))
1018 goto efault;
1019 buf->previous = dirent;
1020 dirent = (void __user *)dirent + reclen;
1021 buf->current_dir = dirent;
1022 buf->count -= reclen;
1023 return 0;
1024 efault:
1025 buf->error = -EFAULT;
1026 return -EFAULT;
1029 asmlinkage long compat_sys_getdents64(unsigned int fd,
1030 struct linux_dirent64 __user * dirent, unsigned int count)
1032 struct file * file;
1033 struct linux_dirent64 __user * lastdirent;
1034 struct compat_getdents_callback64 buf;
1035 int error;
1037 error = -EFAULT;
1038 if (!access_ok(VERIFY_WRITE, dirent, count))
1039 goto out;
1041 error = -EBADF;
1042 file = fget(fd);
1043 if (!file)
1044 goto out;
1046 buf.current_dir = dirent;
1047 buf.previous = NULL;
1048 buf.count = count;
1049 buf.error = 0;
1051 error = vfs_readdir(file, compat_filldir64, &buf);
1052 if (error < 0)
1053 goto out_putf;
1054 error = buf.error;
1055 lastdirent = buf.previous;
1056 if (lastdirent) {
1057 typeof(lastdirent->d_off) d_off = file->f_pos;
1058 __put_user_unaligned(d_off, &lastdirent->d_off);
1059 error = count - buf.count;
1062 out_putf:
1063 fput(file);
1064 out:
1065 return error;
1067 #endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
1069 static ssize_t compat_do_readv_writev(int type, struct file *file,
1070 const struct compat_iovec __user *uvector,
1071 unsigned long nr_segs, loff_t *pos)
1073 typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
1074 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
1076 compat_ssize_t tot_len;
1077 struct iovec iovstack[UIO_FASTIOV];
1078 struct iovec *iov=iovstack, *vector;
1079 ssize_t ret;
1080 int seg;
1081 io_fn_t fn;
1082 iov_fn_t fnv;
1083 struct inode *inode;
1086 * SuS says "The readv() function *may* fail if the iovcnt argument
1087 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
1088 * traditionally returned zero for zero segments, so...
1090 ret = 0;
1091 if (nr_segs == 0)
1092 goto out;
1095 * First get the "struct iovec" from user memory and
1096 * verify all the pointers
1098 ret = -EINVAL;
1099 if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
1100 goto out;
1101 if (!file->f_op)
1102 goto out;
1103 if (nr_segs > UIO_FASTIOV) {
1104 ret = -ENOMEM;
1105 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
1106 if (!iov)
1107 goto out;
1109 ret = -EFAULT;
1110 if (verify_area(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
1111 goto out;
1114 * Single unix specification:
1115 * We should -EINVAL if an element length is not >= 0 and fitting an
1116 * ssize_t. The total length is fitting an ssize_t
1118 * Be careful here because iov_len is a size_t not an ssize_t
1120 tot_len = 0;
1121 vector = iov;
1122 ret = -EINVAL;
1123 for (seg = 0 ; seg < nr_segs; seg++) {
1124 compat_ssize_t tmp = tot_len;
1125 compat_ssize_t len;
1126 compat_uptr_t buf;
1128 if (__get_user(len, &uvector->iov_len) ||
1129 __get_user(buf, &uvector->iov_base)) {
1130 ret = -EFAULT;
1131 goto out;
1133 if (len < 0) /* size_t not fitting an compat_ssize_t .. */
1134 goto out;
1135 tot_len += len;
1136 if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
1137 goto out;
1138 vector->iov_base = compat_ptr(buf);
1139 vector->iov_len = (compat_size_t) len;
1140 uvector++;
1141 vector++;
1143 if (tot_len == 0) {
1144 ret = 0;
1145 goto out;
1148 inode = file->f_dentry->d_inode;
1149 /* VERIFY_WRITE actually means a read, as we write to user space */
1150 ret = locks_verify_area((type == READ
1151 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
1152 inode, file, *pos, tot_len);
1153 if (ret)
1154 goto out;
1156 fnv = NULL;
1157 if (type == READ) {
1158 fn = file->f_op->read;
1159 fnv = file->f_op->readv;
1160 } else {
1161 fn = (io_fn_t)file->f_op->write;
1162 fnv = file->f_op->writev;
1164 if (fnv) {
1165 ret = fnv(file, iov, nr_segs, pos);
1166 goto out;
1169 /* Do it by hand, with file-ops */
1170 ret = 0;
1171 vector = iov;
1172 while (nr_segs > 0) {
1173 void __user * base;
1174 size_t len;
1175 ssize_t nr;
1177 base = vector->iov_base;
1178 len = vector->iov_len;
1179 vector++;
1180 nr_segs--;
1182 nr = fn(file, base, len, pos);
1184 if (nr < 0) {
1185 if (!ret) ret = nr;
1186 break;
1188 ret += nr;
1189 if (nr != len)
1190 break;
1192 out:
1193 if (iov != iovstack)
1194 kfree(iov);
1195 if ((ret + (type == READ)) > 0)
1196 dnotify_parent(file->f_dentry,
1197 (type == READ) ? DN_ACCESS : DN_MODIFY);
1198 return ret;
1201 asmlinkage ssize_t
1202 compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1204 struct file *file;
1205 ssize_t ret = -EBADF;
1207 file = fget(fd);
1208 if (!file)
1209 return -EBADF;
1211 if (!(file->f_mode & FMODE_READ))
1212 goto out;
1214 ret = -EINVAL;
1215 if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
1216 goto out;
1218 ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
1220 out:
1221 fput(file);
1222 return ret;
1225 asmlinkage ssize_t
1226 compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1228 struct file *file;
1229 ssize_t ret = -EBADF;
1231 file = fget(fd);
1232 if (!file)
1233 return -EBADF;
1234 if (!(file->f_mode & FMODE_WRITE))
1235 goto out;
1237 ret = -EINVAL;
1238 if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
1239 goto out;
1241 ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
1243 out:
1244 fput(file);
1245 return ret;
1249 * compat_count() counts the number of arguments/envelopes. It is basically
1250 * a copy of count() from fs/exec.c, except that it works with 32 bit argv
1251 * and envp pointers.
1253 static int compat_count(compat_uptr_t __user *argv, int max)
1255 int i = 0;
1257 if (argv != NULL) {
1258 for (;;) {
1259 compat_uptr_t p;
1261 if (get_user(p, argv))
1262 return -EFAULT;
1263 if (!p)
1264 break;
1265 argv++;
1266 if(++i > max)
1267 return -E2BIG;
1270 return i;
1274 * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
1275 * except that it works with 32 bit argv and envp pointers.
1277 static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
1278 struct linux_binprm *bprm)
1280 struct page *kmapped_page = NULL;
1281 char *kaddr = NULL;
1282 int ret;
1284 while (argc-- > 0) {
1285 compat_uptr_t str;
1286 int len;
1287 unsigned long pos;
1289 if (get_user(str, argv+argc) ||
1290 !(len = strnlen_user(compat_ptr(str), bprm->p))) {
1291 ret = -EFAULT;
1292 goto out;
1295 if (bprm->p < len) {
1296 ret = -E2BIG;
1297 goto out;
1300 bprm->p -= len;
1301 /* XXX: add architecture specific overflow check here. */
1302 pos = bprm->p;
1304 while (len > 0) {
1305 int i, new, err;
1306 int offset, bytes_to_copy;
1307 struct page *page;
1309 offset = pos % PAGE_SIZE;
1310 i = pos/PAGE_SIZE;
1311 page = bprm->page[i];
1312 new = 0;
1313 if (!page) {
1314 page = alloc_page(GFP_HIGHUSER);
1315 bprm->page[i] = page;
1316 if (!page) {
1317 ret = -ENOMEM;
1318 goto out;
1320 new = 1;
1323 if (page != kmapped_page) {
1324 if (kmapped_page)
1325 kunmap(kmapped_page);
1326 kmapped_page = page;
1327 kaddr = kmap(kmapped_page);
1329 if (new && offset)
1330 memset(kaddr, 0, offset);
1331 bytes_to_copy = PAGE_SIZE - offset;
1332 if (bytes_to_copy > len) {
1333 bytes_to_copy = len;
1334 if (new)
1335 memset(kaddr+offset+len, 0,
1336 PAGE_SIZE-offset-len);
1338 err = copy_from_user(kaddr+offset, compat_ptr(str),
1339 bytes_to_copy);
1340 if (err) {
1341 ret = -EFAULT;
1342 goto out;
1345 pos += bytes_to_copy;
1346 str += bytes_to_copy;
1347 len -= bytes_to_copy;
1350 ret = 0;
1351 out:
1352 if (kmapped_page)
1353 kunmap(kmapped_page);
1354 return ret;
1357 #ifdef CONFIG_MMU
1359 #define free_arg_pages(bprm) do { } while (0)
1361 #else
1363 static inline void free_arg_pages(struct linux_binprm *bprm)
1365 int i;
1367 for (i = 0; i < MAX_ARG_PAGES; i++) {
1368 if (bprm->page[i])
1369 __free_page(bprm->page[i]);
1370 bprm->page[i] = NULL;
1374 #endif /* CONFIG_MMU */
1377 * compat_do_execve() is mostly a copy of do_execve(), with the exception
1378 * that it processes 32 bit argv and envp pointers.
1380 int compat_do_execve(char * filename,
1381 compat_uptr_t __user *argv,
1382 compat_uptr_t __user *envp,
1383 struct pt_regs * regs)
1385 struct linux_binprm *bprm;
1386 struct file *file;
1387 int retval;
1388 int i;
1390 file = open_exec(filename);
1392 retval = PTR_ERR(file);
1393 if (IS_ERR(file))
1394 return retval;
1396 sched_exec();
1398 retval = -ENOMEM;
1399 bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
1400 if (!bprm)
1401 goto out_ret;
1402 memset(bprm, 0, sizeof(*bprm));
1404 bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
1405 bprm->file = file;
1406 bprm->filename = filename;
1407 bprm->interp = filename;
1408 bprm->mm = mm_alloc();
1409 if (!bprm->mm)
1410 goto out_file;
1412 retval = init_new_context(current, bprm->mm);
1413 if (retval < 0)
1414 goto out_mm;
1416 bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t));
1417 if ((retval = bprm->argc) < 0)
1418 goto out_mm;
1420 bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t));
1421 if ((retval = bprm->envc) < 0)
1422 goto out_mm;
1424 retval = security_bprm_alloc(bprm);
1425 if (retval)
1426 goto out;
1428 retval = prepare_binprm(bprm);
1429 if (retval < 0)
1430 goto out;
1432 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1433 if (retval < 0)
1434 goto out;
1436 bprm->exec = bprm->p;
1437 retval = compat_copy_strings(bprm->envc, envp, bprm);
1438 if (retval < 0)
1439 goto out;
1441 retval = compat_copy_strings(bprm->argc, argv, bprm);
1442 if (retval < 0)
1443 goto out;
1445 retval = search_binary_handler(bprm, regs);
1446 if (retval >= 0) {
1447 free_arg_pages(bprm);
1449 /* execve success */
1450 security_bprm_free(bprm);
1451 kfree(bprm);
1452 return retval;
1455 out:
1456 /* Something went wrong, return the inode and free the argument pages*/
1457 for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
1458 struct page * page = bprm->page[i];
1459 if (page)
1460 __free_page(page);
1463 if (bprm->security)
1464 security_bprm_free(bprm);
1466 out_mm:
1467 if (bprm->mm)
1468 mmdrop(bprm->mm);
1470 out_file:
1471 if (bprm->file) {
1472 allow_write_access(bprm->file);
1473 fput(bprm->file);
1475 kfree(bprm);
1477 out_ret:
1478 return retval;
1481 #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
1483 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
1486 * Ooo, nasty. We need here to frob 32-bit unsigned longs to
1487 * 64-bit unsigned longs.
1489 static inline
1490 int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1491 unsigned long *fdset)
1493 nr = ROUND_UP(nr, __COMPAT_NFDBITS);
1494 if (ufdset) {
1495 unsigned long odd;
1497 if (verify_area(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
1498 return -EFAULT;
1500 odd = nr & 1UL;
1501 nr &= ~1UL;
1502 while (nr) {
1503 unsigned long h, l;
1504 __get_user(l, ufdset);
1505 __get_user(h, ufdset+1);
1506 ufdset += 2;
1507 *fdset++ = h << 32 | l;
1508 nr -= 2;
1510 if (odd)
1511 __get_user(*fdset, ufdset);
1512 } else {
1513 /* Tricky, must clear full unsigned long in the
1514 * kernel fdset at the end, this makes sure that
1515 * actually happens.
1517 memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
1519 return 0;
1522 static inline
1523 void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1524 unsigned long *fdset)
1526 unsigned long odd;
1527 nr = ROUND_UP(nr, __COMPAT_NFDBITS);
1529 if (!ufdset)
1530 return;
1532 odd = nr & 1UL;
1533 nr &= ~1UL;
1534 while (nr) {
1535 unsigned long h, l;
1536 l = *fdset++;
1537 h = l >> 32;
1538 __put_user(l, ufdset);
1539 __put_user(h, ufdset+1);
1540 ufdset += 2;
1541 nr -= 2;
1543 if (odd)
1544 __put_user(*fdset, ufdset);
1549 * This is a virtual copy of sys_select from fs/select.c and probably
1550 * should be compared to it from time to time
1552 static void *select_bits_alloc(int size)
1554 return kmalloc(6 * size, GFP_KERNEL);
1557 static void select_bits_free(void *bits, int size)
1559 kfree(bits);
1563 * We can actually return ERESTARTSYS instead of EINTR, but I'd
1564 * like to be certain this leads to no problems. So I return
1565 * EINTR just for safety.
1567 * Update: ERESTARTSYS breaks at least the xview clock binary, so
1568 * I'm trying ERESTARTNOHAND which restart only when you want to.
1570 #define MAX_SELECT_SECONDS \
1571 ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
1573 asmlinkage long
1574 compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
1575 compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
1577 fd_set_bits fds;
1578 char *bits;
1579 long timeout;
1580 int ret, size, max_fdset;
1582 timeout = MAX_SCHEDULE_TIMEOUT;
1583 if (tvp) {
1584 time_t sec, usec;
1586 if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
1587 || (ret = __get_user(sec, &tvp->tv_sec))
1588 || (ret = __get_user(usec, &tvp->tv_usec)))
1589 goto out_nofds;
1591 ret = -EINVAL;
1592 if (sec < 0 || usec < 0)
1593 goto out_nofds;
1595 if ((unsigned long) sec < MAX_SELECT_SECONDS) {
1596 timeout = ROUND_UP(usec, 1000000/HZ);
1597 timeout += sec * (unsigned long) HZ;
1601 ret = -EINVAL;
1602 if (n < 0)
1603 goto out_nofds;
1605 /* max_fdset can increase, so grab it once to avoid race */
1606 max_fdset = current->files->max_fdset;
1607 if (n > max_fdset)
1608 n = max_fdset;
1611 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
1612 * since we used fdset we need to allocate memory in units of
1613 * long-words.
1615 ret = -ENOMEM;
1616 size = FDS_BYTES(n);
1617 bits = select_bits_alloc(size);
1618 if (!bits)
1619 goto out_nofds;
1620 fds.in = (unsigned long *) bits;
1621 fds.out = (unsigned long *) (bits + size);
1622 fds.ex = (unsigned long *) (bits + 2*size);
1623 fds.res_in = (unsigned long *) (bits + 3*size);
1624 fds.res_out = (unsigned long *) (bits + 4*size);
1625 fds.res_ex = (unsigned long *) (bits + 5*size);
1627 if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
1628 (ret = compat_get_fd_set(n, outp, fds.out)) ||
1629 (ret = compat_get_fd_set(n, exp, fds.ex)))
1630 goto out;
1631 zero_fd_set(n, fds.res_in);
1632 zero_fd_set(n, fds.res_out);
1633 zero_fd_set(n, fds.res_ex);
1635 ret = do_select(n, &fds, &timeout);
1637 if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
1638 time_t sec = 0, usec = 0;
1639 if (timeout) {
1640 sec = timeout / HZ;
1641 usec = timeout % HZ;
1642 usec *= (1000000/HZ);
1644 if (put_user(sec, &tvp->tv_sec) ||
1645 put_user(usec, &tvp->tv_usec))
1646 ret = -EFAULT;
1649 if (ret < 0)
1650 goto out;
1651 if (!ret) {
1652 ret = -ERESTARTNOHAND;
1653 if (signal_pending(current))
1654 goto out;
1655 ret = 0;
1658 compat_set_fd_set(n, inp, fds.res_in);
1659 compat_set_fd_set(n, outp, fds.res_out);
1660 compat_set_fd_set(n, exp, fds.res_ex);
1662 out:
1663 select_bits_free(bits, size);
1664 out_nofds:
1665 return ret;
1668 #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
1669 /* Stuff for NFS server syscalls... */
1670 struct compat_nfsctl_svc {
1671 u16 svc32_port;
1672 s32 svc32_nthreads;
1675 struct compat_nfsctl_client {
1676 s8 cl32_ident[NFSCLNT_IDMAX+1];
1677 s32 cl32_naddr;
1678 struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX];
1679 s32 cl32_fhkeytype;
1680 s32 cl32_fhkeylen;
1681 u8 cl32_fhkey[NFSCLNT_KEYMAX];
1684 struct compat_nfsctl_export {
1685 char ex32_client[NFSCLNT_IDMAX+1];
1686 char ex32_path[NFS_MAXPATHLEN+1];
1687 compat_dev_t ex32_dev;
1688 compat_ino_t ex32_ino;
1689 compat_int_t ex32_flags;
1690 compat_uid_t ex32_anon_uid;
1691 compat_gid_t ex32_anon_gid;
1694 struct compat_nfsctl_fdparm {
1695 struct sockaddr gd32_addr;
1696 s8 gd32_path[NFS_MAXPATHLEN+1];
1697 compat_int_t gd32_version;
1700 struct compat_nfsctl_fsparm {
1701 struct sockaddr gd32_addr;
1702 s8 gd32_path[NFS_MAXPATHLEN+1];
1703 compat_int_t gd32_maxlen;
1706 struct compat_nfsctl_arg {
1707 compat_int_t ca32_version; /* safeguard */
1708 union {
1709 struct compat_nfsctl_svc u32_svc;
1710 struct compat_nfsctl_client u32_client;
1711 struct compat_nfsctl_export u32_export;
1712 struct compat_nfsctl_fdparm u32_getfd;
1713 struct compat_nfsctl_fsparm u32_getfs;
1714 } u;
1715 #define ca32_svc u.u32_svc
1716 #define ca32_client u.u32_client
1717 #define ca32_export u.u32_export
1718 #define ca32_getfd u.u32_getfd
1719 #define ca32_getfs u.u32_getfs
1722 union compat_nfsctl_res {
1723 __u8 cr32_getfh[NFS_FHSIZE];
1724 struct knfsd_fh cr32_getfs;
1727 static int compat_nfs_svc_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg)
1729 int err;
1731 err = access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc));
1732 err |= get_user(karg->ca_version, &arg->ca32_version);
1733 err |= __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port);
1734 err |= __get_user(karg->ca_svc.svc_nthreads, &arg->ca32_svc.svc32_nthreads);
1735 return (err) ? -EFAULT : 0;
1738 static int compat_nfs_clnt_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg)
1740 int err;
1742 err = access_ok(VERIFY_READ, &arg->ca32_client, sizeof(arg->ca32_client));
1743 err |= get_user(karg->ca_version, &arg->ca32_version);
1744 err |= __copy_from_user(&karg->ca_client.cl_ident[0],
1745 &arg->ca32_client.cl32_ident[0],
1746 NFSCLNT_IDMAX);
1747 err |= __get_user(karg->ca_client.cl_naddr, &arg->ca32_client.cl32_naddr);
1748 err |= __copy_from_user(&karg->ca_client.cl_addrlist[0],
1749 &arg->ca32_client.cl32_addrlist[0],
1750 (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
1751 err |= __get_user(karg->ca_client.cl_fhkeytype,
1752 &arg->ca32_client.cl32_fhkeytype);
1753 err |= __get_user(karg->ca_client.cl_fhkeylen,
1754 &arg->ca32_client.cl32_fhkeylen);
1755 err |= __copy_from_user(&karg->ca_client.cl_fhkey[0],
1756 &arg->ca32_client.cl32_fhkey[0],
1757 NFSCLNT_KEYMAX);
1759 return (err) ? -EFAULT : 0;
1762 static int compat_nfs_exp_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg)
1764 int err;
1766 err = access_ok(VERIFY_READ, &arg->ca32_export, sizeof(arg->ca32_export));
1767 err |= get_user(karg->ca_version, &arg->ca32_version);
1768 err |= __copy_from_user(&karg->ca_export.ex_client[0],
1769 &arg->ca32_export.ex32_client[0],
1770 NFSCLNT_IDMAX);
1771 err |= __copy_from_user(&karg->ca_export.ex_path[0],
1772 &arg->ca32_export.ex32_path[0],
1773 NFS_MAXPATHLEN);
1774 err |= __get_user(karg->ca_export.ex_dev,
1775 &arg->ca32_export.ex32_dev);
1776 err |= __get_user(karg->ca_export.ex_ino,
1777 &arg->ca32_export.ex32_ino);
1778 err |= __get_user(karg->ca_export.ex_flags,
1779 &arg->ca32_export.ex32_flags);
1780 err |= __get_user(karg->ca_export.ex_anon_uid,
1781 &arg->ca32_export.ex32_anon_uid);
1782 err |= __get_user(karg->ca_export.ex_anon_gid,
1783 &arg->ca32_export.ex32_anon_gid);
1784 SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
1785 SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
1787 return (err) ? -EFAULT : 0;
1790 static int compat_nfs_getfd_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg)
1792 int err;
1794 err = access_ok(VERIFY_READ, &arg->ca32_getfd, sizeof(arg->ca32_getfd));
1795 err |= get_user(karg->ca_version, &arg->ca32_version);
1796 err |= __copy_from_user(&karg->ca_getfd.gd_addr,
1797 &arg->ca32_getfd.gd32_addr,
1798 (sizeof(struct sockaddr)));
1799 err |= __copy_from_user(&karg->ca_getfd.gd_path,
1800 &arg->ca32_getfd.gd32_path,
1801 (NFS_MAXPATHLEN+1));
1802 err |= __get_user(karg->ca_getfd.gd_version,
1803 &arg->ca32_getfd.gd32_version);
1805 return (err) ? -EFAULT : 0;
1808 static int compat_nfs_getfs_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg __user *arg)
1810 int err;
1812 err = access_ok(VERIFY_READ, &arg->ca32_getfs, sizeof(arg->ca32_getfs));
1813 err |= get_user(karg->ca_version, &arg->ca32_version);
1814 err |= __copy_from_user(&karg->ca_getfs.gd_addr,
1815 &arg->ca32_getfs.gd32_addr,
1816 (sizeof(struct sockaddr)));
1817 err |= __copy_from_user(&karg->ca_getfs.gd_path,
1818 &arg->ca32_getfs.gd32_path,
1819 (NFS_MAXPATHLEN+1));
1820 err |= __get_user(karg->ca_getfs.gd_maxlen,
1821 &arg->ca32_getfs.gd32_maxlen);
1823 return (err) ? -EFAULT : 0;
1826 /* This really doesn't need translations, we are only passing
1827 * back a union which contains opaque nfs file handle data.
1829 static int compat_nfs_getfh_res_trans(union nfsctl_res *kres, union compat_nfsctl_res __user *res)
1831 int err;
1833 err = copy_to_user(res, kres, sizeof(*res));
1835 return (err) ? -EFAULT : 0;
1838 asmlinkage long compat_sys_nfsservctl(int cmd, struct compat_nfsctl_arg __user *arg,
1839 union compat_nfsctl_res __user *res)
1841 struct nfsctl_arg *karg;
1842 union nfsctl_res *kres;
1843 mm_segment_t oldfs;
1844 int err;
1846 karg = kmalloc(sizeof(*karg), GFP_USER);
1847 kres = kmalloc(sizeof(*kres), GFP_USER);
1848 if(!karg || !kres) {
1849 err = -ENOMEM;
1850 goto done;
1853 switch(cmd) {
1854 case NFSCTL_SVC:
1855 err = compat_nfs_svc_trans(karg, arg);
1856 break;
1858 case NFSCTL_ADDCLIENT:
1859 err = compat_nfs_clnt_trans(karg, arg);
1860 break;
1862 case NFSCTL_DELCLIENT:
1863 err = compat_nfs_clnt_trans(karg, arg);
1864 break;
1866 case NFSCTL_EXPORT:
1867 case NFSCTL_UNEXPORT:
1868 err = compat_nfs_exp_trans(karg, arg);
1869 break;
1871 case NFSCTL_GETFD:
1872 err = compat_nfs_getfd_trans(karg, arg);
1873 break;
1875 case NFSCTL_GETFS:
1876 err = compat_nfs_getfs_trans(karg, arg);
1877 break;
1879 default:
1880 err = -EINVAL;
1881 goto done;
1884 oldfs = get_fs();
1885 set_fs(KERNEL_DS);
1886 /* The __user pointer casts are valid because of the set_fs() */
1887 err = sys_nfsservctl(cmd, (void __user *) karg, (void __user *) kres);
1888 set_fs(oldfs);
1890 if (err)
1891 goto done;
1893 if((cmd == NFSCTL_GETFD) ||
1894 (cmd == NFSCTL_GETFS))
1895 err = compat_nfs_getfh_res_trans(kres, res);
1897 done:
1898 kfree(karg);
1899 kfree(kres);
1900 return err;
1902 #else /* !NFSD */
1903 long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
1905 return sys_ni_syscall();
1907 #endif