aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2022-04-18 23:03:53 +0000
committerAlan Somers <asomers@FreeBSD.org>2022-04-19 00:59:10 +0000
commit3a1b3c6a1e68063330e897a5a5c94518edae4a3b (patch)
treed8998c93b28f460f03c2fec0da85c708f093f2fd /sys/fs
parent8b83d7e0ee54416b0ee58bd85f9c0ae7fb3357a1 (diff)
downloadsrc-3a1b3c6a1e68063330e897a5a5c94518edae4a3b.tar.gz
src-3a1b3c6a1e68063330e897a5a5c94518edae4a3b.zip
fusefs: correctly handle servers that report too much data written
During a FUSE_WRITE, the kernel requests the server to write a certain amount of data, and the server responds with the amount that it actually did write. It is obviously an error for the server to write more than it was provided, and we always treated it as such, but there were two problems: * If the server responded with a huge amount, greater than INT_MAX, it would trigger an integer overflow which would cause a panic. * When extending the file, we wrongly set the file's size before validing the amount written. PR: 263263 Reported by: Robert Morris <rtm@lcs.mit.edu> MFC after: 2 weeks Sponsored by: Axcient Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D34955
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/fuse/fuse_io.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c
index 07c0f958e028..9ef4badfcdff 100644
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -395,8 +395,19 @@ retry:
fwo = ((struct fuse_write_out *)fdi.answ);
+ if (fwo->size > fwi->size) {
+ fuse_warn(data, FSESS_WARN_WROTE_LONG,
+ "wrote more data than we provided it.");
+ /* This is bonkers. Clear attr cache. */
+ fvdat->flag &= ~FN_SIZECHANGE;
+ fuse_vnode_clear_attr_cache(vp);
+ err = EINVAL;
+ break;
+ }
+
/* Adjust the uio in the case of short writes */
diff = fwi->size - fwo->size;
+
as_written_offset = uio->uio_offset - diff;
if (as_written_offset - diff > filesize) {
@@ -406,12 +417,7 @@ retry:
if (as_written_offset - diff >= filesize)
fvdat->flag &= ~FN_SIZECHANGE;
- if (diff < 0) {
- fuse_warn(data, FSESS_WARN_WROTE_LONG,
- "wrote more data than we provided it.");
- err = EINVAL;
- break;
- } else if (diff > 0) {
+ if (diff > 0) {
/* Short write */
if (!direct_io) {
fuse_warn(data, FSESS_WARN_SHORT_WRITE,