diff --git a/pkg/sentry/devices/tundev/BUILD b/pkg/sentry/devices/tundev/BUILD index 60c971030..a2fc2917e 100644 --- a/pkg/sentry/devices/tundev/BUILD +++ b/pkg/sentry/devices/tundev/BUILD @@ -20,5 +20,6 @@ go_library( "//pkg/tcpip/link/tun", "//pkg/usermem", "//pkg/waiter", + "@org_golang_x_sys//unix:go_default_library", ], ) diff --git a/pkg/sentry/devices/tundev/tundev.go b/pkg/sentry/devices/tundev/tundev.go index c98c8d3f8..f8efd0ed0 100644 --- a/pkg/sentry/devices/tundev/tundev.go +++ b/pkg/sentry/devices/tundev/tundev.go @@ -16,6 +16,7 @@ package tundev import ( + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" @@ -139,6 +140,9 @@ func (fd *tunFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int6 // Write implements vfs.FileDescriptionImpl.Write. func (fd *tunFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) { + if src.NumBytes() == 0 { + return 0, unix.EINVAL + } data := make([]byte, src.NumBytes()) if _, err := src.CopyIn(ctx, data); err != nil { return 0, err diff --git a/pkg/sentry/fs/dev/BUILD b/pkg/sentry/fs/dev/BUILD index 7baf26b24..5fb5acaae 100644 --- a/pkg/sentry/fs/dev/BUILD +++ b/pkg/sentry/fs/dev/BUILD @@ -37,5 +37,6 @@ go_library( "//pkg/tcpip/link/tun", "//pkg/usermem", "//pkg/waiter", + "@org_golang_x_sys//unix:go_default_library", ], ) diff --git a/pkg/sentry/fs/dev/net_tun.go b/pkg/sentry/fs/dev/net_tun.go index 89aa2666d..c5b7871cc 100644 --- a/pkg/sentry/fs/dev/net_tun.go +++ b/pkg/sentry/fs/dev/net_tun.go @@ -15,6 +15,7 @@ package dev import ( + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" @@ -131,6 +132,9 @@ func (n *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io user // Write implements fs.FileOperations.Write. func (n *netTunFileOperations) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) { + if src.NumBytes() == 0 { + return 0, unix.EINVAL + } data := make([]byte, src.NumBytes()) if _, err := src.CopyIn(ctx, data); err != nil { return 0, err diff --git a/test/syscalls/linux/tuntap.cc b/test/syscalls/linux/tuntap.cc index 956208bee..e2ceba366 100644 --- a/test/syscalls/linux/tuntap.cc +++ b/test/syscalls/linux/tuntap.cc @@ -269,6 +269,17 @@ TEST_F(TuntapTest, InvalidReadWrite) { EXPECT_THAT(write(fd.get(), buf, sizeof(buf)), SyscallFailsWithErrno(EBADFD)); } +TEST_F(TuntapTest, ZeroWrite) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN))); + + FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(kDevNetTun, O_RDWR)); + struct ifreq ifr_set = {}; + ifr_set.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr_set.ifr_name, kTunName, IFNAMSIZ); + EXPECT_THAT(ioctl(fd.get(), TUNSETIFF, &ifr_set), SyscallSucceeds()); + EXPECT_THAT(write(fd.get(), nullptr, 0), SyscallFailsWithErrno(EINVAL)); +} + TEST_F(TuntapTest, WriteToDownDevice) { SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));