From 690dd2360cd4923f0895dce8c95ccd73d0a7062c Mon Sep 17 00:00:00 2001 From: Nicolas Lacasse Date: Thu, 9 May 2024 11:49:46 -0700 Subject: [PATCH] getdents size argument must fit in int32. PiperOrigin-RevId: 632222885 --- pkg/sentry/syscalls/linux/sys_getdents.go | 5 +++-- test/syscalls/linux/getdents.cc | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/sentry/syscalls/linux/sys_getdents.go b/pkg/sentry/syscalls/linux/sys_getdents.go index 5766327342..99e131dde7 100644 --- a/pkg/sentry/syscalls/linux/sys_getdents.go +++ b/pkg/sentry/syscalls/linux/sys_getdents.go @@ -43,7 +43,8 @@ const DirentStructBytesWithoutName = 8 + 8 + 2 + 1 + 1 func getdents(t *kernel.Task, args arch.SyscallArguments, isGetdents64 bool) (uintptr, *kernel.SyscallControl, error) { fd := args[0].Int() addr := args[1].Pointer() - size := int(args[2].Uint()) + size := args[2].Int() + if size < DirentStructBytesWithoutName { return 0, nil, linuxerr.EINVAL } @@ -64,7 +65,7 @@ func getdents(t *kernel.Task, args arch.SyscallArguments, isGetdents64 bool) (ui return 0, nil, err } - cb := getGetdentsCallback(t, int(allowedSize), size, isGetdents64) + cb := getGetdentsCallback(t, int(allowedSize), int(size), isGetdents64) err = file.IterDirents(t, cb) n, _ := t.CopyOutBytes(addr, cb.buf[:cb.copied]) diff --git a/test/syscalls/linux/getdents.cc b/test/syscalls/linux/getdents.cc index e276fc136f..64fc2ad013 100644 --- a/test/syscalls/linux/getdents.cc +++ b/test/syscalls/linux/getdents.cc @@ -503,6 +503,22 @@ TYPED_TEST(GetdentsTest, ZeroLengthOutBuffer) { SyscallFailsWithErrno(EINVAL)); } +// Tests that getdents() fails when called with too large size. +TYPED_TEST(GetdentsTest, TooLargeSize) { + auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_DIRECTORY)); + + typename TestFixture::DirentBufferType dirents(100); + // Try one over the limit. + EXPECT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(), + static_cast(INT32_MAX) + 1), + SyscallFailsWithErrno(EINVAL)); + // Try way over the limit. + EXPECT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(), + static_cast(-1)), + SyscallFailsWithErrno(EINVAL)); +} + // Some tests using the glibc readdir interface. TEST(ReaddirTest, OpenDir) { DIR* dev;