4 * Kernel compatibililty routines for e.g. 32 bit syscall support
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>
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 <net/sock.h> /* siocdevprivate_ioctl */
39 #include <asm/uaccess.h>
42 * Not all architectures have sys_utime, so implement this in terms
45 asmlinkage
long compat_sys_utime(char *filename
, struct compat_utimbuf
*t
)
50 if (get_user(tv
[0].tv_sec
, &t
->actime
) ||
51 get_user(tv
[1].tv_sec
, &t
->modtime
))
56 return do_utimes(filename
, t
? tv
: NULL
);
59 asmlinkage
long compat_sys_utimes(char *filename
, struct compat_timeval
*t
)
64 if (get_user(tv
[0].tv_sec
, &t
[0].tv_sec
) ||
65 get_user(tv
[0].tv_usec
, &t
[0].tv_usec
) ||
66 get_user(tv
[1].tv_sec
, &t
[1].tv_sec
) ||
67 get_user(tv
[1].tv_usec
, &t
[1].tv_usec
))
70 return do_utimes(filename
, t
? tv
: NULL
);
73 asmlinkage
long compat_sys_newstat(char * filename
,
74 struct compat_stat
*statbuf
)
77 int error
= vfs_stat(filename
, &stat
);
80 error
= cp_compat_stat(&stat
, statbuf
);
84 asmlinkage
long compat_sys_newlstat(char * filename
,
85 struct compat_stat
*statbuf
)
88 int error
= vfs_lstat(filename
, &stat
);
91 error
= cp_compat_stat(&stat
, statbuf
);
95 asmlinkage
long compat_sys_newfstat(unsigned int fd
,
96 struct compat_stat
* statbuf
)
99 int error
= vfs_fstat(fd
, &stat
);
102 error
= cp_compat_stat(&stat
, statbuf
);
106 static int put_compat_statfs(struct compat_statfs
*ubuf
, struct kstatfs
*kbuf
)
109 if (sizeof ubuf
->f_blocks
== 4) {
110 if ((kbuf
->f_blocks
| kbuf
->f_bfree
|
111 kbuf
->f_bavail
| kbuf
->f_files
| kbuf
->f_ffree
) &
112 0xffffffff00000000ULL
)
115 if (verify_area(VERIFY_WRITE
, ubuf
, sizeof(*ubuf
)) ||
116 __put_user(kbuf
->f_type
, &ubuf
->f_type
) ||
117 __put_user(kbuf
->f_bsize
, &ubuf
->f_bsize
) ||
118 __put_user(kbuf
->f_blocks
, &ubuf
->f_blocks
) ||
119 __put_user(kbuf
->f_bfree
, &ubuf
->f_bfree
) ||
120 __put_user(kbuf
->f_bavail
, &ubuf
->f_bavail
) ||
121 __put_user(kbuf
->f_files
, &ubuf
->f_files
) ||
122 __put_user(kbuf
->f_ffree
, &ubuf
->f_ffree
) ||
123 __put_user(kbuf
->f_namelen
, &ubuf
->f_namelen
) ||
124 __put_user(kbuf
->f_fsid
.val
[0], &ubuf
->f_fsid
.val
[0]) ||
125 __put_user(kbuf
->f_fsid
.val
[1], &ubuf
->f_fsid
.val
[1]) ||
126 __put_user(kbuf
->f_frsize
, &ubuf
->f_frsize
) ||
127 __put_user(0, &ubuf
->f_spare
[0]) ||
128 __put_user(0, &ubuf
->f_spare
[1]) ||
129 __put_user(0, &ubuf
->f_spare
[2]) ||
130 __put_user(0, &ubuf
->f_spare
[3]) ||
131 __put_user(0, &ubuf
->f_spare
[4]))
137 * The following statfs calls are copies of code from fs/open.c and
138 * should be checked against those from time to time
140 asmlinkage
long compat_sys_statfs(const char *path
, struct compat_statfs
*buf
)
145 error
= user_path_walk(path
, &nd
);
148 error
= vfs_statfs(nd
.dentry
->d_inode
->i_sb
, &tmp
);
149 if (!error
&& put_compat_statfs(buf
, &tmp
))
156 asmlinkage
long compat_sys_fstatfs(unsigned int fd
, struct compat_statfs
*buf
)
166 error
= vfs_statfs(file
->f_dentry
->d_inode
->i_sb
, &tmp
);
167 if (!error
&& put_compat_statfs(buf
, &tmp
))
174 static int put_compat_statfs64(struct compat_statfs64
*ubuf
, struct kstatfs
*kbuf
)
176 if (sizeof ubuf
->f_blocks
== 4) {
177 if ((kbuf
->f_blocks
| kbuf
->f_bfree
|
178 kbuf
->f_bavail
| kbuf
->f_files
| kbuf
->f_ffree
) &
179 0xffffffff00000000ULL
)
182 if (verify_area(VERIFY_WRITE
, ubuf
, sizeof(*ubuf
)) ||
183 __put_user(kbuf
->f_type
, &ubuf
->f_type
) ||
184 __put_user(kbuf
->f_bsize
, &ubuf
->f_bsize
) ||
185 __put_user(kbuf
->f_blocks
, &ubuf
->f_blocks
) ||
186 __put_user(kbuf
->f_bfree
, &ubuf
->f_bfree
) ||
187 __put_user(kbuf
->f_bavail
, &ubuf
->f_bavail
) ||
188 __put_user(kbuf
->f_files
, &ubuf
->f_files
) ||
189 __put_user(kbuf
->f_ffree
, &ubuf
->f_ffree
) ||
190 __put_user(kbuf
->f_namelen
, &ubuf
->f_namelen
) ||
191 __put_user(kbuf
->f_fsid
.val
[0], &ubuf
->f_fsid
.val
[0]) ||
192 __put_user(kbuf
->f_fsid
.val
[1], &ubuf
->f_fsid
.val
[1]) ||
193 __put_user(kbuf
->f_frsize
, &ubuf
->f_frsize
))
198 asmlinkage
long compat_statfs64(const char *path
, compat_size_t sz
, struct compat_statfs64
*buf
)
203 if (sz
!= sizeof(*buf
))
206 error
= user_path_walk(path
, &nd
);
209 error
= vfs_statfs(nd
.dentry
->d_inode
->i_sb
, &tmp
);
210 if (!error
&& put_compat_statfs64(buf
, &tmp
))
217 asmlinkage
long compat_fstatfs64(unsigned int fd
, compat_size_t sz
, struct compat_statfs64
*buf
)
223 if (sz
!= sizeof(*buf
))
230 error
= vfs_statfs(file
->f_dentry
->d_inode
->i_sb
, &tmp
);
231 if (!error
&& put_compat_statfs64(buf
, &tmp
))
238 /* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64 */
240 #define IOCTL_HASHSIZE 256
241 struct ioctl_trans
*ioctl32_hash_table
[IOCTL_HASHSIZE
];
243 extern struct ioctl_trans ioctl_start
[];
244 extern int ioctl_table_size
;
246 static inline unsigned long ioctl32_hash(unsigned long cmd
)
248 return (((cmd
>> 6) ^ (cmd
>> 4) ^ cmd
)) % IOCTL_HASHSIZE
;
251 static void ioctl32_insert_translation(struct ioctl_trans
*trans
)
254 struct ioctl_trans
*t
;
256 hash
= ioctl32_hash (trans
->cmd
);
257 if (!ioctl32_hash_table
[hash
])
258 ioctl32_hash_table
[hash
] = trans
;
260 t
= ioctl32_hash_table
[hash
];
268 static int __init
init_sys32_ioctl(void)
272 for (i
= 0; i
< ioctl_table_size
; i
++) {
273 if (ioctl_start
[i
].next
!= 0) {
274 printk("ioctl translation %d bad\n",i
);
278 ioctl32_insert_translation(&ioctl_start
[i
]);
283 __initcall(init_sys32_ioctl
);
285 static struct ioctl_trans
*ioctl_free_list
;
287 /* Never free them really. This avoids SMP races. With a Read-Copy-Update
288 enabled kernel we could just use the RCU infrastructure for this. */
289 static void free_ioctl(struct ioctl_trans
*t
)
293 t
->next
= ioctl_free_list
;
297 int register_ioctl32_conversion(unsigned int cmd
, int (*handler
)(unsigned int, unsigned int, unsigned long, struct file
*))
299 struct ioctl_trans
*t
;
300 unsigned long hash
= ioctl32_hash(cmd
);
303 for (t
= (struct ioctl_trans
*)ioctl32_hash_table
[hash
];
307 printk("Trying to register duplicated ioctl32 handler %x\n", cmd
);
313 if (ioctl_free_list
) {
315 ioctl_free_list
= t
->next
;
317 t
= kmalloc(sizeof(struct ioctl_trans
), GFP_KERNEL
);
326 t
->handler
= handler
;
327 ioctl32_insert_translation(t
);
333 static inline int builtin_ioctl(struct ioctl_trans
*t
)
335 return t
>= ioctl_start
&& t
< (ioctl_start
+ ioctl_table_size
);
339 This function cannot unregister duplicate ioctls, because they are not
341 When they happen we need to extend the prototype to pass the handler too. */
343 int unregister_ioctl32_conversion(unsigned int cmd
)
345 unsigned long hash
= ioctl32_hash(cmd
);
346 struct ioctl_trans
*t
, *t1
;
350 t
= (struct ioctl_trans
*)ioctl32_hash_table
[hash
];
357 if (builtin_ioctl(t
)) {
358 printk("%p tried to unregister builtin ioctl %x\n",
359 __builtin_return_address(0), cmd
);
361 ioctl32_hash_table
[hash
] = t
->next
;
368 t1
= (struct ioctl_trans
*)(long)t
->next
;
369 if (t1
->cmd
== cmd
) {
370 if (builtin_ioctl(t1
)) {
371 printk("%p tried to unregister builtin ioctl %x\n",
372 __builtin_return_address(0), cmd
);
383 printk(KERN_ERR
"Trying to free unknown 32bit ioctl handler %x\n", cmd
);
389 EXPORT_SYMBOL(register_ioctl32_conversion
);
390 EXPORT_SYMBOL(unregister_ioctl32_conversion
);
392 asmlinkage
long compat_sys_ioctl(unsigned int fd
, unsigned int cmd
, unsigned long arg
)
396 struct ioctl_trans
*t
;
402 if (!filp
->f_op
|| !filp
->f_op
->ioctl
) {
403 error
= sys_ioctl (fd
, cmd
, arg
);
407 t
= (struct ioctl_trans
*)ioctl32_hash_table
[ioctl32_hash (cmd
)];
409 while (t
&& t
->cmd
!= cmd
)
410 t
= (struct ioctl_trans
*)t
->next
;
414 error
= t
->handler(fd
, cmd
, arg
, filp
);
417 error
= sys_ioctl(fd
, cmd
, arg
);
418 } else if (cmd
>= SIOCDEVPRIVATE
&& cmd
<= (SIOCDEVPRIVATE
+ 15)) {
419 error
= siocdevprivate_ioctl(fd
, cmd
, arg
);
424 char *path
= (char *)__get_free_page(GFP_KERNEL
), *fn
= "?";
426 /* find the name of the device. */
428 fn
= d_path(filp
->f_dentry
, filp
->f_vfsmnt
,
432 sprintf(buf
,"'%c'", (cmd
>>24) & 0x3f);
433 if (!isprint(buf
[1]))
434 sprintf(buf
, "%02x", buf
[1]);
435 printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
436 "cmd(%08x){%s} arg(%08x) on %s\n",
437 current
->comm
, current
->pid
,
438 (int)fd
, (unsigned int)cmd
, buf
, (unsigned int)arg
,
441 free_page((unsigned long)path
);
451 static int get_compat_flock(struct flock
*kfl
, struct compat_flock
*ufl
)
453 if (!access_ok(VERIFY_READ
, ufl
, sizeof(*ufl
)) ||
454 __get_user(kfl
->l_type
, &ufl
->l_type
) ||
455 __get_user(kfl
->l_whence
, &ufl
->l_whence
) ||
456 __get_user(kfl
->l_start
, &ufl
->l_start
) ||
457 __get_user(kfl
->l_len
, &ufl
->l_len
) ||
458 __get_user(kfl
->l_pid
, &ufl
->l_pid
))
463 static int put_compat_flock(struct flock
*kfl
, struct compat_flock
*ufl
)
465 if (!access_ok(VERIFY_WRITE
, ufl
, sizeof(*ufl
)) ||
466 __put_user(kfl
->l_type
, &ufl
->l_type
) ||
467 __put_user(kfl
->l_whence
, &ufl
->l_whence
) ||
468 __put_user(kfl
->l_start
, &ufl
->l_start
) ||
469 __put_user(kfl
->l_len
, &ufl
->l_len
) ||
470 __put_user(kfl
->l_pid
, &ufl
->l_pid
))
475 #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
476 static int get_compat_flock64(struct flock
*kfl
, struct compat_flock64
*ufl
)
478 if (!access_ok(VERIFY_READ
, ufl
, sizeof(*ufl
)) ||
479 __get_user(kfl
->l_type
, &ufl
->l_type
) ||
480 __get_user(kfl
->l_whence
, &ufl
->l_whence
) ||
481 __get_user(kfl
->l_start
, &ufl
->l_start
) ||
482 __get_user(kfl
->l_len
, &ufl
->l_len
) ||
483 __get_user(kfl
->l_pid
, &ufl
->l_pid
))
489 #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
490 static int put_compat_flock64(struct flock
*kfl
, struct compat_flock64
*ufl
)
492 if (!access_ok(VERIFY_WRITE
, ufl
, sizeof(*ufl
)) ||
493 __put_user(kfl
->l_type
, &ufl
->l_type
) ||
494 __put_user(kfl
->l_whence
, &ufl
->l_whence
) ||
495 __put_user(kfl
->l_start
, &ufl
->l_start
) ||
496 __put_user(kfl
->l_len
, &ufl
->l_len
) ||
497 __put_user(kfl
->l_pid
, &ufl
->l_pid
))
503 asmlinkage
long compat_sys_fcntl64(unsigned int fd
, unsigned int cmd
,
514 ret
= get_compat_flock(&f
, compat_ptr(arg
));
519 ret
= sys_fcntl(fd
, cmd
, (unsigned long)&f
);
521 if ((cmd
== F_GETLK
) && (ret
== 0)) {
522 if ((f
.l_start
>= COMPAT_OFF_T_MAX
) ||
523 ((f
.l_start
+ f
.l_len
) >= COMPAT_OFF_T_MAX
))
526 ret
= put_compat_flock(&f
, compat_ptr(arg
));
533 ret
= get_compat_flock64(&f
, compat_ptr(arg
));
538 ret
= sys_fcntl(fd
, (cmd
== F_GETLK64
) ? F_GETLK
:
539 ((cmd
== F_SETLK64
) ? F_SETLK
: F_SETLKW
),
542 if ((cmd
== F_GETLK64
) && (ret
== 0)) {
543 if ((f
.l_start
>= COMPAT_LOFF_T_MAX
) ||
544 ((f
.l_start
+ f
.l_len
) >= COMPAT_LOFF_T_MAX
))
547 ret
= put_compat_flock64(&f
, compat_ptr(arg
));
552 ret
= sys_fcntl(fd
, cmd
, arg
);
558 asmlinkage
long compat_sys_fcntl(unsigned int fd
, unsigned int cmd
,
561 if ((cmd
== F_GETLK64
) || (cmd
== F_SETLK64
) || (cmd
== F_SETLKW64
))
563 return compat_sys_fcntl64(fd
, cmd
, arg
);
567 compat_sys_io_setup(unsigned nr_reqs
, u32
*ctx32p
)
572 mm_segment_t oldfs
= get_fs();
573 if (unlikely(get_user(ctx64
, ctx32p
)))
577 ret
= sys_io_setup(nr_reqs
, &ctx64
);
579 /* truncating is ok because it's a user address */
581 ret
= put_user((u32
) ctx64
, ctx32p
);
586 compat_sys_io_getevents(aio_context_t ctx_id
,
587 unsigned long min_nr
,
589 struct io_event
*events
,
590 struct compat_timespec
*timeout
)
594 struct timespec
*ut
= NULL
;
597 if (unlikely(!access_ok(VERIFY_WRITE
, events
,
598 nr
* sizeof(struct io_event
))))
601 if (get_compat_timespec(&t
, timeout
))
604 ut
= compat_alloc_user_space(sizeof(*ut
));
605 if (copy_to_user(ut
, &t
, sizeof(t
)) )
608 ret
= sys_io_getevents(ctx_id
, min_nr
, nr
, events
, ut
);
614 copy_iocb(long nr
, u32
*ptr32
, u64
*ptr64
)
619 for (i
= 0; i
< nr
; ++i
) {
620 if (get_user(uptr
, ptr32
+ i
))
622 if (put_user((u64
)compat_ptr(uptr
), ptr64
+ i
))
628 #define MAX_AIO_SUBMITS (PAGE_SIZE/sizeof(struct iocb *))
631 compat_sys_io_submit(aio_context_t ctx_id
, int nr
, u32
*iocb
)
633 struct iocb
**iocb64
;
636 if (unlikely(nr
< 0))
639 if (nr
> MAX_AIO_SUBMITS
)
640 nr
= MAX_AIO_SUBMITS
;
642 iocb64
= compat_alloc_user_space(nr
* sizeof(*iocb64
));
643 ret
= copy_iocb(nr
, iocb
, (u64
*) iocb64
);
645 ret
= sys_io_submit(ctx_id
, nr
, iocb64
);
649 struct compat_ncp_mount_data
{
650 compat_int_t version
;
651 compat_uint_t ncp_fd
;
652 compat_uid_t mounted_uid
;
653 compat_pid_t wdog_pid
;
654 unsigned char mounted_vol
[NCP_VOLNAME_LEN
+ 1];
655 compat_uint_t time_out
;
656 compat_uint_t retry_count
;
660 compat_mode_t file_mode
;
661 compat_mode_t dir_mode
;
664 struct compat_ncp_mount_data_v4
{
665 compat_int_t version
;
666 compat_ulong_t flags
;
667 compat_ulong_t mounted_uid
;
668 compat_long_t wdog_pid
;
669 compat_uint_t ncp_fd
;
670 compat_uint_t time_out
;
671 compat_uint_t retry_count
;
674 compat_ulong_t file_mode
;
675 compat_ulong_t dir_mode
;
678 static void *do_ncp_super_data_conv(void *raw_data
)
680 int version
= *(unsigned int *)raw_data
;
683 struct compat_ncp_mount_data
*c_n
= raw_data
;
684 struct ncp_mount_data
*n
= raw_data
;
686 n
->dir_mode
= c_n
->dir_mode
;
687 n
->file_mode
= c_n
->file_mode
;
690 memmove (n
->mounted_vol
, c_n
->mounted_vol
, (sizeof (c_n
->mounted_vol
) + 3 * sizeof (unsigned int)));
691 n
->wdog_pid
= c_n
->wdog_pid
;
692 n
->mounted_uid
= c_n
->mounted_uid
;
693 } else if (version
== 4) {
694 struct compat_ncp_mount_data_v4
*c_n
= raw_data
;
695 struct ncp_mount_data_v4
*n
= raw_data
;
697 n
->dir_mode
= c_n
->dir_mode
;
698 n
->file_mode
= c_n
->file_mode
;
701 n
->retry_count
= c_n
->retry_count
;
702 n
->time_out
= c_n
->time_out
;
703 n
->ncp_fd
= c_n
->ncp_fd
;
704 n
->wdog_pid
= c_n
->wdog_pid
;
705 n
->mounted_uid
= c_n
->mounted_uid
;
706 n
->flags
= c_n
->flags
;
707 } else if (version
!= 5) {
714 struct compat_smb_mount_data
{
715 compat_int_t version
;
716 compat_uid_t mounted_uid
;
719 compat_mode_t file_mode
;
720 compat_mode_t dir_mode
;
723 static void *do_smb_super_data_conv(void *raw_data
)
725 struct smb_mount_data
*s
= raw_data
;
726 struct compat_smb_mount_data
*c_s
= raw_data
;
728 if (c_s
->version
!= SMB_MOUNT_OLDVERSION
)
730 s
->dir_mode
= c_s
->dir_mode
;
731 s
->file_mode
= c_s
->file_mode
;
734 s
->mounted_uid
= c_s
->mounted_uid
;
739 extern int copy_mount_options (const void __user
*, unsigned long *);
741 #define SMBFS_NAME "smbfs"
742 #define NCPFS_NAME "ncpfs"
744 asmlinkage
int compat_sys_mount(char __user
* dev_name
, char __user
* dir_name
,
745 char __user
* type
, unsigned long flags
,
748 unsigned long type_page
;
749 unsigned long data_page
;
750 unsigned long dev_page
;
754 retval
= copy_mount_options (type
, &type_page
);
758 dir_page
= getname(dir_name
);
759 retval
= PTR_ERR(dir_page
);
760 if (IS_ERR(dir_page
))
763 retval
= copy_mount_options (dev_name
, &dev_page
);
767 retval
= copy_mount_options (data
, &data_page
);
774 if (!strcmp((char *)type_page
, SMBFS_NAME
)) {
775 do_smb_super_data_conv((void *)data_page
);
776 } else if (!strcmp((char *)type_page
, NCPFS_NAME
)) {
777 do_ncp_super_data_conv((void *)data_page
);
782 retval
= do_mount((char*)dev_page
, dir_page
, (char*)type_page
,
783 flags
, (void*)data_page
);
786 free_page(data_page
);
792 free_page(type_page
);