Commit cc56f7de7f00d188c7c4da1e9861581853b9e92f

Authored by Changli Gao
Committed by Jens Axboe
1 parent f21121cde6

sendfile(): check f_op.splice_write() rather than f_op.sendpage()

sendfile(2) was reworked with the splice infrastructure, but it still
checks f_op.sendpage() instead of f_op.splice_write() wrongly.  Although
if f_op.sendpage() exists, f_op.splice_write() always exists at the same
time currently, the assumption will be broken in future silently.  This
patch also brings a side effect: sendfile(2) can work with any output
file.  Some security checks related to f_op are added too.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

Showing 2 changed files with 15 additions and 11 deletions Side-by-side Diff

... ... @@ -826,8 +826,6 @@
826 826 if (!(out_file->f_mode & FMODE_WRITE))
827 827 goto fput_out;
828 828 retval = -EINVAL;
829   - if (!out_file->f_op || !out_file->f_op->sendpage)
830   - goto fput_out;
831 829 in_inode = in_file->f_path.dentry->d_inode;
832 830 out_inode = out_file->f_path.dentry->d_inode;
833 831 retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
... ... @@ -648,9 +648,11 @@
648 648 ret = buf->ops->confirm(pipe, buf);
649 649 if (!ret) {
650 650 more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
651   -
652   - ret = file->f_op->sendpage(file, buf->page, buf->offset,
653   - sd->len, &pos, more);
  651 + if (file->f_op && file->f_op->sendpage)
  652 + ret = file->f_op->sendpage(file, buf->page, buf->offset,
  653 + sd->len, &pos, more);
  654 + else
  655 + ret = -EINVAL;
654 656 }
655 657  
656 658 return ret;
... ... @@ -1068,8 +1070,9 @@
1068 1070 if (unlikely(ret < 0))
1069 1071 return ret;
1070 1072  
1071   - splice_write = out->f_op->splice_write;
1072   - if (!splice_write)
  1073 + if (out->f_op && out->f_op->splice_write)
  1074 + splice_write = out->f_op->splice_write;
  1075 + else
1073 1076 splice_write = default_file_splice_write;
1074 1077  
1075 1078 return splice_write(pipe, out, ppos, len, flags);
... ... @@ -1093,8 +1096,9 @@
1093 1096 if (unlikely(ret < 0))
1094 1097 return ret;
1095 1098  
1096   - splice_read = in->f_op->splice_read;
1097   - if (!splice_read)
  1099 + if (in->f_op && in->f_op->splice_read)
  1100 + splice_read = in->f_op->splice_read;
  1101 + else
1098 1102 splice_read = default_file_splice_read;
1099 1103  
1100 1104 return splice_read(in, ppos, pipe, len, flags);
... ... @@ -1316,7 +1320,8 @@
1316 1320 if (off_in)
1317 1321 return -ESPIPE;
1318 1322 if (off_out) {
1319   - if (out->f_op->llseek == no_llseek)
  1323 + if (!out->f_op || !out->f_op->llseek ||
  1324 + out->f_op->llseek == no_llseek)
1320 1325 return -EINVAL;
1321 1326 if (copy_from_user(&offset, off_out, sizeof(loff_t)))
1322 1327 return -EFAULT;
... ... @@ -1336,7 +1341,8 @@
1336 1341 if (off_out)
1337 1342 return -ESPIPE;
1338 1343 if (off_in) {
1339   - if (in->f_op->llseek == no_llseek)
  1344 + if (!in->f_op || !in->f_op->llseek ||
  1345 + in->f_op->llseek == no_llseek)
1340 1346 return -EINVAL;
1341 1347 if (copy_from_user(&offset, off_in, sizeof(loff_t)))
1342 1348 return -EFAULT;