Commit cc56f7de7f00d188c7c4da1e9861581853b9e92f
Committed by
Jens Axboe
1 parent
f21121cde6
Exists in
master
and in
4 other branches
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
fs/read_write.c
... | ... | @@ -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); |
fs/splice.c
... | ... | @@ -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; |