@@ -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+
12141251static 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 );
0 commit comments