aboutsummaryrefslogtreecommitdiffstats
path: root/fs/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/compat.c')
-rw-r--r--fs/compat.c161
1 files changed, 91 insertions, 70 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 4b6ed03cc478..e6d5d70cf3cf 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -8,13 +8,14 @@
8 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) 8 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
9 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 9 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
10 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs 10 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
11 * Copyright (C) 2003 Pavel Machek (pavel@suse.cz) 11 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
12 * 12 *
13 * This program is free software; you can redistribute it and/or modify 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 14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation. 15 * published by the Free Software Foundation.
16 */ 16 */
17 17
18#include <linux/stddef.h>
18#include <linux/kernel.h> 19#include <linux/kernel.h>
19#include <linux/linkage.h> 20#include <linux/linkage.h>
20#include <linux/compat.h> 21#include <linux/compat.h>
@@ -266,7 +267,7 @@ asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_sta
266 error = user_path(pathname, &path); 267 error = user_path(pathname, &path);
267 if (!error) { 268 if (!error) {
268 struct kstatfs tmp; 269 struct kstatfs tmp;
269 error = vfs_statfs(path.dentry, &tmp); 270 error = vfs_statfs(&path, &tmp);
270 if (!error) 271 if (!error)
271 error = put_compat_statfs(buf, &tmp); 272 error = put_compat_statfs(buf, &tmp);
272 path_put(&path); 273 path_put(&path);
@@ -284,7 +285,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user
284 file = fget(fd); 285 file = fget(fd);
285 if (!file) 286 if (!file)
286 goto out; 287 goto out;
287 error = vfs_statfs(file->f_path.dentry, &tmp); 288 error = vfs_statfs(&file->f_path, &tmp);
288 if (!error) 289 if (!error)
289 error = put_compat_statfs(buf, &tmp); 290 error = put_compat_statfs(buf, &tmp);
290 fput(file); 291 fput(file);
@@ -334,7 +335,7 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t s
334 error = user_path(pathname, &path); 335 error = user_path(pathname, &path);
335 if (!error) { 336 if (!error) {
336 struct kstatfs tmp; 337 struct kstatfs tmp;
337 error = vfs_statfs(path.dentry, &tmp); 338 error = vfs_statfs(&path, &tmp);
338 if (!error) 339 if (!error)
339 error = put_compat_statfs64(buf, &tmp); 340 error = put_compat_statfs64(buf, &tmp);
340 path_put(&path); 341 path_put(&path);
@@ -355,7 +356,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
355 file = fget(fd); 356 file = fget(fd);
356 if (!file) 357 if (!file)
357 goto out; 358 goto out;
358 error = vfs_statfs(file->f_path.dentry, &tmp); 359 error = vfs_statfs(&file->f_path, &tmp);
359 if (!error) 360 if (!error)
360 error = put_compat_statfs64(buf, &tmp); 361 error = put_compat_statfs64(buf, &tmp);
361 fput(file); 362 fput(file);
@@ -378,7 +379,7 @@ asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u)
378 sb = user_get_super(new_decode_dev(dev)); 379 sb = user_get_super(new_decode_dev(dev));
379 if (!sb) 380 if (!sb)
380 return -EINVAL; 381 return -EINVAL;
381 err = vfs_statfs(sb->s_root, &sbuf); 382 err = statfs_by_dentry(sb->s_root, &sbuf);
382 drop_super(sb); 383 drop_super(sb);
383 if (err) 384 if (err)
384 return err; 385 return err;
@@ -568,6 +569,79 @@ out:
568 return ret; 569 return ret;
569} 570}
570 571
572/* A write operation does a read from user space and vice versa */
573#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
574
575ssize_t compat_rw_copy_check_uvector(int type,
576 const struct compat_iovec __user *uvector, unsigned long nr_segs,
577 unsigned long fast_segs, struct iovec *fast_pointer,
578 struct iovec **ret_pointer)
579{
580 compat_ssize_t tot_len;
581 struct iovec *iov = *ret_pointer = fast_pointer;
582 ssize_t ret = 0;
583 int seg;
584
585 /*
586 * SuS says "The readv() function *may* fail if the iovcnt argument
587 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
588 * traditionally returned zero for zero segments, so...
589 */
590 if (nr_segs == 0)
591 goto out;
592
593 ret = -EINVAL;
594 if (nr_segs > UIO_MAXIOV || nr_segs < 0)
595 goto out;
596 if (nr_segs > fast_segs) {
597 ret = -ENOMEM;
598 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
599 if (iov == NULL) {
600 *ret_pointer = fast_pointer;
601 goto out;
602 }
603 }
604 *ret_pointer = iov;
605
606 /*
607 * Single unix specification:
608 * We should -EINVAL if an element length is not >= 0 and fitting an
609 * ssize_t. The total length is fitting an ssize_t
610 *
611 * Be careful here because iov_len is a size_t not an ssize_t
612 */
613 tot_len = 0;
614 ret = -EINVAL;
615 for (seg = 0; seg < nr_segs; seg++) {
616 compat_ssize_t tmp = tot_len;
617 compat_uptr_t buf;
618 compat_ssize_t len;
619
620 if (__get_user(len, &uvector->iov_len) ||
621 __get_user(buf, &uvector->iov_base)) {
622 ret = -EFAULT;
623 goto out;
624 }
625 if (len < 0) /* size_t not fitting in compat_ssize_t .. */
626 goto out;
627 tot_len += len;
628 if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
629 goto out;
630 if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
631 ret = -EFAULT;
632 goto out;
633 }
634 iov->iov_base = compat_ptr(buf);
635 iov->iov_len = (compat_size_t) len;
636 uvector++;
637 iov++;
638 }
639 ret = tot_len;
640
641out:
642 return ret;
643}
644
571static inline long 645static inline long
572copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64) 646copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
573{ 647{
@@ -600,7 +674,7 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
600 iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64)); 674 iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
601 ret = copy_iocb(nr, iocb, iocb64); 675 ret = copy_iocb(nr, iocb, iocb64);
602 if (!ret) 676 if (!ret)
603 ret = sys_io_submit(ctx_id, nr, iocb64); 677 ret = do_io_submit(ctx_id, nr, iocb64, 1);
604 return ret; 678 return ret;
605} 679}
606 680
@@ -818,8 +892,6 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
818 return retval; 892 return retval;
819} 893}
820 894
821#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
822
823struct compat_old_linux_dirent { 895struct compat_old_linux_dirent {
824 compat_ulong_t d_ino; 896 compat_ulong_t d_ino;
825 compat_ulong_t d_offset; 897 compat_ulong_t d_offset;
@@ -908,7 +980,8 @@ static int compat_filldir(void *__buf, const char *name, int namlen,
908 struct compat_linux_dirent __user * dirent; 980 struct compat_linux_dirent __user * dirent;
909 struct compat_getdents_callback *buf = __buf; 981 struct compat_getdents_callback *buf = __buf;
910 compat_ulong_t d_ino; 982 compat_ulong_t d_ino;
911 int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(compat_long_t)); 983 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
984 namlen + 2, sizeof(compat_long_t));
912 985
913 buf->error = -EINVAL; /* only used if we fail.. */ 986 buf->error = -EINVAL; /* only used if we fail.. */
914 if (reclen > buf->count) 987 if (reclen > buf->count)
@@ -995,8 +1068,8 @@ static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t
995{ 1068{
996 struct linux_dirent64 __user *dirent; 1069 struct linux_dirent64 __user *dirent;
997 struct compat_getdents_callback64 *buf = __buf; 1070 struct compat_getdents_callback64 *buf = __buf;
998 int jj = NAME_OFFSET(dirent); 1071 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
999 int reclen = ALIGN(jj + namlen + 1, sizeof(u64)); 1072 sizeof(u64));
1000 u64 off; 1073 u64 off;
1001 1074
1002 buf->error = -EINVAL; /* only used if we fail.. */ 1075 buf->error = -EINVAL; /* only used if we fail.. */
@@ -1077,70 +1150,21 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
1077{ 1150{
1078 compat_ssize_t tot_len; 1151 compat_ssize_t tot_len;
1079 struct iovec iovstack[UIO_FASTIOV]; 1152 struct iovec iovstack[UIO_FASTIOV];
1080 struct iovec *iov=iovstack, *vector; 1153 struct iovec *iov;
1081 ssize_t ret; 1154 ssize_t ret;
1082 int seg;
1083 io_fn_t fn; 1155 io_fn_t fn;
1084 iov_fn_t fnv; 1156 iov_fn_t fnv;
1085 1157
1086 /*
1087 * SuS says "The readv() function *may* fail if the iovcnt argument
1088 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
1089 * traditionally returned zero for zero segments, so...
1090 */
1091 ret = 0;
1092 if (nr_segs == 0)
1093 goto out;
1094
1095 /*
1096 * First get the "struct iovec" from user memory and
1097 * verify all the pointers
1098 */
1099 ret = -EINVAL; 1158 ret = -EINVAL;
1100 if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
1101 goto out;
1102 if (!file->f_op) 1159 if (!file->f_op)
1103 goto out; 1160 goto out;
1104 if (nr_segs > UIO_FASTIOV) { 1161
1105 ret = -ENOMEM;
1106 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
1107 if (!iov)
1108 goto out;
1109 }
1110 ret = -EFAULT; 1162 ret = -EFAULT;
1111 if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector))) 1163 if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
1112 goto out; 1164 goto out;
1113 1165
1114 /* 1166 tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs,
1115 * Single unix specification: 1167 UIO_FASTIOV, iovstack, &iov);
1116 * We should -EINVAL if an element length is not >= 0 and fitting an
1117 * ssize_t. The total length is fitting an ssize_t
1118 *
1119 * Be careful here because iov_len is a size_t not an ssize_t
1120 */
1121 tot_len = 0;
1122 vector = iov;
1123 ret = -EINVAL;
1124 for (seg = 0 ; seg < nr_segs; seg++) {
1125 compat_ssize_t tmp = tot_len;
1126 compat_ssize_t len;
1127 compat_uptr_t buf;
1128
1129 if (__get_user(len, &uvector->iov_len) ||
1130 __get_user(buf, &uvector->iov_base)) {
1131 ret = -EFAULT;
1132 goto out;
1133 }
1134 if (len < 0) /* size_t not fitting an compat_ssize_t .. */
1135 goto out;
1136 tot_len += len;
1137 if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
1138 goto out;
1139 vector->iov_base = compat_ptr(buf);
1140 vector->iov_len = (compat_size_t) len;
1141 uvector++;
1142 vector++;
1143 }
1144 if (tot_len == 0) { 1168 if (tot_len == 0) {
1145 ret = 0; 1169 ret = 0;
1146 goto out; 1170 goto out;
@@ -1169,11 +1193,10 @@ out:
1169 if (iov != iovstack) 1193 if (iov != iovstack)
1170 kfree(iov); 1194 kfree(iov);
1171 if ((ret + (type == READ)) > 0) { 1195 if ((ret + (type == READ)) > 0) {
1172 struct dentry *dentry = file->f_path.dentry;
1173 if (type == READ) 1196 if (type == READ)
1174 fsnotify_access(dentry); 1197 fsnotify_access(file);
1175 else 1198 else
1176 fsnotify_modify(dentry); 1199 fsnotify_modify(file);
1177 } 1200 }
1178 return ret; 1201 return ret;
1179} 1202}
@@ -1531,8 +1554,6 @@ int compat_do_execve(char * filename,
1531 if (retval < 0) 1554 if (retval < 0)
1532 goto out; 1555 goto out;
1533 1556
1534 current->stack_start = current->mm->start_stack;
1535
1536 /* execve succeeded */ 1557 /* execve succeeded */
1537 current->fs->in_exec = 0; 1558 current->fs->in_exec = 0;
1538 current->in_execve = 0; 1559 current->in_execve = 0;