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/smb.h>
31#include <linux/smb_mount.h>
32#include <linux/ncp_mount.h>
33#include <linux/nfs4_mount.h>
34#include <linux/smp_lock.h>
35#include <linux/syscalls.h>
36#include <linux/ctype.h>
37#include <linux/module.h>
38#include <linux/dirent.h>
39#include <linux/dnotify.h>
40#include <linux/highuid.h>
41#include <linux/sunrpc/svc.h>
42#include <linux/nfsd/nfsd.h>
43#include <linux/nfsd/syscall.h>
44#include <linux/personality.h>
45#include <linux/rwsem.h>
46
47#include <net/sock.h>
48
49#include <asm/uaccess.h>
50#include <asm/mmu_context.h>
51
52
53
54
55
56asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
57{
58 struct timeval tv[2];
59
60 if (t) {
61 if (get_user(tv[0].tv_sec, &t->actime) ||
62 get_user(tv[1].tv_sec, &t->modtime))
63 return -EFAULT;
64 tv[0].tv_usec = 0;
65 tv[1].tv_usec = 0;
66 }
67 return do_utimes(filename, t ? tv : NULL);
68}
69
70asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
71{
72 struct timeval tv[2];
73
74 if (t) {
75 if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
76 get_user(tv[0].tv_usec, &t[0].tv_usec) ||
77 get_user(tv[1].tv_sec, &t[1].tv_sec) ||
78 get_user(tv[1].tv_usec, &t[1].tv_usec))
79 return -EFAULT;
80 }
81 return do_utimes(filename, t ? tv : NULL);
82}
83
84asmlinkage long compat_sys_newstat(char __user * filename,
85 struct compat_stat __user *statbuf)
86{
87 struct kstat64 stat;
88 int error = vfs_stat64(filename, &stat);
89
90 if (!error)
91 error = cp_compat_stat(&stat, statbuf);
92 return error;
93}
94
95asmlinkage long compat_sys_newlstat(char __user * filename,
96 struct compat_stat __user *statbuf)
97{
98 struct kstat64 stat;
99 int error = vfs_lstat64(filename, &stat);
100
101 if (!error)
102 error = cp_compat_stat(&stat, statbuf);
103 return error;
104}
105
106asmlinkage long compat_sys_newfstat(unsigned int fd,
107 struct compat_stat __user * statbuf)
108{
109 struct kstat64 stat;
110 int error = vfs_fstat64(fd, &stat);
111
112 if (!error)
113 error = cp_compat_stat(&stat, statbuf);
114 return error;
115}
116
117static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
118{
119
120 if (sizeof ubuf->f_blocks == 4) {
121 if ((kbuf->f_blocks | kbuf->f_bfree |
122 kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
123 0xffffffff00000000ULL)
124 return -EOVERFLOW;
125 }
126 if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
127 __put_user(kbuf->f_type, &ubuf->f_type) ||
128 __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
129 __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
130 __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
131 __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
132 __put_user(kbuf->f_files, &ubuf->f_files) ||
133 __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
134 __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
135 __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
136 __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
137 __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
138 __put_user(0, &ubuf->f_spare[0]) ||
139 __put_user(0, &ubuf->f_spare[1]) ||
140 __put_user(0, &ubuf->f_spare[2]) ||
141 __put_user(0, &ubuf->f_spare[3]) ||
142 __put_user(0, &ubuf->f_spare[4]))
143 return -EFAULT;
144 return 0;
145}
146
147
148
149
150
151asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf)
152{
153 struct nameidata nd;
154 int error;
155
156 error = user_path_walk(path, &nd);
157 if (!error) {
158 struct kstatfs tmp;
159 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
160 if (!error && put_compat_statfs(buf, &tmp))
161 error = -EFAULT;
162 path_release(&nd);
163 }
164 return error;
165}
166
167asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
168{
169 struct file * file;
170 struct kstatfs tmp;
171 int error;
172
173 error = -EBADF;
174 file = fget(fd);
175 if (!file)
176 goto out;
177 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
178 if (!error && put_compat_statfs(buf, &tmp))
179 error = -EFAULT;
180 fput(file);
181out:
182 return error;
183}
184
185static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
186{
187 if (sizeof ubuf->f_blocks == 4) {
188 if ((kbuf->f_blocks | kbuf->f_bfree |
189 kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
190 0xffffffff00000000ULL)
191 return -EOVERFLOW;
192 }
193 if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
194 __put_user(kbuf->f_type, &ubuf->f_type) ||
195 __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
196 __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
197 __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
198 __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
199 __put_user(kbuf->f_files, &ubuf->f_files) ||
200 __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
201 __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
202 __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
203 __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
204 __put_user(kbuf->f_frsize, &ubuf->f_frsize))
205 return -EFAULT;
206 return 0;
207}
208
209asmlinkage long compat_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf)
210{
211 struct nameidata nd;
212 int error;
213
214 if (sz != sizeof(*buf))
215 return -EINVAL;
216
217 error = user_path_walk(path, &nd);
218 if (!error) {
219 struct kstatfs tmp;
220 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
221 if (!error && put_compat_statfs64(buf, &tmp))
222 error = -EFAULT;
223 path_release(&nd);
224 }
225 return error;
226}
227
228asmlinkage long compat_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
229{
230 struct file * file;
231 struct kstatfs tmp;
232 int error;
233
234 if (sz != sizeof(*buf))
235 return -EINVAL;
236
237 error = -EBADF;
238 file = fget(fd);
239 if (!file)
240 goto out;
241 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
242 if (!error && put_compat_statfs64(buf, &tmp))
243 error = -EFAULT;
244 fput(file);
245out:
246 return error;
247}
248
249
250
251#define IOCTL_HASHSIZE 256
252static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
253static DECLARE_RWSEM(ioctl32_sem);
254
255extern struct ioctl_trans ioctl_start[];
256extern int ioctl_table_size;
257
258static inline unsigned long ioctl32_hash(unsigned long cmd)
259{
260 return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
261}
262
263static void ioctl32_insert_translation(struct ioctl_trans *trans)
264{
265 unsigned long hash;
266 struct ioctl_trans *t;
267
268 init_rwsem(&trans->inuse);
269
270 hash = ioctl32_hash (trans->cmd);
271 if (!ioctl32_hash_table[hash])
272 ioctl32_hash_table[hash] = trans;
273 else {
274 t = ioctl32_hash_table[hash];
275 while (t->next)
276 t = t->next;
277 trans->next = NULL;
278 t->next = trans;
279 }
280}
281
282static int __init init_sys32_ioctl(void)
283{
284 int i;
285
286 for (i = 0; i < ioctl_table_size; i++) {
287 if (ioctl_start[i].next != 0) {
288 printk("ioctl translation %d bad\n",i);
289 return -1;
290 }
291
292 ioctl32_insert_translation(&ioctl_start[i]);
293 }
294 return 0;
295}
296
297__initcall(init_sys32_ioctl);
298
299int register_ioctl32_conversion(unsigned int cmd,
300 ioctl_trans_handler_t handler)
301{
302 struct ioctl_trans *t;
303 struct ioctl_trans *new_t;
304 unsigned long hash = ioctl32_hash(cmd);
305
306 new_t = kmalloc(sizeof(*new_t), GFP_KERNEL);
307 if (!new_t)
308 return -ENOMEM;
309
310 down_write(&ioctl32_sem);
311 for (t = ioctl32_hash_table[hash]; t; t = t->next) {
312 if (t->cmd == cmd) {
313 printk(KERN_ERR "Trying to register duplicated ioctl32 "
314 "handler %x\n", cmd);
315 up_write(&ioctl32_sem);
316 kfree(new_t);
317 return -EINVAL;
318 }
319 }
320 new_t->next = NULL;
321 new_t->cmd = cmd;
322 new_t->handler = handler;
323 ioctl32_insert_translation(new_t);
324
325 up_write(&ioctl32_sem);
326 return 0;
327}
328EXPORT_SYMBOL(register_ioctl32_conversion);
329
330static inline int builtin_ioctl(struct ioctl_trans *t)
331{
332 return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
333}
334
335
336
337
338
339
340int unregister_ioctl32_conversion(unsigned int cmd)
341{
342 unsigned long hash = ioctl32_hash(cmd);
343 struct ioctl_trans **pt, *t;
344
345 down_write(&ioctl32_sem);
346 for (pt = ioctl32_hash_table + hash; (t = *pt) != NULL; pt = &t->next) {
347 if (t->cmd != cmd)
348 continue;
349 if (builtin_ioctl(t)) {
350 printk(KERN_ERR "%p tried to unregister builtin ioctl %x\n",
351 __builtin_return_address(0), cmd);
352 goto out;
353 }
354
355 *pt = t->next;
356 up_write(&ioctl32_sem);
357
358 down_write(&t->inuse);
359 up_write(&t->inuse);
360 kfree(t);
361
362 return 0;
363 }
364 printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd);
365out:
366 up_write(&ioctl32_sem);
367 return -EINVAL;
368}
369EXPORT_SYMBOL(unregister_ioctl32_conversion);
370
371asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
372 unsigned long arg)
373{
374 struct file * filp;
375 int error = -EBADF;
376 struct ioctl_trans *t;
377
378 filp = fget(fd);
379 if(!filp)
380 goto out2;
381
382 if (!filp->f_op || !filp->f_op->ioctl) {
383 error = sys_ioctl (fd, cmd, arg);
384 goto out;
385 }
386
387 down_read(&ioctl32_sem);
388
389 t = ioctl32_hash_table[ioctl32_hash (cmd)];
390
391 while (t && t->cmd != cmd)
392 t = t->next;
393 if (t) {
394 if (t->handler) {
395 down_read(&t->inuse);
396 up_read(&ioctl32_sem);
397 lock_kernel();
398 error = t->handler(fd, cmd, arg, filp);
399 unlock_kernel();
400 up_read(&t->inuse);
401 } else {
402 up_read(&ioctl32_sem);
403 error = sys_ioctl(fd, cmd, arg);
404 }
405 } else {
406 up_read(&ioctl32_sem);
407 if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
408 error = siocdevprivate_ioctl(fd, cmd, arg);
409 } else {
410 static int count;
411 if (++count <= 50) {
412 char buf[10];
413 char *fn = "?";
414 char *path;
415
416 path = (char *)__get_free_page(GFP_KERNEL);
417
418
419 if (path) {
420 fn = d_path(filp->f_dentry,
421 filp->f_vfsmnt, path,
422 PAGE_SIZE);
423 if (IS_ERR(fn))
424 fn = "?";
425 }
426
427 sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
428 if (!isprint(buf[1]))
429 sprintf(buf, "%02x", buf[1]);
430 printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
431 "cmd(%08x){%s} arg(%08x) on %s\n",
432 current->comm, current->pid,
433 (int)fd, (unsigned int)cmd, buf,
434 (unsigned int)arg, fn);
435 if (path)
436 free_page((unsigned long)path);
437 }
438 error = -EINVAL;
439 }
440 }
441out:
442 fput(filp);
443out2:
444 return error;
445}
446
447static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
448{
449 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
450 __get_user(kfl->l_type, &ufl->l_type) ||
451 __get_user(kfl->l_whence, &ufl->l_whence) ||
452 __get_user(kfl->l_start, &ufl->l_start) ||
453 __get_user(kfl->l_len, &ufl->l_len) ||
454 __get_user(kfl->l_pid, &ufl->l_pid))
455 return -EFAULT;
456 return 0;
457}
458
459static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
460{
461 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
462 __put_user(kfl->l_type, &ufl->l_type) ||
463 __put_user(kfl->l_whence, &ufl->l_whence) ||
464 __put_user(kfl->l_start, &ufl->l_start) ||
465 __put_user(kfl->l_len, &ufl->l_len) ||
466 __put_user(kfl->l_pid, &ufl->l_pid))
467 return -EFAULT;
468 return 0;
469}
470
471#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
472static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
473{
474 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
475 __get_user(kfl->l_type, &ufl->l_type) ||
476 __get_user(kfl->l_whence, &ufl->l_whence) ||
477 __get_user(kfl->l_start, &ufl->l_start) ||
478 __get_user(kfl->l_len, &ufl->l_len) ||
479 __get_user(kfl->l_pid, &ufl->l_pid))
480 return -EFAULT;
481 return 0;
482}
483#endif
484
485#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
486static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
487{
488 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
489 __put_user(kfl->l_type, &ufl->l_type) ||
490 __put_user(kfl->l_whence, &ufl->l_whence) ||
491 __put_user(kfl->l_start, &ufl->l_start) ||
492 __put_user(kfl->l_len, &ufl->l_len) ||
493 __put_user(kfl->l_pid, &ufl->l_pid))
494 return -EFAULT;
495 return 0;
496}
497#endif
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 ((compat_off_t) f.l_start != f.l_start ||
519 (compat_off_t) f.l_len != f.l_len)
520 ret = -EOVERFLOW;
521 else
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 ((compat_loff_t) f.l_start != f.l_start ||
540 (compat_loff_t) f.l_len != f.l_len)
541 ret = -EOVERFLOW;
542 else
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
562asmlinkage long
563compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
564{
565 long ret;
566 aio_context_t ctx64;
567
568 mm_segment_t oldfs = get_fs();
569 if (unlikely(get_user(ctx64, ctx32p)))
570 return -EFAULT;
571
572 set_fs(KERNEL_DS);
573
574 ret = sys_io_setup(nr_reqs, (aio_context_t __user *) &ctx64);
575 set_fs(oldfs);
576
577 if (!ret)
578 ret = put_user((u32) ctx64, ctx32p);
579 return ret;
580}
581
582asmlinkage long
583compat_sys_io_getevents(aio_context_t ctx_id,
584 unsigned long min_nr,
585 unsigned long nr,
586 struct io_event __user *events,
587 struct compat_timespec __user *timeout)
588{
589 long ret;
590 struct timespec t;
591 struct timespec __user *ut = NULL;
592
593 ret = -EFAULT;
594 if (unlikely(!access_ok(VERIFY_WRITE, events,
595 nr * sizeof(struct io_event))))
596 goto out;
597 if (timeout) {
598 if (get_compat_timespec(&t, timeout))
599 goto out;
600
601 ut = compat_alloc_user_space(sizeof(*ut));
602 if (copy_to_user(ut, &t, sizeof(t)) )
603 goto out;
604 }
605 ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
606out:
607 return ret;
608}
609
610static inline long
611copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
612{
613 compat_uptr_t uptr;
614 int i;
615
616 for (i = 0; i < nr; ++i) {
617 if (get_user(uptr, ptr32 + i))
618 return -EFAULT;
619 if (put_user(compat_ptr(uptr), ptr64 + i))
620 return -EFAULT;
621 }
622 return 0;
623}
624
625#define MAX_AIO_SUBMITS (PAGE_SIZE/sizeof(struct iocb *))
626
627asmlinkage long
628compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
629{
630 struct iocb __user * __user *iocb64;
631 long ret;
632
633 if (unlikely(nr < 0))
634 return -EINVAL;
635
636 if (nr > MAX_AIO_SUBMITS)
637 nr = MAX_AIO_SUBMITS;
638
639 iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
640 ret = copy_iocb(nr, iocb, iocb64);
641 if (!ret)
642 ret = sys_io_submit(ctx_id, nr, iocb64);
643 return ret;
644}
645
646struct compat_ncp_mount_data {
647 compat_int_t version;
648 compat_uint_t ncp_fd;
649 compat_uid_t mounted_uid;
650 compat_pid_t wdog_pid;
651 unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
652 compat_uint_t time_out;
653 compat_uint_t retry_count;
654 compat_uint_t flags;
655 compat_uid_t uid;
656 compat_gid_t gid;
657 compat_mode_t file_mode;
658 compat_mode_t dir_mode;
659};
660
661struct compat_ncp_mount_data_v4 {
662 compat_int_t version;
663 compat_ulong_t flags;
664 compat_ulong_t mounted_uid;
665 compat_long_t wdog_pid;
666 compat_uint_t ncp_fd;
667 compat_uint_t time_out;
668 compat_uint_t retry_count;
669 compat_ulong_t uid;
670 compat_ulong_t gid;
671 compat_ulong_t file_mode;
672 compat_ulong_t dir_mode;
673};
674
675static void *do_ncp_super_data_conv(void *raw_data)
676{
677 int version = *(unsigned int *)raw_data;
678
679 if (version == 3) {
680 struct compat_ncp_mount_data *c_n = raw_data;
681 struct ncp_mount_data *n = raw_data;
682
683 n->dir_mode = c_n->dir_mode;
684 n->file_mode = c_n->file_mode;
685 n->gid = c_n->gid;
686 n->uid = c_n->uid;
687 memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
688 n->wdog_pid = c_n->wdog_pid;
689 n->mounted_uid = c_n->mounted_uid;
690 } else if (version == 4) {
691 struct compat_ncp_mount_data_v4 *c_n = raw_data;
692 struct ncp_mount_data_v4 *n = raw_data;
693
694 n->dir_mode = c_n->dir_mode;
695 n->file_mode = c_n->file_mode;
696 n->gid = c_n->gid;
697 n->uid = c_n->uid;
698 n->retry_count = c_n->retry_count;
699 n->time_out = c_n->time_out;
700 n->ncp_fd = c_n->ncp_fd;
701 n->wdog_pid = c_n->wdog_pid;
702 n->mounted_uid = c_n->mounted_uid;
703 n->flags = c_n->flags;
704 } else if (version != 5) {
705 return NULL;
706 }
707
708 return raw_data;
709}
710
711struct compat_smb_mount_data {
712 compat_int_t version;
713 compat_uid_t mounted_uid;
714 compat_uid_t uid;
715 compat_gid_t gid;
716 compat_mode_t file_mode;
717 compat_mode_t dir_mode;
718};
719
720static void *do_smb_super_data_conv(void *raw_data)
721{
722 struct smb_mount_data *s = raw_data;
723 struct compat_smb_mount_data *c_s = raw_data;
724
725 if (c_s->version != SMB_MOUNT_OLDVERSION)
726 goto out;
727 s->dir_mode = c_s->dir_mode;
728 s->file_mode = c_s->file_mode;
729 s->gid = c_s->gid;
730 s->uid = c_s->uid;
731 s->mounted_uid = c_s->mounted_uid;
732 out:
733 return raw_data;
734}
735
736struct compat_nfs_string {
737 compat_uint_t len;
738 compat_uptr_t __user data;
739};
740
741static inline void compat_nfs_string(struct nfs_string *dst,
742 struct compat_nfs_string *src)
743{
744 dst->data = compat_ptr(src->data);
745 dst->len = src->len;
746}
747
748struct compat_nfs4_mount_data_v1 {
749 compat_int_t version;
750 compat_int_t flags;
751 compat_int_t rsize;
752 compat_int_t wsize;
753 compat_int_t timeo;
754 compat_int_t retrans;
755 compat_int_t acregmin;
756 compat_int_t acregmax;
757 compat_int_t acdirmin;
758 compat_int_t acdirmax;
759 struct compat_nfs_string client_addr;
760 struct compat_nfs_string mnt_path;
761 struct compat_nfs_string hostname;
762 compat_uint_t host_addrlen;
763 compat_uptr_t __user host_addr;
764 compat_int_t proto;
765 compat_int_t auth_flavourlen;
766 compat_uptr_t __user auth_flavours;
767};
768
769static int do_nfs4_super_data_conv(void *raw_data)
770{
771 int version = *(compat_uint_t *) raw_data;
772
773 if (version == 1) {
774 struct compat_nfs4_mount_data_v1 *raw = raw_data;
775 struct nfs4_mount_data *real = raw_data;
776
777
778 real->auth_flavours = compat_ptr(raw->auth_flavours);
779 real->auth_flavourlen = raw->auth_flavourlen;
780 real->proto = raw->proto;
781 real->host_addr = compat_ptr(raw->host_addr);
782 real->host_addrlen = raw->host_addrlen;
783 compat_nfs_string(&real->hostname, &raw->hostname);
784 compat_nfs_string(&real->mnt_path, &raw->mnt_path);
785 compat_nfs_string(&real->client_addr, &raw->client_addr);
786 real->acdirmax = raw->acdirmax;
787 real->acdirmin = raw->acdirmin;
788 real->acregmax = raw->acregmax;
789 real->acregmin = raw->acregmin;
790 real->retrans = raw->retrans;
791 real->timeo = raw->timeo;
792 real->wsize = raw->wsize;
793 real->rsize = raw->rsize;
794 real->flags = raw->flags;
795 real->version = raw->version;
796 }
797 else {
798 return -EINVAL;
799 }
800
801 return 0;
802}
803
804extern int copy_mount_options (const void __user *, unsigned long *);
805
806#define SMBFS_NAME "smbfs"
807#define NCPFS_NAME "ncpfs"
808#define NFS4_NAME "nfs4"
809
810asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
811 char __user * type, unsigned long flags,
812 void __user * data)
813{
814 unsigned long type_page;
815 unsigned long data_page;
816 unsigned long dev_page;
817 char *dir_page;
818 int retval;
819
820 retval = copy_mount_options (type, &type_page);
821 if (retval < 0)
822 goto out;
823
824 dir_page = getname(dir_name);
825 retval = PTR_ERR(dir_page);
826 if (IS_ERR(dir_page))
827 goto out1;
828
829 retval = copy_mount_options (dev_name, &dev_page);
830 if (retval < 0)
831 goto out2;
832
833 retval = copy_mount_options (data, &data_page);
834 if (retval < 0)
835 goto out3;
836
837 retval = -EINVAL;
838
839 if (type_page && data_page) {
840 if (!strcmp((char *)type_page, SMBFS_NAME)) {
841 do_smb_super_data_conv((void *)data_page);
842 } else if (!strcmp((char *)type_page, NCPFS_NAME)) {
843 do_ncp_super_data_conv((void *)data_page);
844 } else if (!strcmp((char *)type_page, NFS4_NAME)) {
845 if (do_nfs4_super_data_conv((void *) data_page))
846 goto out4;
847 }
848 }
849
850 lock_kernel();
851 retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
852 flags, (void*)data_page);
853 unlock_kernel();
854
855 out4:
856 free_page(data_page);
857 out3:
858 free_page(dev_page);
859 out2:
860 putname(dir_page);
861 out1:
862 free_page(type_page);
863 out:
864 return retval;
865}
866
867#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
868#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & \
869 ~(sizeof(compat_long_t)-1))
870
871struct compat_old_linux_dirent {
872 compat_ulong_t d_ino;
873 compat_ulong_t d_offset;
874 unsigned short d_namlen;
875 char d_name[1];
876};
877
878struct compat_readdir_callback {
879 struct compat_old_linux_dirent __user *dirent;
880 int result;
881};
882
883static int compat_fillonedir(void *__buf, const char *name, int namlen,
884 loff_t offset, ino_t ino, unsigned int d_type)
885{
886 struct compat_readdir_callback *buf = __buf;
887 struct compat_old_linux_dirent __user *dirent;
888
889 if (buf->result)
890 return -EINVAL;
891 buf->result++;
892 dirent = buf->dirent;
893 if (!access_ok(VERIFY_WRITE, dirent,
894 (unsigned long)(dirent->d_name + namlen + 1) -
895 (unsigned long)dirent))
896 goto efault;
897 if ( __put_user(ino, &dirent->d_ino) ||
898 __put_user(offset, &dirent->d_offset) ||
899 __put_user(namlen, &dirent->d_namlen) ||
900 __copy_to_user(dirent->d_name, name, namlen) ||
901 __put_user(0, dirent->d_name + namlen))
902 goto efault;
903 return 0;
904efault:
905 buf->result = -EFAULT;
906 return -EFAULT;
907}
908
909asmlinkage long compat_old_readdir(unsigned int fd,
910 struct compat_old_linux_dirent __user *dirent, unsigned int count)
911{
912 int error;
913 struct file *file;
914 struct compat_readdir_callback buf;
915
916 error = -EBADF;
917 file = fget(fd);
918 if (!file)
919 goto out;
920
921 buf.result = 0;
922 buf.dirent = dirent;
923
924 error = vfs_readdir(file, compat_fillonedir, &buf);
925 if (error >= 0)
926 error = buf.result;
927
928 fput(file);
929out:
930 return error;
931}
932
933struct compat_linux_dirent {
934 compat_ulong_t d_ino;
935 compat_ulong_t d_off;
936 unsigned short d_reclen;
937 char d_name[1];
938};
939
940struct compat_getdents_callback {
941 struct compat_linux_dirent __user *current_dir;
942 struct compat_linux_dirent __user *previous;
943 int count;
944 int error;
945};
946
947static int compat_filldir(void *__buf, const char *name, int namlen,
948 loff_t offset, ino_t ino, unsigned int d_type)
949{
950 struct compat_linux_dirent __user * dirent;
951 struct compat_getdents_callback *buf = __buf;
952 int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
953
954 buf->error = -EINVAL;
955 if (reclen > buf->count)
956 return -EINVAL;
957 dirent = buf->previous;
958 if (dirent) {
959 if (__put_user(offset, &dirent->d_off))
960 goto efault;
961 }
962 dirent = buf->current_dir;
963 if (__put_user(ino, &dirent->d_ino))
964 goto efault;
965 if (__put_user(reclen, &dirent->d_reclen))
966 goto efault;
967 if (copy_to_user(dirent->d_name, name, namlen))
968 goto efault;
969 if (__put_user(0, dirent->d_name + namlen))
970 goto efault;
971 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
972 goto efault;
973 buf->previous = dirent;
974 dirent = (void __user *)dirent + reclen;
975 buf->current_dir = dirent;
976 buf->count -= reclen;
977 return 0;
978efault:
979 buf->error = -EFAULT;
980 return -EFAULT;
981}
982
983asmlinkage long compat_sys_getdents(unsigned int fd,
984 struct compat_linux_dirent __user *dirent, unsigned int count)
985{
986 struct file * file;
987 struct compat_linux_dirent __user * lastdirent;
988 struct compat_getdents_callback buf;
989 int error;
990
991 error = -EFAULT;
992 if (!access_ok(VERIFY_WRITE, dirent, count))
993 goto out;
994
995 error = -EBADF;
996 file = fget(fd);
997 if (!file)
998 goto out;
999
1000 buf.current_dir = dirent;
1001 buf.previous = NULL;
1002 buf.count = count;
1003 buf.error = 0;
1004
1005 error = vfs_readdir(file, compat_filldir, &buf);
1006 if (error < 0)
1007 goto out_putf;
1008 error = buf.error;
1009 lastdirent = buf.previous;
1010 if (lastdirent) {
1011 if (put_user(file->f_pos, &lastdirent->d_off))
1012 error = -EFAULT;
1013 else
1014 error = count - buf.count;
1015 }
1016
1017out_putf:
1018 fput(file);
1019out:
1020 return error;
1021}
1022
1023#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
1024#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
1025
1026struct compat_getdents_callback64 {
1027 struct linux_dirent64 __user *current_dir;
1028 struct linux_dirent64 __user *previous;
1029 int count;
1030 int error;
1031};
1032
1033static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
1034 ino_t ino, unsigned int d_type)
1035{
1036 struct linux_dirent64 __user *dirent;
1037 struct compat_getdents_callback64 *buf = __buf;
1038 int jj = NAME_OFFSET(dirent);
1039 int reclen = COMPAT_ROUND_UP64(jj + namlen + 1);
1040 u64 off;
1041
1042 buf->error = -EINVAL;
1043 if (reclen > buf->count)
1044 return -EINVAL;
1045 dirent = buf->previous;
1046
1047 if (dirent) {
1048 if (__put_user_unaligned(offset, &dirent->d_off))
1049 goto efault;
1050 }
1051 dirent = buf->current_dir;
1052 if (__put_user_unaligned(ino, &dirent->d_ino))
1053 goto efault;
1054 off = 0;
1055 if (__put_user_unaligned(off, &dirent->d_off))
1056 goto efault;
1057 if (__put_user(reclen, &dirent->d_reclen))
1058 goto efault;
1059 if (__put_user(d_type, &dirent->d_type))
1060 goto efault;
1061 if (copy_to_user(dirent->d_name, name, namlen))
1062 goto efault;
1063 if (__put_user(0, dirent->d_name + namlen))
1064 goto efault;
1065 buf->previous = dirent;
1066 dirent = (void __user *)dirent + reclen;
1067 buf->current_dir = dirent;
1068 buf->count -= reclen;
1069 return 0;
1070efault:
1071 buf->error = -EFAULT;
1072 return -EFAULT;
1073}
1074
1075asmlinkage long compat_sys_getdents64(unsigned int fd,
1076 struct linux_dirent64 __user * dirent, unsigned int count)
1077{
1078 struct file * file;
1079 struct linux_dirent64 __user * lastdirent;
1080 struct compat_getdents_callback64 buf;
1081 int error;
1082
1083 error = -EFAULT;
1084 if (!access_ok(VERIFY_WRITE, dirent, count))
1085 goto out;
1086
1087 error = -EBADF;
1088 file = fget(fd);
1089 if (!file)
1090 goto out;
1091
1092 buf.current_dir = dirent;
1093 buf.previous = NULL;
1094 buf.count = count;
1095 buf.error = 0;
1096
1097 error = vfs_readdir(file, compat_filldir64, &buf);
1098 if (error < 0)
1099 goto out_putf;
1100 error = buf.error;
1101 lastdirent = buf.previous;
1102 if (lastdirent) {
1103 typeof(lastdirent->d_off) d_off = file->f_pos;
1104 __put_user_unaligned(d_off, &lastdirent->d_off);
1105 error = count - buf.count;
1106 }
1107
1108out_putf:
1109 fput(file);
1110out:
1111 return error;
1112}
1113#endif
1114
1115static ssize_t compat_do_readv_writev(int type, struct file *file,
1116 const struct compat_iovec __user *uvector,
1117 unsigned long nr_segs, loff_t *pos)
1118{
1119 typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
1120 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
1121
1122 compat_ssize_t tot_len;
1123 struct iovec iovstack[UIO_FASTIOV];
1124 struct iovec *iov=iovstack, *vector;
1125 ssize_t ret;
1126 int seg;
1127 io_fn_t fn;
1128 iov_fn_t fnv;
1129 struct inode *inode;
1130
1131
1132
1133
1134
1135
1136 ret = 0;
1137 if (nr_segs == 0)
1138 goto out;
1139
1140
1141
1142
1143
1144 ret = -EINVAL;
1145 if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
1146 goto out;
1147 if (!file->f_op)
1148 goto out;
1149 if (nr_segs > UIO_FASTIOV) {
1150 ret = -ENOMEM;
1151 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
1152 if (!iov)
1153 goto out;
1154 }
1155 ret = -EFAULT;
1156 if (verify_area(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
1157 goto out;
1158
1159
1160
1161
1162
1163
1164
1165
1166 tot_len = 0;
1167 vector = iov;
1168 ret = -EINVAL;
1169 for (seg = 0 ; seg < nr_segs; seg++) {
1170 compat_ssize_t tmp = tot_len;
1171 compat_ssize_t len;
1172 compat_uptr_t buf;
1173
1174 if (__get_user(len, &uvector->iov_len) ||
1175 __get_user(buf, &uvector->iov_base)) {
1176 ret = -EFAULT;
1177 goto out;
1178 }
1179 if (len < 0)
1180 goto out;
1181 tot_len += len;
1182 if (tot_len < tmp)
1183 goto out;
1184 vector->iov_base = compat_ptr(buf);
1185 vector->iov_len = (compat_size_t) len;
1186 uvector++;
1187 vector++;
1188 }
1189 if (tot_len == 0) {
1190 ret = 0;
1191 goto out;
1192 }
1193
1194 inode = file->f_dentry->d_inode;
1195
1196 ret = locks_verify_area((type == READ
1197 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
1198 inode, file, *pos, tot_len);
1199 if (ret)
1200 goto out;
1201
1202 ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
1203 if (ret)
1204 goto out;
1205
1206 fnv = NULL;
1207 if (type == READ) {
1208 fn = file->f_op->read;
1209 fnv = file->f_op->readv;
1210 } else {
1211 fn = (io_fn_t)file->f_op->write;
1212 fnv = file->f_op->writev;
1213 }
1214 if (fnv) {
1215 ret = fnv(file, iov, nr_segs, pos);
1216 goto out;
1217 }
1218
1219
1220 ret = 0;
1221 vector = iov;
1222 while (nr_segs > 0) {
1223 void __user * base;
1224 size_t len;
1225 ssize_t nr;
1226
1227 base = vector->iov_base;
1228 len = vector->iov_len;
1229 vector++;
1230 nr_segs--;
1231
1232 nr = fn(file, base, len, pos);
1233
1234 if (nr < 0) {
1235 if (!ret) ret = nr;
1236 break;
1237 }
1238 ret += nr;
1239 if (nr != len)
1240 break;
1241 }
1242out:
1243 if (iov != iovstack)
1244 kfree(iov);
1245 if ((ret + (type == READ)) > 0)
1246 dnotify_parent(file->f_dentry,
1247 (type == READ) ? DN_ACCESS : DN_MODIFY);
1248 return ret;
1249}
1250
1251asmlinkage ssize_t
1252compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1253{
1254 struct file *file;
1255 ssize_t ret = -EBADF;
1256
1257 file = fget(fd);
1258 if (!file)
1259 return -EBADF;
1260
1261 if (!(file->f_mode & FMODE_READ))
1262 goto out;
1263
1264 ret = -EINVAL;
1265 if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
1266 goto out;
1267
1268 ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
1269
1270out:
1271 fput(file);
1272 return ret;
1273}
1274
1275asmlinkage ssize_t
1276compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1277{
1278 struct file *file;
1279 ssize_t ret = -EBADF;
1280
1281 file = fget(fd);
1282 if (!file)
1283 return -EBADF;
1284 if (!(file->f_mode & FMODE_WRITE))
1285 goto out;
1286
1287 ret = -EINVAL;
1288 if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
1289 goto out;
1290
1291 ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
1292
1293out:
1294 fput(file);
1295 return ret;
1296}
1297
1298
1299
1300
1301
1302
1303static int compat_count(compat_uptr_t __user *argv, int max)
1304{
1305 int i = 0;
1306
1307 if (argv != NULL) {
1308 for (;;) {
1309 compat_uptr_t p;
1310
1311 if (get_user(p, argv))
1312 return -EFAULT;
1313 if (!p)
1314 break;
1315 argv++;
1316 if(++i > max)
1317 return -E2BIG;
1318 }
1319 }
1320 return i;
1321}
1322
1323
1324
1325
1326
1327static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
1328 struct linux_binprm *bprm)
1329{
1330 struct page *kmapped_page = NULL;
1331 char *kaddr = NULL;
1332 int ret;
1333
1334 while (argc-- > 0) {
1335 compat_uptr_t str;
1336 int len;
1337 unsigned long pos;
1338
1339 if (get_user(str, argv+argc) ||
1340 !(len = strnlen_user(compat_ptr(str), bprm->p))) {
1341 ret = -EFAULT;
1342 goto out;
1343 }
1344
1345 if (bprm->p < len) {
1346 ret = -E2BIG;
1347 goto out;
1348 }
1349
1350 bprm->p -= len;
1351
1352 pos = bprm->p;
1353
1354 while (len > 0) {
1355 int i, new, err;
1356 int offset, bytes_to_copy;
1357 struct page *page;
1358
1359 offset = pos % PAGE_SIZE;
1360 i = pos/PAGE_SIZE;
1361 page = bprm->page[i];
1362 new = 0;
1363 if (!page) {
1364 page = alloc_page(GFP_HIGHUSER);
1365 bprm->page[i] = page;
1366 if (!page) {
1367 ret = -ENOMEM;
1368 goto out;
1369 }
1370 new = 1;
1371 }
1372
1373 if (page != kmapped_page) {
1374 if (kmapped_page)
1375 kunmap(kmapped_page);
1376 kmapped_page = page;
1377 kaddr = kmap(kmapped_page);
1378 }
1379 if (new && offset)
1380 memset(kaddr, 0, offset);
1381 bytes_to_copy = PAGE_SIZE - offset;
1382 if (bytes_to_copy > len) {
1383 bytes_to_copy = len;
1384 if (new)
1385 memset(kaddr+offset+len, 0,
1386 PAGE_SIZE-offset-len);
1387 }
1388 err = copy_from_user(kaddr+offset, compat_ptr(str),
1389 bytes_to_copy);
1390 if (err) {
1391 ret = -EFAULT;
1392 goto out;
1393 }
1394
1395 pos += bytes_to_copy;
1396 str += bytes_to_copy;
1397 len -= bytes_to_copy;
1398 }
1399 }
1400 ret = 0;
1401out:
1402 if (kmapped_page)
1403 kunmap(kmapped_page);
1404 return ret;
1405}
1406
1407#ifdef CONFIG_MMU
1408
1409#define free_arg_pages(bprm) do { } while (0)
1410
1411#else
1412
1413static inline void free_arg_pages(struct linux_binprm *bprm)
1414{
1415 int i;
1416
1417 for (i = 0; i < MAX_ARG_PAGES; i++) {
1418 if (bprm->page[i])
1419 __free_page(bprm->page[i]);
1420 bprm->page[i] = NULL;
1421 }
1422}
1423
1424#endif
1425
1426
1427
1428
1429
1430int compat_do_execve(char * filename,
1431 compat_uptr_t __user *argv,
1432 compat_uptr_t __user *envp,
1433 struct pt_regs * regs)
1434{
1435 struct linux_binprm *bprm;
1436 struct file *file;
1437 int retval;
1438 int i;
1439
1440 file = open_exec(filename);
1441
1442 retval = PTR_ERR(file);
1443 if (IS_ERR(file))
1444 return retval;
1445
1446 sched_exec();
1447
1448 retval = -ENOMEM;
1449 bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
1450 if (!bprm)
1451 goto out_ret;
1452 memset(bprm, 0, sizeof(*bprm));
1453
1454 bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
1455 bprm->file = file;
1456 bprm->filename = filename;
1457 bprm->interp = filename;
1458 bprm->mm = mm_alloc();
1459 if (!bprm->mm)
1460 goto out_file;
1461
1462 retval = init_new_context(current, bprm->mm);
1463 if (retval < 0)
1464 goto out_mm;
1465
1466 bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t));
1467 if ((retval = bprm->argc) < 0)
1468 goto out_mm;
1469
1470 bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t));
1471 if ((retval = bprm->envc) < 0)
1472 goto out_mm;
1473
1474 retval = security_bprm_alloc(bprm);
1475 if (retval)
1476 goto out;
1477
1478 retval = prepare_binprm(bprm);
1479 if (retval < 0)
1480 goto out;
1481
1482 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1483 if (retval < 0)
1484 goto out;
1485
1486 bprm->exec = bprm->p;
1487 retval = compat_copy_strings(bprm->envc, envp, bprm);
1488 if (retval < 0)
1489 goto out;
1490
1491 retval = compat_copy_strings(bprm->argc, argv, bprm);
1492 if (retval < 0)
1493 goto out;
1494
1495 retval = search_binary_handler(bprm, regs);
1496 if (retval >= 0) {
1497 free_arg_pages(bprm);
1498
1499
1500 security_bprm_free(bprm);
1501 kfree(bprm);
1502 return retval;
1503 }
1504
1505out:
1506
1507 for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
1508 struct page * page = bprm->page[i];
1509 if (page)
1510 __free_page(page);
1511 }
1512
1513 if (bprm->security)
1514 security_bprm_free(bprm);
1515
1516out_mm:
1517 if (bprm->mm)
1518 mmdrop(bprm->mm);
1519
1520out_file:
1521 if (bprm->file) {
1522 allow_write_access(bprm->file);
1523 fput(bprm->file);
1524 }
1525 kfree(bprm);
1526
1527out_ret:
1528 return retval;
1529}
1530
1531#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
1532
1533#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
1534
1535
1536
1537
1538
1539static inline
1540int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1541 unsigned long *fdset)
1542{
1543 nr = ROUND_UP(nr, __COMPAT_NFDBITS);
1544 if (ufdset) {
1545 unsigned long odd;
1546
1547 if (verify_area(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
1548 return -EFAULT;
1549
1550 odd = nr & 1UL;
1551 nr &= ~1UL;
1552 while (nr) {
1553 unsigned long h, l;
1554 __get_user(l, ufdset);
1555 __get_user(h, ufdset+1);
1556 ufdset += 2;
1557 *fdset++ = h << 32 | l;
1558 nr -= 2;
1559 }
1560 if (odd)
1561 __get_user(*fdset, ufdset);
1562 } else {
1563
1564
1565
1566
1567 memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
1568 }
1569 return 0;
1570}
1571
1572static inline
1573void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1574 unsigned long *fdset)
1575{
1576 unsigned long odd;
1577 nr = ROUND_UP(nr, __COMPAT_NFDBITS);
1578
1579 if (!ufdset)
1580 return;
1581
1582 odd = nr & 1UL;
1583 nr &= ~1UL;
1584 while (nr) {
1585 unsigned long h, l;
1586 l = *fdset++;
1587 h = l >> 32;
1588 __put_user(l, ufdset);
1589 __put_user(h, ufdset+1);
1590 ufdset += 2;
1591 nr -= 2;
1592 }
1593 if (odd)
1594 __put_user(*fdset, ufdset);
1595}
1596
1597
1598
1599
1600
1601
1602static void *select_bits_alloc(int size)
1603{
1604 return kmalloc(6 * size, GFP_KERNEL);
1605}
1606
1607static void select_bits_free(void *bits, int size)
1608{
1609 kfree(bits);
1610}
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620#define MAX_SELECT_SECONDS \
1621 ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
1622
1623asmlinkage long
1624compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
1625 compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
1626{
1627 fd_set_bits fds;
1628 char *bits;
1629 long timeout;
1630 int ret, size, max_fdset;
1631
1632 timeout = MAX_SCHEDULE_TIMEOUT;
1633 if (tvp) {
1634 time_t sec, usec;
1635
1636 if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
1637 || (ret = __get_user(sec, &tvp->tv_sec))
1638 || (ret = __get_user(usec, &tvp->tv_usec)))
1639 goto out_nofds;
1640
1641 ret = -EINVAL;
1642 if (sec < 0 || usec < 0)
1643 goto out_nofds;
1644
1645 if ((unsigned long) sec < MAX_SELECT_SECONDS) {
1646 timeout = ROUND_UP(usec, 1000000/HZ);
1647 timeout += sec * (unsigned long) HZ;
1648 }
1649 }
1650
1651 ret = -EINVAL;
1652 if (n < 0)
1653 goto out_nofds;
1654
1655
1656 max_fdset = current->files->max_fdset;
1657 if (n > max_fdset)
1658 n = max_fdset;
1659
1660
1661
1662
1663
1664
1665 ret = -ENOMEM;
1666 size = FDS_BYTES(n);
1667 bits = select_bits_alloc(size);
1668 if (!bits)
1669 goto out_nofds;
1670 fds.in = (unsigned long *) bits;
1671 fds.out = (unsigned long *) (bits + size);
1672 fds.ex = (unsigned long *) (bits + 2*size);
1673 fds.res_in = (unsigned long *) (bits + 3*size);
1674 fds.res_out = (unsigned long *) (bits + 4*size);
1675 fds.res_ex = (unsigned long *) (bits + 5*size);
1676
1677 if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
1678 (ret = compat_get_fd_set(n, outp, fds.out)) ||
1679 (ret = compat_get_fd_set(n, exp, fds.ex)))
1680 goto out;
1681 zero_fd_set(n, fds.res_in);
1682 zero_fd_set(n, fds.res_out);
1683 zero_fd_set(n, fds.res_ex);
1684
1685 ret = do_select(n, &fds, &timeout);
1686
1687 if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
1688 time_t sec = 0, usec = 0;
1689 if (timeout) {
1690 sec = timeout / HZ;
1691 usec = timeout % HZ;
1692 usec *= (1000000/HZ);
1693 }
1694 if (put_user(sec, &tvp->tv_sec) ||
1695 put_user(usec, &tvp->tv_usec))
1696 ret = -EFAULT;
1697 }
1698
1699 if (ret < 0)
1700 goto out;
1701 if (!ret) {
1702 ret = -ERESTARTNOHAND;
1703 if (signal_pending(current))
1704 goto out;
1705 ret = 0;
1706 }
1707
1708 compat_set_fd_set(n, inp, fds.res_in);
1709 compat_set_fd_set(n, outp, fds.res_out);
1710 compat_set_fd_set(n, exp, fds.res_ex);
1711
1712out:
1713 select_bits_free(bits, size);
1714out_nofds:
1715 return ret;
1716}
1717
1718#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
1719
1720struct compat_nfsctl_svc {
1721 u16 svc32_port;
1722 s32 svc32_nthreads;
1723};
1724
1725struct compat_nfsctl_client {
1726 s8 cl32_ident[NFSCLNT_IDMAX+1];
1727 s32 cl32_naddr;
1728 struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX];
1729 s32 cl32_fhkeytype;
1730 s32 cl32_fhkeylen;
1731 u8 cl32_fhkey[NFSCLNT_KEYMAX];
1732};
1733
1734struct compat_nfsctl_export {
1735 char ex32_client[NFSCLNT_IDMAX+1];
1736 char ex32_path[NFS_MAXPATHLEN+1];
1737 compat_dev_t ex32_dev;
1738 compat_ino_t ex32_ino;
1739 compat_int_t ex32_flags;
1740 compat_uid_t ex32_anon_uid;
1741 compat_gid_t ex32_anon_gid;
1742};
1743
1744struct compat_nfsctl_fdparm {
1745 struct sockaddr gd32_addr;
1746 s8 gd32_path[NFS_MAXPATHLEN+1];
1747 compat_int_t gd32_version;
1748};
1749
1750struct compat_nfsctl_fsparm {
1751 struct sockaddr gd32_addr;
1752 s8 gd32_path[NFS_MAXPATHLEN+1];
1753 compat_int_t gd32_maxlen;
1754};
1755
1756struct compat_nfsctl_arg {
1757 compat_int_t ca32_version;
1758 union {
1759 struct compat_nfsctl_svc u32_svc;
1760 struct compat_nfsctl_client u32_client;
1761 struct compat_nfsctl_export u32_export;
1762 struct compat_nfsctl_fdparm u32_getfd;
1763 struct compat_nfsctl_fsparm u32_getfs;
1764 } u;
1765#define ca32_svc u.u32_svc
1766#define ca32_client u.u32_client
1767#define ca32_export u.u32_export
1768#define ca32_getfd u.u32_getfd
1769#define ca32_getfs u.u32_getfs
1770};
1771
1772union compat_nfsctl_res {
1773 __u8 cr32_getfh[NFS_FHSIZE];
1774 struct knfsd_fh cr32_getfs;
1775};
1776
1777static int compat_nfs_svc_trans(struct nfsctl_arg *karg,
1778 struct compat_nfsctl_arg __user *arg)
1779{
1780 if(!access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc)) ||
1781 get_user(karg->ca_version, &arg->ca32_version) ||
1782 __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port) ||
1783 __get_user(karg->ca_svc.svc_nthreads,
1784 &arg->ca32_svc.svc32_nthreads))
1785 return -EFAULT;
1786 return 0;
1787}
1788
1789static int compat_nfs_clnt_trans(struct nfsctl_arg *karg,
1790 struct compat_nfsctl_arg __user *arg)
1791{
1792 if (!access_ok(VERIFY_READ, &arg->ca32_client,
1793 sizeof(arg->ca32_client)) ||
1794 get_user(karg->ca_version, &arg->ca32_version) ||
1795 __copy_from_user(&karg->ca_client.cl_ident[0],
1796 &arg->ca32_client.cl32_ident[0],
1797 NFSCLNT_IDMAX) ||
1798 __get_user(karg->ca_client.cl_naddr,
1799 &arg->ca32_client.cl32_naddr) ||
1800 __copy_from_user(&karg->ca_client.cl_addrlist[0],
1801 &arg->ca32_client.cl32_addrlist[0],
1802 (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)) ||
1803 __get_user(karg->ca_client.cl_fhkeytype,
1804 &arg->ca32_client.cl32_fhkeytype) ||
1805 __get_user(karg->ca_client.cl_fhkeylen,
1806 &arg->ca32_client.cl32_fhkeylen) ||
1807 __copy_from_user(&karg->ca_client.cl_fhkey[0],
1808 &arg->ca32_client.cl32_fhkey[0],
1809 NFSCLNT_KEYMAX))
1810 return -EFAULT;
1811
1812 return 0;
1813}
1814
1815static int compat_nfs_exp_trans(struct nfsctl_arg *karg,
1816 struct compat_nfsctl_arg __user *arg)
1817{
1818 if (!access_ok(VERIFY_READ, &arg->ca32_export,
1819 sizeof(arg->ca32_export)) ||
1820 get_user(karg->ca_version, &arg->ca32_version) ||
1821 __copy_from_user(&karg->ca_export.ex_client[0],
1822 &arg->ca32_export.ex32_client[0],
1823 NFSCLNT_IDMAX) ||
1824 __copy_from_user(&karg->ca_export.ex_path[0],
1825 &arg->ca32_export.ex32_path[0],
1826 NFS_MAXPATHLEN) ||
1827 __get_user(karg->ca_export.ex_dev,
1828 &arg->ca32_export.ex32_dev) ||
1829 __get_user(karg->ca_export.ex_ino,
1830 &arg->ca32_export.ex32_ino) ||
1831 __get_user(karg->ca_export.ex_flags,
1832 &arg->ca32_export.ex32_flags) ||
1833 __get_user(karg->ca_export.ex_anon_uid,
1834 &arg->ca32_export.ex32_anon_uid) ||
1835 __get_user(karg->ca_export.ex_anon_gid,
1836 &arg->ca32_export.ex32_anon_gid))
1837 return -EFAULT;
1838 SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
1839 SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
1840
1841 return 0;
1842}
1843
1844static int compat_nfs_getfd_trans(struct nfsctl_arg *karg,
1845 struct compat_nfsctl_arg __user *arg)
1846{
1847 if(!access_ok(VERIFY_READ, &arg->ca32_getfd, sizeof(arg->ca32_getfd)) ||
1848 get_user(karg->ca_version, &arg->ca32_version) ||
1849 __copy_from_user(&karg->ca_getfd.gd_addr,
1850 &arg->ca32_getfd.gd32_addr,
1851 (sizeof(struct sockaddr))) ||
1852 __copy_from_user(&karg->ca_getfd.gd_path,
1853 &arg->ca32_getfd.gd32_path,
1854 (NFS_MAXPATHLEN+1)) ||
1855 __get_user(karg->ca_getfd.gd_version,
1856 &arg->ca32_getfd.gd32_version))
1857 return -EFAULT;
1858
1859 return 0;
1860}
1861
1862static int compat_nfs_getfs_trans(struct nfsctl_arg *karg,
1863 struct compat_nfsctl_arg __user *arg)
1864{
1865 if (!access_ok(VERIFY_READ,&arg->ca32_getfs,sizeof(arg->ca32_getfs)) ||
1866 get_user(karg->ca_version, &arg->ca32_version) ||
1867 __copy_from_user(&karg->ca_getfs.gd_addr,
1868 &arg->ca32_getfs.gd32_addr,
1869 (sizeof(struct sockaddr))) ||
1870 __copy_from_user(&karg->ca_getfs.gd_path,
1871 &arg->ca32_getfs.gd32_path,
1872 (NFS_MAXPATHLEN+1)) ||
1873 __get_user(karg->ca_getfs.gd_maxlen,
1874 &arg->ca32_getfs.gd32_maxlen))
1875 return -EFAULT;
1876
1877 return 0;
1878}
1879
1880
1881
1882
1883static int compat_nfs_getfh_res_trans(union nfsctl_res *kres,
1884 union compat_nfsctl_res __user *res)
1885{
1886 int err;
1887
1888 err = copy_to_user(res, kres, sizeof(*res));
1889
1890 return (err) ? -EFAULT : 0;
1891}
1892
1893asmlinkage long compat_sys_nfsservctl(int cmd,
1894 struct compat_nfsctl_arg __user *arg,
1895 union compat_nfsctl_res __user *res)
1896{
1897 struct nfsctl_arg *karg;
1898 union nfsctl_res *kres;
1899 mm_segment_t oldfs;
1900 int err;
1901
1902 karg = kmalloc(sizeof(*karg), GFP_USER);
1903 kres = kmalloc(sizeof(*kres), GFP_USER);
1904 if(!karg || !kres) {
1905 err = -ENOMEM;
1906 goto done;
1907 }
1908
1909 switch(cmd) {
1910 case NFSCTL_SVC:
1911 err = compat_nfs_svc_trans(karg, arg);
1912 break;
1913
1914 case NFSCTL_ADDCLIENT:
1915 err = compat_nfs_clnt_trans(karg, arg);
1916 break;
1917
1918 case NFSCTL_DELCLIENT:
1919 err = compat_nfs_clnt_trans(karg, arg);
1920 break;
1921
1922 case NFSCTL_EXPORT:
1923 case NFSCTL_UNEXPORT:
1924 err = compat_nfs_exp_trans(karg, arg);
1925 break;
1926
1927 case NFSCTL_GETFD:
1928 err = compat_nfs_getfd_trans(karg, arg);
1929 break;
1930
1931 case NFSCTL_GETFS:
1932 err = compat_nfs_getfs_trans(karg, arg);
1933 break;
1934
1935 default:
1936 err = -EINVAL;
1937 break;
1938 }
1939
1940 if (err)
1941 goto done;
1942
1943 oldfs = get_fs();
1944 set_fs(KERNEL_DS);
1945
1946 err = sys_nfsservctl(cmd, (void __user *) karg, (void __user *) kres);
1947 set_fs(oldfs);
1948
1949 if (err)
1950 goto done;
1951
1952 if((cmd == NFSCTL_GETFD) ||
1953 (cmd == NFSCTL_GETFS))
1954 err = compat_nfs_getfh_res_trans(kres, res);
1955
1956done:
1957 kfree(karg);
1958 kfree(kres);
1959 return err;
1960}
1961#else
1962long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
1963{
1964 return sys_ni_syscall();
1965}
1966#endif
1967