Skip to content

Commit ee6e00c

Browse files
committed
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>
1 parent 4017eb9 commit ee6e00c

2 files changed

Lines changed: 52 additions & 15 deletions

File tree

fs/splice.c

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,9 +1107,8 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
11071107
/*
11081108
* Determine where to splice to/from.
11091109
*/
1110-
long do_splice(struct file *in, loff_t __user *off_in,
1111-
struct file *out, loff_t __user *off_out,
1112-
size_t len, unsigned int flags)
1110+
long do_splice(struct file *in, loff_t *off_in, struct file *out,
1111+
loff_t *off_out, size_t len, unsigned int flags)
11131112
{
11141113
struct pipe_inode_info *ipipe;
11151114
struct pipe_inode_info *opipe;
@@ -1143,8 +1142,7 @@ long do_splice(struct file *in, loff_t __user *off_in,
11431142
if (off_out) {
11441143
if (!(out->f_mode & FMODE_PWRITE))
11451144
return -EINVAL;
1146-
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
1147-
return -EFAULT;
1145+
offset = *off_out;
11481146
} else {
11491147
offset = out->f_pos;
11501148
}
@@ -1165,8 +1163,8 @@ long do_splice(struct file *in, loff_t __user *off_in,
11651163

11661164
if (!off_out)
11671165
out->f_pos = offset;
1168-
else if (copy_to_user(off_out, &offset, sizeof(loff_t)))
1169-
ret = -EFAULT;
1166+
else
1167+
*off_out = offset;
11701168

11711169
return ret;
11721170
}
@@ -1177,8 +1175,7 @@ long do_splice(struct file *in, loff_t __user *off_in,
11771175
if (off_in) {
11781176
if (!(in->f_mode & FMODE_PREAD))
11791177
return -EINVAL;
1180-
if (copy_from_user(&offset, off_in, sizeof(loff_t)))
1181-
return -EFAULT;
1178+
offset = *off_in;
11821179
} else {
11831180
offset = in->f_pos;
11841181
}
@@ -1202,15 +1199,55 @@ long do_splice(struct file *in, loff_t __user *off_in,
12021199
wakeup_pipe_readers(opipe);
12031200
if (!off_in)
12041201
in->f_pos = offset;
1205-
else if (copy_to_user(off_in, &offset, sizeof(loff_t)))
1206-
ret = -EFAULT;
1202+
else
1203+
*off_in = offset;
12071204

12081205
return ret;
12091206
}
12101207

12111208
return -EINVAL;
12121209
}
12131210

1211+
static long __do_splice(struct file *in, loff_t __user *off_in,
1212+
struct file *out, loff_t __user *off_out,
1213+
size_t len, unsigned int flags)
1214+
{
1215+
struct pipe_inode_info *ipipe;
1216+
struct pipe_inode_info *opipe;
1217+
loff_t offset, *__off_in = NULL, *__off_out = NULL;
1218+
long ret;
1219+
1220+
ipipe = get_pipe_info(in, true);
1221+
opipe = get_pipe_info(out, true);
1222+
1223+
if (ipipe && off_in)
1224+
return -ESPIPE;
1225+
if (opipe && off_out)
1226+
return -ESPIPE;
1227+
1228+
if (off_out) {
1229+
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
1230+
return -EFAULT;
1231+
__off_out = &offset;
1232+
}
1233+
if (off_in) {
1234+
if (copy_from_user(&offset, off_in, sizeof(loff_t)))
1235+
return -EFAULT;
1236+
__off_in = &offset;
1237+
}
1238+
1239+
ret = do_splice(in, __off_in, out, __off_out, len, flags);
1240+
if (ret < 0)
1241+
return ret;
1242+
1243+
if (__off_out && copy_to_user(off_out, __off_out, sizeof(loff_t)))
1244+
return -EFAULT;
1245+
if (__off_in && copy_to_user(off_in, __off_in, sizeof(loff_t)))
1246+
return -EFAULT;
1247+
1248+
return ret;
1249+
}
1250+
12141251
static int iter_to_pipe(struct iov_iter *from,
12151252
struct pipe_inode_info *pipe,
12161253
unsigned flags)
@@ -1405,8 +1442,8 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
14051442
if (in.file) {
14061443
out = fdget(fd_out);
14071444
if (out.file) {
1408-
error = do_splice(in.file, off_in, out.file, off_out,
1409-
len, flags);
1445+
error = __do_splice(in.file, off_in, out.file, off_out,
1446+
len, flags);
14101447
fdput(out);
14111448
}
14121449
fdput(in);

include/linux/splice.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ extern ssize_t add_to_pipe(struct pipe_inode_info *,
7878
struct pipe_buffer *);
7979
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
8080
splice_direct_actor *);
81-
extern long do_splice(struct file *in, loff_t __user *off_in,
82-
struct file *out, loff_t __user *off_out,
81+
extern long do_splice(struct file *in, loff_t *off_in,
82+
struct file *out, loff_t *off_out,
8383
size_t len, unsigned int flags);
8484

8585
extern long do_tee(struct file *in, struct file *out, size_t len,

0 commit comments

Comments
 (0)