X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fcompat.c;h=271b75d1597f507bacbd78b7be31227d5492dd2e;hb=7e78e5e502d4f220d24c6f738f2fdb078ad33607;hp=6b06b6bae35e52cd078efaaabe19198007a4b36d;hpb=0eeca28300df110bd6ed54b31193c83b87921443;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/compat.c b/fs/compat.c index 6b06b6b..271b75d 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include /* siocdevprivate_ioctl */ @@ -166,8 +168,8 @@ asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs if (!error) { struct kstatfs tmp; error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs(buf, &tmp); path_release(&nd); } return error; @@ -184,8 +186,8 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user if (!file) goto out; error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs(buf, &tmp); fput(file); out: return error; @@ -234,8 +236,8 @@ asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, s if (!error) { struct kstatfs tmp; error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs64(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs64(buf, &tmp); path_release(&nd); } return error; @@ -255,8 +257,8 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c if (!file) goto out; error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs64(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs64(buf, &tmp); fput(file); out: return error; @@ -266,7 +268,6 @@ out: #define IOCTL_HASHSIZE 256 static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; -static DECLARE_RWSEM(ioctl32_sem); extern struct ioctl_trans ioctl_start[]; extern int ioctl_table_size; @@ -310,96 +311,6 @@ static int __init init_sys32_ioctl(void) __initcall(init_sys32_ioctl); -int register_ioctl32_conversion(unsigned int cmd, - ioctl_trans_handler_t handler) -{ - struct ioctl_trans *t; - struct ioctl_trans *new_t; - unsigned long hash = ioctl32_hash(cmd); - - new_t = kmalloc(sizeof(*new_t), GFP_KERNEL); - if (!new_t) - return -ENOMEM; - - down_write(&ioctl32_sem); - for (t = ioctl32_hash_table[hash]; t; t = t->next) { - if (t->cmd == cmd) { - printk(KERN_ERR "Trying to register duplicated ioctl32 " - "handler %x\n", cmd); - up_write(&ioctl32_sem); - kfree(new_t); - return -EINVAL; - } - } - new_t->next = NULL; - new_t->cmd = cmd; - new_t->handler = handler; - ioctl32_insert_translation(new_t); - - up_write(&ioctl32_sem); - return 0; -} -EXPORT_SYMBOL(register_ioctl32_conversion); - -static inline int builtin_ioctl(struct ioctl_trans *t) -{ - return t >= ioctl_start && t < (ioctl_start + ioctl_table_size); -} - -/* Problem: - This function cannot unregister duplicate ioctls, because they are not - unique. - When they happen we need to extend the prototype to pass the handler too. */ - -int unregister_ioctl32_conversion(unsigned int cmd) -{ - unsigned long hash = ioctl32_hash(cmd); - struct ioctl_trans *t, *t1; - - down_write(&ioctl32_sem); - - t = ioctl32_hash_table[hash]; - if (!t) { - up_write(&ioctl32_sem); - return -EINVAL; - } - - if (t->cmd == cmd) { - if (builtin_ioctl(t)) { - printk("%p tried to unregister builtin ioctl %x\n", - __builtin_return_address(0), cmd); - } else { - ioctl32_hash_table[hash] = t->next; - up_write(&ioctl32_sem); - kfree(t); - return 0; - } - } - while (t->next) { - t1 = t->next; - if (t1->cmd == cmd) { - if (builtin_ioctl(t1)) { - printk("%p tried to unregister builtin " - "ioctl %x\n", - __builtin_return_address(0), cmd); - goto out; - } else { - t->next = t1->next; - up_write(&ioctl32_sem); - kfree(t1); - return 0; - } - } - t = t1; - } - printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", - cmd); -out: - up_write(&ioctl32_sem); - return -EINVAL; -} -EXPORT_SYMBOL(unregister_ioctl32_conversion); - static void compat_ioctl_error(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg) { @@ -478,14 +389,10 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, break; } - /* When register_ioctl32_conversion is finally gone remove - this lock! -AK */ - down_read(&ioctl32_sem); for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { if (t->cmd == cmd) goto found_handler; } - up_read(&ioctl32_sem); if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) && cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { @@ -505,11 +412,9 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, lock_kernel(); error = t->handler(fd, cmd, arg, filp); unlock_kernel(); - up_read(&ioctl32_sem); goto out_fput; } - up_read(&ioctl32_sem); do_ioctl: error = vfs_ioctl(filp, fd, cmd, arg); out_fput: @@ -589,9 +494,21 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs(old_fs); if (cmd == F_GETLK && ret == 0) { - if ((f.l_start >= COMPAT_OFF_T_MAX) || - ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX)) + /* GETLK was successfule and we need to return the data... + * but it needs to fit in the compat structure. + * l_start shouldn't be too big, unless the original + * start + end is greater than COMPAT_OFF_T_MAX, in which + * case the app was asking for trouble, so we return + * -EOVERFLOW in that case. + * l_len could be too big, in which case we just truncate it, + * and only allow the app to see that part of the conflicting + * lock that might make sense to it anyway + */ + + if (f.l_start > COMPAT_OFF_T_MAX) ret = -EOVERFLOW; + if (f.l_len > COMPAT_OFF_T_MAX) + f.l_len = COMPAT_OFF_T_MAX; if (ret == 0) ret = put_compat_flock(&f, compat_ptr(arg)); } @@ -610,9 +527,11 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, (unsigned long)&f); set_fs(old_fs); if (cmd == F_GETLK64 && ret == 0) { - if ((f.l_start >= COMPAT_LOFF_T_MAX) || - ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX)) + /* need to return lock information - see above for commentary */ + if (f.l_start > COMPAT_LOFF_T_MAX) ret = -EOVERFLOW; + if (f.l_len > COMPAT_LOFF_T_MAX) + f.l_len = COMPAT_LOFF_T_MAX; if (ret == 0) ret = put_compat_flock64(&f, compat_ptr(arg)); } @@ -720,14 +639,14 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb) struct compat_ncp_mount_data { compat_int_t version; compat_uint_t ncp_fd; - compat_uid_t mounted_uid; + __compat_uid_t mounted_uid; compat_pid_t wdog_pid; unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; compat_uint_t time_out; compat_uint_t retry_count; compat_uint_t flags; - compat_uid_t uid; - compat_gid_t gid; + __compat_uid_t uid; + __compat_gid_t gid; compat_mode_t file_mode; compat_mode_t dir_mode; }; @@ -784,9 +703,9 @@ static void *do_ncp_super_data_conv(void *raw_data) struct compat_smb_mount_data { compat_int_t version; - compat_uid_t mounted_uid; - compat_uid_t uid; - compat_gid_t gid; + __compat_uid_t mounted_uid; + __compat_uid_t uid; + __compat_gid_t gid; compat_mode_t file_mode; compat_mode_t dir_mode; }; @@ -1265,7 +1184,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, } ret = rw_verify_area(type, file, pos, tot_len); - if (ret) + if (ret < 0) goto out; fnv = NULL; @@ -1365,6 +1284,16 @@ out: } /* + * Exactly like fs/open.c:sys_open(), except that it doesn't set the + * O_LARGEFILE flag. + */ +asmlinkage long +compat_sys_open(const char __user *filename, int flags, int mode) +{ + return do_sys_open(filename, flags, mode); +} + +/* * compat_count() counts the number of arguments/envelopes. It is basically * a copy of count() from fs/exec.c, except that it works with 32 bit argv * and envp pointers. @@ -1567,6 +1496,7 @@ int compat_do_execve(char * filename, /* execve success */ security_bprm_free(bprm); + acct_update_integrals(current); kfree(bprm); return retval; } @@ -1699,6 +1629,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp char *bits; long timeout; int size, max_fdset, ret = -EINVAL; + struct fdtable *fdt; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -1724,7 +1655,10 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp goto out_nofds; /* max_fdset can increase, so grab it once to avoid race */ - max_fdset = current->files->max_fdset; + rcu_read_lock(); + fdt = files_fdtable(current->files); + max_fdset = fdt->max_fdset; + rcu_read_unlock(); if (n > max_fdset) n = max_fdset; @@ -1808,8 +1742,8 @@ struct compat_nfsctl_export { compat_dev_t ex32_dev; compat_ino_t ex32_ino; compat_int_t ex32_flags; - compat_uid_t ex32_anon_uid; - compat_gid_t ex32_anon_gid; + __compat_uid_t ex32_anon_uid; + __compat_gid_t ex32_anon_gid; }; struct compat_nfsctl_fdparm {