Created attachment 233202 [details] fuse daemon that replies to write with a huge size, causing a kernel page fault In fuse_write_directbackend(), there's a check for the case in which the daemon claims more bytes were written than the kernel asked for: diff = fwi->size - fwo->size; ...; if (diff < 0) { fuse_warn(data, FSESS_WARN_WROTE_LONG, "wrote more data than we provided it."); But fwi->size and fwo->size are 32-bit unsigned, and diff is 32-bit signed, so if fwi->size is small and fwo->size is huge, diff can end up positive. In that case, a little farther on, this can execute: void *src = (char*)fwi_data + fwo->size; memmove(fwi_data, src, diff); which, for a huge fwo->size, can cause a read through a wild pointer. I've included a demo: # uname -a FreeBSD 14.0-CURRENT FreeBSD 14.0-CURRENT #194 main-n250915-a8123f770b1e-dirty: Tue Apr 12 15:44:48 EDT 2022 rtm@xxx:/usr/obj/usr/rtm/symbsd/src/riscv.riscv64/sys/RTM riscv # pkg install fusefs-libs # cc -I/usr/local/include/fuse -o futo17a futo17a.c -L/usr/local/lib -lfuse # ./futo17a ... WARNING: FUSE protocol violation for server mounted at /mnt: short writes are only allowed with direct_io. This warning will not be repeated. ... panic: Fatal page fault at 0xffffffc000552bc4: 0xffffffd102104a0a KDB: stack backtrace: db_trace_self() at db_trace_self db_trace_self_wrapper() at db_trace_self_wrapper+0x38 kdb_backtrace() at kdb_backtrace+0x2c vpanic() at vpanic+0x16e panic() at panic+0x2a page_fault_handler() at page_fault_handler+0x1aa do_trap_supervisor() at do_trap_supervisor+0x76 cpu_exception_handler_supervisor() at cpu_exception_handler_supervisor+0x70 --- exception 13, tval = 0xffffffd102104a0a memcpy() at memcpy+0x48 fuse_write_directbackend() at fuse_write_directbackend+0x1f6 fuse_io_strategy() at fuse_io_strategy+0x1c4 fuse_vnop_strategy() at fuse_vnop_strategy+0x46 VOP_STRATEGY_APV() at VOP_STRATEGY_APV+0x32 VOP_STRATEGY() at VOP_STRATEGY+0x26 bufstrategy() at bufstrategy+0x2c bstrategy() at bstrategy+0x14 bufwrite() at bufwrite+0x184 bwrite() at bwrite+0x16 fuse_write_biobackend() at fuse_write_biobackend+0x606 fuse_vnop_write() at fuse_vnop_write+0x16a VOP_WRITE_APV() at VOP_WRITE_APV+0x66 VOP_WRITE() at VOP_WRITE+0x2e vn_write() at vn_write+0x120 vn_io_fault() at vn_io_fault+0xd6 fo_write() at fo_write+0xa dofilewrite() at dofilewrite+0x66 kern_writev() at kern_writev+0x40 sys_write() at sys_write+0x54 syscallenter() at syscallenter+0xf4 ecall_handler() at ecall_handler+0x18 do_trap_user() at do_trap_user+0xea cpu_exception_handler_user() at cpu_exception_handler_user+0x72 --- exception 8, tval = 0 KDB: enter: panic [ thread pid 88 tid 100063 ] Stopped at breakpoint+0xa: c.ldsp s0,0(sp) db>
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=3a1b3c6a1e68063330e897a5a5c94518edae4a3b commit 3a1b3c6a1e68063330e897a5a5c94518edae4a3b Author: Alan Somers <asomers@FreeBSD.org> AuthorDate: 2022-04-18 23:03:53 +0000 Commit: Alan Somers <asomers@FreeBSD.org> CommitDate: 2022-04-19 00:59:10 +0000 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 sys/fs/fuse/fuse_io.c | 18 ++++++++----- tests/sys/fs/fusefs/write.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=04f7286f44c484b4288b3071139d451ae4a623d7 commit 04f7286f44c484b4288b3071139d451ae4a623d7 Author: Alan Somers <asomers@FreeBSD.org> AuthorDate: 2022-04-18 23:03:53 +0000 Commit: Alan Somers <asomers@FreeBSD.org> CommitDate: 2022-05-12 20:39:47 +0000 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> Sponsored by: Axcient Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D34955 (cherry picked from commit 3a1b3c6a1e68063330e897a5a5c94518edae4a3b) sys/fs/fuse/fuse_io.c | 18 ++++++++----- tests/sys/fs/fusefs/write.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-)
A commit in branch stable/12 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=3a5ccf21b2aa27f51451b40be7388f671595d36a commit 3a5ccf21b2aa27f51451b40be7388f671595d36a Author: Alan Somers <asomers@FreeBSD.org> AuthorDate: 2022-04-18 23:03:53 +0000 Commit: Alan Somers <asomers@FreeBSD.org> CommitDate: 2022-08-20 00:55:25 +0000 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> Sponsored by: Axcient Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D34955 (cherry picked from commit 3a1b3c6a1e68063330e897a5a5c94518edae4a3b) sys/fs/fuse/fuse_io.c | 18 ++++++++----- tests/sys/fs/fusefs/write.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-)