From 474878635025df289b63e488b6c6b7e1513cc9c1 Mon Sep 17 00:00:00 2001 From: Jamie Liu Date: Tue, 6 Aug 2024 14:25:44 -0700 Subject: [PATCH] fuse: check write() length correctness This is consistent with Linux's fs/fuse/dev.c:fuse_do_dev_write(). PiperOrigin-RevId: 660096450 --- pkg/sentry/fsimpl/fuse/dev.go | 8 +++++++- test/syscalls/linux/fuse.cc | 28 +++++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/pkg/sentry/fsimpl/fuse/dev.go b/pkg/sentry/fsimpl/fuse/dev.go index cc88c7081..501ad088b 100644 --- a/pkg/sentry/fsimpl/fuse/dev.go +++ b/pkg/sentry/fsimpl/fuse/dev.go @@ -225,12 +225,18 @@ func (fd *DeviceFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs. return 0, linuxerr.EPERM } + var hdr linux.FUSEHeaderOut + if src.NumBytes() < int64(hdr.SizeBytes()) { + return 0, linuxerr.EINVAL + } n, err := src.CopyIn(ctx, fd.writeBuf[:]) if err != nil { return 0, err } - var hdr linux.FUSEHeaderOut hdr.UnmarshalBytes(fd.writeBuf[:]) + if src.NumBytes() != int64(hdr.Len) { + return 0, linuxerr.EINVAL + } fut, ok := fd.completions[hdr.Unique] if !ok { diff --git a/test/syscalls/linux/fuse.cc b/test/syscalls/linux/fuse.cc index f24b0b895..f2b267ad0 100644 --- a/test/syscalls/linux/fuse.cc +++ b/test/syscalls/linux/fuse.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -32,10 +33,13 @@ #include "test/util/file_descriptor.h" #include "test/util/fs_util.h" #include "test/util/linux_capability_util.h" +#include "test/util/mount_util.h" #include "test/util/posix_error.h" #include "test/util/temp_path.h" #include "test/util/test_util.h" +using ::testing::Ge; + namespace gvisor { namespace testing { @@ -49,21 +53,19 @@ TEST(FuseTest, RejectBadInit) { auto mount_point = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); auto mount_opts = absl::StrFormat("fd=%d,user_id=0,group_id=0,rootmode=40000", fd.get()); + auto mount = ASSERT_NO_ERRNO_AND_VALUE( + Mount("fuse", mount_point.path(), "fuse", MS_NODEV | MS_NOSUID, + mount_opts, 0 /* umountflags */)); - EXPECT_THAT(mount("fuse", mount_point.path().c_str(), "fuse", - MS_NODEV | MS_NOSUID, mount_opts.c_str()), - SyscallSucceeds()); - mount_point.release(); + // Read the init request so that we have the correct unique ID. + alignas(fuse_in_header) char req_buf[FUSE_MIN_READ_BUFFER]; + ASSERT_THAT(read(fd.get(), req_buf, sizeof(req_buf)), + SyscallSucceedsWithValue(Ge(sizeof(fuse_in_header)))); - struct response { - uint32_t len; - int32_t err; - uint64_t uid; - } resp; - // min value for length is 24 + sizeof(response) - resp.len = 24 + sizeof(resp) - 1; - resp.err = 0; - resp.uid = 2; + fuse_out_header resp; + resp.len = sizeof(resp) - 1; + resp.error = 0; + resp.unique = reinterpret_cast(req_buf)->unique; ASSERT_THAT(write(fd.get(), reinterpret_cast(&resp), sizeof(resp)), SyscallFailsWithErrno(EINVAL));