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: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
4017eb91a9
commit
ee6e00c868
63
fs/splice.c
63
fs/splice.c
@ -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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 *,
|
|||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user