Commit ee6e00c8 authored by Jens Axboe's avatar Jens Axboe

splice: change exported internal do_splice() helper to take kernel offset

With the set_fs change, we can no longer rely on copy_{to,from}_user()
accepting a kernel pointer, and it was bad form to do so anyway. Clean
this up and change the internal helper that io_uring uses to deal with
kernel pointers instead. This puts the offset copy in/out in __do_splice()
instead, which just calls the same helper.
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 4017eb91
...@@ -1107,9 +1107,8 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, ...@@ -1107,9 +1107,8 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
/* /*
* Determine where to splice to/from. * Determine where to splice to/from.
*/ */
long do_splice(struct file *in, loff_t __user *off_in, long do_splice(struct file *in, loff_t *off_in, struct file *out,
struct file *out, loff_t __user *off_out, loff_t *off_out, size_t len, unsigned int flags)
size_t len, unsigned int flags)
{ {
struct pipe_inode_info *ipipe; struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe; struct pipe_inode_info *opipe;
...@@ -1143,8 +1142,7 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1143,8 +1142,7 @@ long do_splice(struct file *in, loff_t __user *off_in,
if (off_out) { if (off_out) {
if (!(out->f_mode & FMODE_PWRITE)) if (!(out->f_mode & FMODE_PWRITE))
return -EINVAL; return -EINVAL;
if (copy_from_user(&offset, off_out, sizeof(loff_t))) offset = *off_out;
return -EFAULT;
} else { } else {
offset = out->f_pos; offset = out->f_pos;
} }
...@@ -1165,8 +1163,8 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1165,8 +1163,8 @@ long do_splice(struct file *in, loff_t __user *off_in,
if (!off_out) if (!off_out)
out->f_pos = offset; out->f_pos = offset;
else if (copy_to_user(off_out, &offset, sizeof(loff_t))) else
ret = -EFAULT; *off_out = offset;
return ret; return ret;
} }
...@@ -1177,8 +1175,7 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1177,8 +1175,7 @@ long do_splice(struct file *in, loff_t __user *off_in,
if (off_in) { if (off_in) {
if (!(in->f_mode & FMODE_PREAD)) if (!(in->f_mode & FMODE_PREAD))
return -EINVAL; return -EINVAL;
if (copy_from_user(&offset, off_in, sizeof(loff_t))) offset = *off_in;
return -EFAULT;
} else { } else {
offset = in->f_pos; offset = in->f_pos;
} }
...@@ -1202,8 +1199,8 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1202,8 +1199,8 @@ long do_splice(struct file *in, loff_t __user *off_in,
wakeup_pipe_readers(opipe); wakeup_pipe_readers(opipe);
if (!off_in) if (!off_in)
in->f_pos = offset; in->f_pos = offset;
else if (copy_to_user(off_in, &offset, sizeof(loff_t))) else
ret = -EFAULT; *off_in = offset;
return ret; return ret;
} }
...@@ -1211,6 +1208,46 @@ long do_splice(struct file *in, loff_t __user *off_in, ...@@ -1211,6 +1208,46 @@ long do_splice(struct file *in, loff_t __user *off_in,
return -EINVAL; return -EINVAL;
} }
static long __do_splice(struct file *in, loff_t __user *off_in,
struct file *out, loff_t __user *off_out,
size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe;
loff_t offset, *__off_in = NULL, *__off_out = NULL;
long ret;
ipipe = get_pipe_info(in, true);
opipe = get_pipe_info(out, true);
if (ipipe && off_in)
return -ESPIPE;
if (opipe && off_out)
return -ESPIPE;
if (off_out) {
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
return -EFAULT;
__off_out = &offset;
}
if (off_in) {
if (copy_from_user(&offset, off_in, sizeof(loff_t)))
return -EFAULT;
__off_in = &offset;
}
ret = do_splice(in, __off_in, out, __off_out, len, flags);
if (ret < 0)
return ret;
if (__off_out && copy_to_user(off_out, __off_out, sizeof(loff_t)))
return -EFAULT;
if (__off_in && copy_to_user(off_in, __off_in, sizeof(loff_t)))
return -EFAULT;
return ret;
}
static int iter_to_pipe(struct iov_iter *from, static int iter_to_pipe(struct iov_iter *from,
struct pipe_inode_info *pipe, struct pipe_inode_info *pipe,
unsigned flags) unsigned flags)
...@@ -1405,8 +1442,8 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in, ...@@ -1405,8 +1442,8 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
if (in.file) { if (in.file) {
out = fdget(fd_out); out = fdget(fd_out);
if (out.file) { if (out.file) {
error = do_splice(in.file, off_in, out.file, off_out, error = __do_splice(in.file, off_in, out.file, off_out,
len, flags); len, flags);
fdput(out); fdput(out);
} }
fdput(in); fdput(in);
......
...@@ -78,8 +78,8 @@ extern ssize_t add_to_pipe(struct pipe_inode_info *, ...@@ -78,8 +78,8 @@ extern ssize_t add_to_pipe(struct pipe_inode_info *,
struct pipe_buffer *); struct pipe_buffer *);
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
splice_direct_actor *); splice_direct_actor *);
extern long do_splice(struct file *in, loff_t __user *off_in, extern long do_splice(struct file *in, loff_t *off_in,
struct file *out, loff_t __user *off_out, struct file *out, loff_t *off_out,
size_t len, unsigned int flags); size_t len, unsigned int flags);
extern long do_tee(struct file *in, struct file *out, size_t len, extern long do_tee(struct file *in, struct file *out, size_t len,
......
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