summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/fsimpl/verity/verity.go8
-rw-r--r--test/syscalls/BUILD4
-rw-r--r--test/syscalls/linux/BUILD16
-rw-r--r--test/syscalls/linux/verity_getdents.cc95
4 files changed, 121 insertions, 2 deletions
diff --git a/pkg/sentry/fsimpl/verity/verity.go b/pkg/sentry/fsimpl/verity/verity.go
index fa7696ad6..969003613 100644
--- a/pkg/sentry/fsimpl/verity/verity.go
+++ b/pkg/sentry/fsimpl/verity/verity.go
@@ -868,6 +868,10 @@ func (fd *fileDescription) IterDirents(ctx context.Context, cb vfs.IterDirentsCa
fd.mu.Lock()
defer fd.mu.Unlock()
+ if _, err := fd.lowerFD.Seek(ctx, fd.off, linux.SEEK_SET); err != nil {
+ return err
+ }
+
var ds []vfs.Dirent
err := fd.lowerFD.IterDirents(ctx, vfs.IterDirentsCallbackFunc(func(dirent vfs.Dirent) error {
// Do not include the Merkle tree files.
@@ -890,8 +894,8 @@ func (fd *fileDescription) IterDirents(ctx context.Context, cb vfs.IterDirentsCa
return err
}
- // The result should contain all children plus "." and "..".
- if fd.d.verityEnabled() && len(ds) != len(fd.d.childrenNames)+2 {
+ // The result should be a part of all children plus "." and "..", counting from fd.off.
+ if fd.d.verityEnabled() && len(ds) != len(fd.d.childrenNames)+2-int(fd.off) {
return fd.d.fs.alertIntegrityViolation(fmt.Sprintf("Unexpected children number %d", len(ds)))
}
diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD
index 85412f54b..99743b14a 100644
--- a/test/syscalls/BUILD
+++ b/test/syscalls/BUILD
@@ -216,6 +216,10 @@ syscall_test(
)
syscall_test(
+ test = "//test/syscalls/linux:verity_getdents_test",
+)
+
+syscall_test(
test = "//test/syscalls/linux:getrandom_test",
)
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index f3df889b6..9a912dba8 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -962,6 +962,22 @@ cc_binary(
)
cc_binary(
+ name = "verity_getdents_test",
+ testonly = 1,
+ srcs = ["verity_getdents.cc"],
+ linkstatic = 1,
+ deps = [
+ "//test/util:capability_util",
+ gtest,
+ "//test/util:fs_util",
+ "//test/util:temp_path",
+ "//test/util:test_main",
+ "//test/util:test_util",
+ "//test/util:verity_util",
+ ],
+)
+
+cc_binary(
name = "getrandom_test",
testonly = 1,
srcs = ["getrandom.cc"],
diff --git a/test/syscalls/linux/verity_getdents.cc b/test/syscalls/linux/verity_getdents.cc
new file mode 100644
index 000000000..093595dd3
--- /dev/null
+++ b/test/syscalls/linux/verity_getdents.cc
@@ -0,0 +1,95 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <dirent.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/syscall.h>
+
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "test/util/capability_util.h"
+#include "test/util/fs_util.h"
+#include "test/util/temp_path.h"
+#include "test/util/test_util.h"
+#include "test/util/verity_util.h"
+
+namespace gvisor {
+namespace testing {
+
+namespace {
+
+class GetDentsTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ // Verity is implemented in VFS2.
+ SKIP_IF(IsRunningWithVFS1());
+
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
+ // Mount a tmpfs file system, to be wrapped by a verity fs.
+ tmpfs_dir_ = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ ASSERT_THAT(mount("", tmpfs_dir_.path().c_str(), "tmpfs", 0, ""),
+ SyscallSucceeds());
+
+ // Create a new file in the tmpfs mount.
+ file_ = ASSERT_NO_ERRNO_AND_VALUE(
+ TempPath::CreateFileWith(tmpfs_dir_.path(), kContents, 0777));
+ filename_ = Basename(file_.path());
+ }
+
+ TempPath tmpfs_dir_;
+ TempPath file_;
+ std::string filename_;
+};
+
+TEST_F(GetDentsTest, GetDents) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ std::vector<std::string> expect = {".", "..", filename_};
+ EXPECT_NO_ERRNO(DirContains(verity_dir, expect, /*exclude=*/{}));
+}
+
+TEST_F(GetDentsTest, Deleted) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ EXPECT_THAT(unlink(JoinPath(tmpfs_dir_.path(), filename_).c_str()),
+ SyscallSucceeds());
+
+ EXPECT_THAT(DirContains(verity_dir, /*expect=*/{}, /*exclude=*/{}),
+ PosixErrorIs(EIO, ::testing::_));
+}
+
+TEST_F(GetDentsTest, Renamed) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ std::string new_file_name = "renamed-" + filename_;
+ EXPECT_THAT(rename(JoinPath(tmpfs_dir_.path(), filename_).c_str(),
+ JoinPath(tmpfs_dir_.path(), new_file_name).c_str()),
+ SyscallSucceeds());
+
+ EXPECT_THAT(DirContains(verity_dir, /*expect=*/{}, /*exclude=*/{}),
+ PosixErrorIs(EIO, ::testing::_));
+}
+
+} // namespace
+
+} // namespace testing
+} // namespace gvisor