move compat_rw_copy_check_uvector() over to fs/read_write.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>zero-colors
parent
2b8910264a
commit
f502985564
76
fs/compat.c
76
fs/compat.c
|
@ -54,82 +54,6 @@
|
||||||
#include <asm/ioctls.h>
|
#include <asm/ioctls.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
/* A write operation does a read from user space and vice versa */
|
|
||||||
#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
|
|
||||||
|
|
||||||
ssize_t compat_rw_copy_check_uvector(int type,
|
|
||||||
const struct compat_iovec __user *uvector, unsigned long nr_segs,
|
|
||||||
unsigned long fast_segs, struct iovec *fast_pointer,
|
|
||||||
struct iovec **ret_pointer)
|
|
||||||
{
|
|
||||||
compat_ssize_t tot_len;
|
|
||||||
struct iovec *iov = *ret_pointer = fast_pointer;
|
|
||||||
ssize_t ret = 0;
|
|
||||||
int seg;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SuS says "The readv() function *may* fail if the iovcnt argument
|
|
||||||
* was less than or equal to 0, or greater than {IOV_MAX}. Linux has
|
|
||||||
* traditionally returned zero for zero segments, so...
|
|
||||||
*/
|
|
||||||
if (nr_segs == 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = -EINVAL;
|
|
||||||
if (nr_segs > UIO_MAXIOV)
|
|
||||||
goto out;
|
|
||||||
if (nr_segs > fast_segs) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
|
|
||||||
if (iov == NULL)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
*ret_pointer = iov;
|
|
||||||
|
|
||||||
ret = -EFAULT;
|
|
||||||
if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Single unix specification:
|
|
||||||
* We should -EINVAL if an element length is not >= 0 and fitting an
|
|
||||||
* ssize_t.
|
|
||||||
*
|
|
||||||
* In Linux, the total length is limited to MAX_RW_COUNT, there is
|
|
||||||
* no overflow possibility.
|
|
||||||
*/
|
|
||||||
tot_len = 0;
|
|
||||||
ret = -EINVAL;
|
|
||||||
for (seg = 0; seg < nr_segs; seg++) {
|
|
||||||
compat_uptr_t buf;
|
|
||||||
compat_ssize_t len;
|
|
||||||
|
|
||||||
if (__get_user(len, &uvector->iov_len) ||
|
|
||||||
__get_user(buf, &uvector->iov_base)) {
|
|
||||||
ret = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (len < 0) /* size_t not fitting in compat_ssize_t .. */
|
|
||||||
goto out;
|
|
||||||
if (type >= 0 &&
|
|
||||||
!access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
|
|
||||||
ret = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (len > MAX_RW_COUNT - tot_len)
|
|
||||||
len = MAX_RW_COUNT - tot_len;
|
|
||||||
tot_len += len;
|
|
||||||
iov->iov_base = compat_ptr(buf);
|
|
||||||
iov->iov_len = (compat_size_t) len;
|
|
||||||
uvector++;
|
|
||||||
iov++;
|
|
||||||
}
|
|
||||||
ret = tot_len;
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct compat_ncp_mount_data {
|
struct compat_ncp_mount_data {
|
||||||
compat_int_t version;
|
compat_int_t version;
|
||||||
compat_uint_t ncp_fd;
|
compat_uint_t ncp_fd;
|
||||||
|
|
|
@ -841,6 +841,81 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
ssize_t compat_rw_copy_check_uvector(int type,
|
||||||
|
const struct compat_iovec __user *uvector, unsigned long nr_segs,
|
||||||
|
unsigned long fast_segs, struct iovec *fast_pointer,
|
||||||
|
struct iovec **ret_pointer)
|
||||||
|
{
|
||||||
|
compat_ssize_t tot_len;
|
||||||
|
struct iovec *iov = *ret_pointer = fast_pointer;
|
||||||
|
ssize_t ret = 0;
|
||||||
|
int seg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SuS says "The readv() function *may* fail if the iovcnt argument
|
||||||
|
* was less than or equal to 0, or greater than {IOV_MAX}. Linux has
|
||||||
|
* traditionally returned zero for zero segments, so...
|
||||||
|
*/
|
||||||
|
if (nr_segs == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = -EINVAL;
|
||||||
|
if (nr_segs > UIO_MAXIOV)
|
||||||
|
goto out;
|
||||||
|
if (nr_segs > fast_segs) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
|
||||||
|
if (iov == NULL)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*ret_pointer = iov;
|
||||||
|
|
||||||
|
ret = -EFAULT;
|
||||||
|
if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Single unix specification:
|
||||||
|
* We should -EINVAL if an element length is not >= 0 and fitting an
|
||||||
|
* ssize_t.
|
||||||
|
*
|
||||||
|
* In Linux, the total length is limited to MAX_RW_COUNT, there is
|
||||||
|
* no overflow possibility.
|
||||||
|
*/
|
||||||
|
tot_len = 0;
|
||||||
|
ret = -EINVAL;
|
||||||
|
for (seg = 0; seg < nr_segs; seg++) {
|
||||||
|
compat_uptr_t buf;
|
||||||
|
compat_ssize_t len;
|
||||||
|
|
||||||
|
if (__get_user(len, &uvector->iov_len) ||
|
||||||
|
__get_user(buf, &uvector->iov_base)) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (len < 0) /* size_t not fitting in compat_ssize_t .. */
|
||||||
|
goto out;
|
||||||
|
if (type >= 0 &&
|
||||||
|
!access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (len > MAX_RW_COUNT - tot_len)
|
||||||
|
len = MAX_RW_COUNT - tot_len;
|
||||||
|
tot_len += len;
|
||||||
|
iov->iov_base = compat_ptr(buf);
|
||||||
|
iov->iov_len = (compat_size_t) len;
|
||||||
|
uvector++;
|
||||||
|
iov++;
|
||||||
|
}
|
||||||
|
ret = tot_len;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static ssize_t __do_readv_writev(int type, struct file *file,
|
static ssize_t __do_readv_writev(int type, struct file *file,
|
||||||
struct iov_iter *iter, loff_t *pos, int flags)
|
struct iov_iter *iter, loff_t *pos, int flags)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue