Commit 908c104c authored by David S. Miller's avatar David S. Miller

[SPARC64]: Copy over readv/writev 32-bit compat fixes from ppc64.

parent a091cf75
...@@ -952,25 +952,40 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -952,25 +952,40 @@ static long do_readv_writev32(int type, struct file *file,
io_fn_t fn; io_fn_t fn;
iov_fn_t fnv; iov_fn_t fnv;
/*
* 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...
*/
retval = 0;
if (count == 0)
goto out;
/* First get the "struct iovec" from user memory and /* First get the "struct iovec" from user memory and
* verify all the pointers * verify all the pointers
*/ */
retval = 0;
if (!count)
goto out_nofree;
retval = -EFAULT;
if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
goto out_nofree;
retval = -EINVAL; retval = -EINVAL;
if (count > UIO_MAXIOV) if (count > UIO_MAXIOV)
goto out_nofree; goto out;
if (!file->f_op)
goto out;
if (count > UIO_FASTIOV) { if (count > UIO_FASTIOV) {
retval = -ENOMEM; retval = -ENOMEM;
iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
if (!iov) if (!iov)
goto out_nofree; goto out;
} }
retval = -EFAULT;
if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
goto out;
/*
* Single unix specification:
* We should -EINVAL if an element length is not >= 0 and fitting an
* ssize_t. The total length is fitting an ssize_t
*
* Be careful here because iov_len is a size_t not an ssize_t
*/
tot_len = 0; tot_len = 0;
i = count; i = count;
ivp = iov; ivp = iov;
...@@ -980,9 +995,12 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -980,9 +995,12 @@ static long do_readv_writev32(int type, struct file *file,
compat_ssize_t len; compat_ssize_t len;
u32 buf; u32 buf;
__get_user(len, &vector->iov_len); if (__get_user(len, &vector->iov_len) ||
__get_user(buf, &vector->iov_base); __get_user(buf, &vector->iov_base)) {
if (len < 0) /* size_t not fittina an compat_ssize_t .. */ retval = -EFAULT;
goto out;
}
if (len < 0) /* size_t not fitting an ssize_t32 .. */
goto out; goto out;
tot_len += len; tot_len += len;
if (tot_len < tmp) /* maths overflow on the compat_ssize_t */ if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
...@@ -993,25 +1011,32 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -993,25 +1011,32 @@ static long do_readv_writev32(int type, struct file *file,
ivp++; ivp++;
i--; i--;
} }
if (tot_len == 0) {
retval = 0;
goto out;
}
inode = file->f_dentry->d_inode; inode = file->f_dentry->d_inode;
/* VERIFY_WRITE actually means a read, as we write to user space */ /* VERIFY_WRITE actually means a read, as we write to user space */
retval = locks_verify_area((type == VERIFY_WRITE retval = locks_verify_area((type == READ
? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
inode, file, file->f_pos, tot_len); inode, file, file->f_pos, tot_len);
if (retval) if (retval)
goto out; goto out;
/* VERIFY_WRITE actually means a read, as we write to user space */ if (type == READ) {
fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev); fn = file->f_op->read;
fnv = file->f_op->readv;
} else {
fn = (io_fn_t)file->f_op->write;
fnv = file->f_op->writev;
}
if (fnv) { if (fnv) {
retval = fnv(file, iov, count, &file->f_pos); retval = fnv(file, iov, count, &file->f_pos);
goto out; goto out;
} }
fn = (type == VERIFY_WRITE ? file->f_op->read : /* Do it by hand, with file-ops */
(io_fn_t) file->f_op->write);
ivp = iov; ivp = iov;
while (count > 0) { while (count > 0) {
void * base; void * base;
...@@ -1021,7 +1046,9 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -1021,7 +1046,9 @@ static long do_readv_writev32(int type, struct file *file,
len = ivp->iov_len; len = ivp->iov_len;
ivp++; ivp++;
count--; count--;
nr = fn(file, base, len, &file->f_pos); nr = fn(file, base, len, &file->f_pos);
if (nr < 0) { if (nr < 0) {
if (!retval) if (!retval)
retval = nr; retval = nr;
...@@ -1034,11 +1061,9 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -1034,11 +1061,9 @@ static long do_readv_writev32(int type, struct file *file,
out: out:
if (iov != iovstack) if (iov != iovstack)
kfree(iov); kfree(iov);
out_nofree: if ((retval + (type == READ)) > 0)
/* VERIFY_WRITE actually means a read, as we write to user space */
if ((retval + (type == VERIFY_WRITE)) > 0)
dnotify_parent(file->f_dentry, dnotify_parent(file->f_dentry,
(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY); (type == READ) ? DN_ACCESS : DN_MODIFY);
return retval; return retval;
} }
...@@ -1046,35 +1071,46 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -1046,35 +1071,46 @@ static long do_readv_writev32(int type, struct file *file,
asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count) asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count)
{ {
struct file *file; struct file *file;
long ret = -EBADF; int ret;
file = fget(fd); file = fget(fd);
if(!file) if(!file)
goto bad_file; return -EBADF;
if (file->f_op && (file->f_mode & FMODE_READ) && ret = -EBADF;
(file->f_op->readv || file->f_op->read)) if (!(file->f_mode & FMODE_READ))
ret = do_readv_writev32(VERIFY_WRITE, file, vector, count); goto out;
fput(file); ret = -EINVAL;
if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
goto out;
ret = do_readv_writev32(READ, file, vector, count);
bad_file: out:
fput(file);
return ret; return ret;
} }
asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count) asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count)
{ {
struct file *file; struct file *file;
int ret = -EBADF; int ret;
file = fget(fd); file = fget(fd);
if(!file) if(!file)
goto bad_file; return -EBADF;
if (file->f_op && (file->f_mode & FMODE_WRITE) &&
(file->f_op->writev || file->f_op->write))
ret = do_readv_writev32(VERIFY_READ, file, vector, count);
fput(file);
bad_file: ret = -EBADF;
if (!(file->f_mode & FMODE_WRITE))
goto out;
ret = -EINVAL;
if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
goto out;
ret = do_readv_writev32(WRITE, file, vector, count);
out:
fput(file);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment