fuse: check write() length correctness

This is consistent with Linux's fs/fuse/dev.c:fuse_do_dev_write().

PiperOrigin-RevId: 660096450
This commit is contained in:
Jamie Liu
2024-08-06 14:30:22 -07:00
committed by gVisor bot
parent b1d7ceafb1
commit 4748786350
2 changed files with 22 additions and 14 deletions
+7 -1
View File
@@ -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 {
+15 -13
View File
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <linux/capability.h>
#include <linux/fuse.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/stat.h>
@@ -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<fuse_in_header*>(req_buf)->unique;
ASSERT_THAT(write(fd.get(), reinterpret_cast<char*>(&resp), sizeof(resp)),
SyscallFailsWithErrno(EINVAL));