diff --git a/test/perf/BUILD b/test/perf/BUILD index 75b5003e2..97ca0e75a 100644 --- a/test/perf/BUILD +++ b/test/perf/BUILD @@ -139,3 +139,10 @@ syscall_test( debug = False, test = "//test/perf/linux:write_benchmark", ) + +syscall_test( + size = "large", + debug = False, + test = "//test/perf/linux:verity_open_benchmark", + vfs1 = False, +) diff --git a/test/perf/linux/BUILD b/test/perf/linux/BUILD index e76e359ff..b4f192227 100644 --- a/test/perf/linux/BUILD +++ b/test/perf/linux/BUILD @@ -370,3 +370,22 @@ cc_binary( "//test/util:test_main", ], ) + +cc_binary( + name = "verity_open_benchmark", + testonly = 1, + srcs = [ + "verity_open_benchmark.cc", + ], + deps = [ + gbenchmark, + gtest, + "//test/util:capability_util", + "//test/util:fs_util", + "//test/util:logging", + "//test/util:temp_path", + "//test/util:test_main", + "//test/util:test_util", + "//test/util:verity_util", + ], +) diff --git a/test/perf/linux/verity_open_benchmark.cc b/test/perf/linux/verity_open_benchmark.cc new file mode 100644 index 000000000..ce53a2100 --- /dev/null +++ b/test/perf/linux/verity_open_benchmark.cc @@ -0,0 +1,73 @@ +// 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 +#include +#include +#include + +#include +#include +#include + +#include "gtest/gtest.h" +#include "benchmark/benchmark.h" +#include "test/util/capability_util.h" +#include "test/util/fs_util.h" +#include "test/util/logging.h" +#include "test/util/temp_path.h" +#include "test/util/test_util.h" +#include "test/util/verity_util.h" + +namespace gvisor { +namespace testing { + +namespace { + +void BM_Open(benchmark::State& state) { + SKIP_IF(IsRunningWithVFS1()); + + const int size = state.range(0); + std::vector cache; + std::vector targets; + + // Mount a tmpfs file system to be wrapped by a verity fs. + TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + TEST_CHECK(mount("", dir.path().c_str(), "tmpfs", 0, "") == 0); + + for (int i = 0; i < size; i++) { + auto path = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path())); + targets.emplace_back( + EnableTarget(std::string(Basename(path.path())), O_RDONLY)); + cache.emplace_back(std::move(path)); + } + + std::string verity_dir = + TEST_CHECK_NO_ERRNO_AND_VALUE(MountVerity(dir.path(), targets)); + + unsigned int seed = 1; + for (auto _ : state) { + const int chosen = rand_r(&seed) % size; + int fd = open(JoinPath(verity_dir, targets[chosen].path).c_str(), O_RDONLY); + TEST_CHECK(fd != -1); + close(fd); + } +} + +BENCHMARK(BM_Open)->Range(1, 128)->UseRealTime(); + +} // namespace + +} // namespace testing +} // namespace gvisor diff --git a/test/runner/defs.bzl b/test/runner/defs.bzl index 405e03832..05c75b130 100644 --- a/test/runner/defs.bzl +++ b/test/runner/defs.bzl @@ -135,6 +135,7 @@ def syscall_test( add_overlay = False, add_uds_tree = False, add_hostinet = False, + vfs1 = True, vfs2 = True, fuse = False, debug = True, @@ -148,6 +149,7 @@ def syscall_test( add_overlay: add an overlay test. add_uds_tree: add a UDS test. add_hostinet: add a hostinet test. + vfs1: enable VFS1 tests. Could be false only if vfs2 is true. vfs2: enable VFS2 support. fuse: enable FUSE support. debug: enable debug output. @@ -157,7 +159,7 @@ def syscall_test( if not tags: tags = [] - if vfs2 and not fuse: + if vfs2 and vfs1 and not fuse: # Generate a vfs1 plain test. Most testing will now be # biased towards vfs2, with only a single vfs1 case. _syscall_test( @@ -171,7 +173,7 @@ def syscall_test( **kwargs ) - if not fuse: + if vfs1 and not fuse: # Generate a native test if fuse is not required. _syscall_test( test = test, diff --git a/test/syscalls/linux/verity_getdents.cc b/test/syscalls/linux/verity_getdents.cc index 2eafc3dd3..822a75254 100644 --- a/test/syscalls/linux/verity_getdents.cc +++ b/test/syscalls/linux/verity_getdents.cc @@ -59,7 +59,7 @@ class GetDentsTest : public ::testing::Test { TEST_F(GetDentsTest, GetDents) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); std::vector expect = {".", "..", filename_}; EXPECT_NO_ERRNO(DirContains(verity_dir, expect, /*exclude=*/{})); @@ -67,7 +67,7 @@ TEST_F(GetDentsTest, GetDents) { TEST_F(GetDentsTest, Deleted) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); EXPECT_THAT(unlink(JoinPath(tmpfs_dir_.path(), filename_).c_str()), SyscallSucceeds()); @@ -78,7 +78,7 @@ TEST_F(GetDentsTest, Deleted) { TEST_F(GetDentsTest, Renamed) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); std::string new_file_name = "renamed-" + filename_; EXPECT_THAT(rename(JoinPath(tmpfs_dir_.path(), filename_).c_str(), diff --git a/test/syscalls/linux/verity_ioctl.cc b/test/syscalls/linux/verity_ioctl.cc index e7e4fa64b..45650809c 100644 --- a/test/syscalls/linux/verity_ioctl.cc +++ b/test/syscalls/linux/verity_ioctl.cc @@ -106,7 +106,7 @@ TEST_F(IoctlTest, Measure) { TEST_F(IoctlTest, Mount) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Make sure the file can be open and read in the mounted verity fs. auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE( @@ -118,7 +118,7 @@ TEST_F(IoctlTest, Mount) { TEST_F(IoctlTest, NonExistingFile) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Confirm that opening a non-existing file in the verity-enabled directory // triggers the expected error instead of verification failure. @@ -129,7 +129,7 @@ TEST_F(IoctlTest, NonExistingFile) { TEST_F(IoctlTest, ModifiedFile) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Modify the file and check verification failure upon reading from it. auto const fd = ASSERT_NO_ERRNO_AND_VALUE( @@ -144,7 +144,7 @@ TEST_F(IoctlTest, ModifiedFile) { TEST_F(IoctlTest, ModifiedMerkle) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Modify the Merkle file and check verification failure upon opening the // corresponding file. @@ -159,7 +159,7 @@ TEST_F(IoctlTest, ModifiedMerkle) { TEST_F(IoctlTest, ModifiedDirMerkle) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Modify the Merkle file for the parent directory and check verification // failure upon opening the corresponding file. @@ -174,7 +174,7 @@ TEST_F(IoctlTest, ModifiedDirMerkle) { TEST_F(IoctlTest, Stat) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); struct stat st; EXPECT_THAT(stat(JoinPath(verity_dir, filename_).c_str(), &st), @@ -183,7 +183,7 @@ TEST_F(IoctlTest, Stat) { TEST_F(IoctlTest, ModifiedStat) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); EXPECT_THAT(chmod(JoinPath(tmpfs_dir_.path(), filename_).c_str(), 0644), SyscallSucceeds()); @@ -194,7 +194,7 @@ TEST_F(IoctlTest, ModifiedStat) { TEST_F(IoctlTest, DeleteFile) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); EXPECT_THAT(unlink(JoinPath(tmpfs_dir_.path(), filename_).c_str()), SyscallSucceeds()); @@ -204,7 +204,7 @@ TEST_F(IoctlTest, DeleteFile) { TEST_F(IoctlTest, DeleteMerkle) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); EXPECT_THAT( unlink(MerklePath(JoinPath(tmpfs_dir_.path(), filename_)).c_str()), @@ -215,7 +215,7 @@ TEST_F(IoctlTest, DeleteMerkle) { TEST_F(IoctlTest, RenameFile) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); std::string new_file_name = "renamed-" + filename_; EXPECT_THAT(rename(JoinPath(tmpfs_dir_.path(), filename_).c_str(), @@ -227,7 +227,7 @@ TEST_F(IoctlTest, RenameFile) { TEST_F(IoctlTest, RenameMerkle) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); std::string new_file_name = "renamed-" + filename_; EXPECT_THAT( diff --git a/test/syscalls/linux/verity_mmap.cc b/test/syscalls/linux/verity_mmap.cc index 09ced6eb3..2bfd43b16 100644 --- a/test/syscalls/linux/verity_mmap.cc +++ b/test/syscalls/linux/verity_mmap.cc @@ -58,7 +58,7 @@ class MmapTest : public ::testing::Test { TEST_F(MmapTest, MmapRead) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Make sure the file can be open and mmapped in the mounted verity fs. auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE( @@ -72,7 +72,7 @@ TEST_F(MmapTest, MmapRead) { TEST_F(MmapTest, ModifiedBeforeMmap) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Modify the file and check verification failure upon mmapping. auto const fd = ASSERT_NO_ERRNO_AND_VALUE( @@ -91,7 +91,7 @@ TEST_F(MmapTest, ModifiedBeforeMmap) { TEST_F(MmapTest, ModifiedAfterMmap) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE( Open(JoinPath(verity_dir, filename_), O_RDONLY, 0777)); @@ -127,7 +127,7 @@ INSTANTIATE_TEST_SUITE_P( TEST_P(MmapParamTest, Mmap) { std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, /*targets=*/{})); + MountVerity(tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY)})); // Make sure the file can be open and mmapped in the mounted verity fs. auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE( diff --git a/test/syscalls/linux/verity_symlink.cc b/test/syscalls/linux/verity_symlink.cc index bbf5375cb..c6fce8ead 100644 --- a/test/syscalls/linux/verity_symlink.cc +++ b/test/syscalls/linux/verity_symlink.cc @@ -62,9 +62,9 @@ class SymlinkTest : public ::testing::Test { }; TEST_F(SymlinkTest, Success) { - std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, - {EnableTarget(kSymlink, O_RDONLY | O_NOFOLLOW)})); + std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE(MountVerity( + tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY), + EnableTarget(kSymlink, O_RDONLY | O_NOFOLLOW)})); char buf[256]; EXPECT_THAT( @@ -77,9 +77,9 @@ TEST_F(SymlinkTest, Success) { } TEST_F(SymlinkTest, DeleteLink) { - std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, - {EnableTarget(kSymlink, O_RDONLY | O_NOFOLLOW)})); + std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE(MountVerity( + tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY), + EnableTarget(kSymlink, O_RDONLY | O_NOFOLLOW)})); ASSERT_THAT(unlink(JoinPath(tmpfs_dir_.path(), kSymlink).c_str()), SyscallSucceeds()); @@ -92,9 +92,9 @@ TEST_F(SymlinkTest, DeleteLink) { } TEST_F(SymlinkTest, ModifyLink) { - std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE( - MountVerity(tmpfs_dir_.path(), filename_, - {EnableTarget(kSymlink, O_RDONLY | O_NOFOLLOW)})); + std::string verity_dir = ASSERT_NO_ERRNO_AND_VALUE(MountVerity( + tmpfs_dir_.path(), {EnableTarget(filename_, O_RDONLY), + EnableTarget(kSymlink, O_RDONLY | O_NOFOLLOW)})); ASSERT_THAT(unlink(JoinPath(tmpfs_dir_.path(), kSymlink).c_str()), SyscallSucceeds()); diff --git a/test/util/verity_util.cc b/test/util/verity_util.cc index 501d7c2cf..b7d1cb212 100644 --- a/test/util/verity_util.cc +++ b/test/util/verity_util.cc @@ -54,20 +54,14 @@ PosixError FlipRandomBit(int fd, int size) { return NoError(); } -PosixErrorOr MountVerity(std::string tmpfs_dir, - std::string filename, +PosixErrorOr MountVerity(std::string lower_dir, std::vector targets) { - // Mount a verity fs on the existing tmpfs mount. - std::string mount_opts = "lower_path=" + tmpfs_dir; + // Mount a verity fs on the existing mount. + std::string mount_opts = "lower_path=" + lower_dir; ASSIGN_OR_RETURN_ERRNO(TempPath verity_dir, TempPath::CreateDir()); RETURN_ERROR_IF_SYSCALL_FAIL( mount("", verity_dir.path().c_str(), "verity", 0, mount_opts.c_str())); - // Enable the file, symlink(if provided) and the directory. - ASSIGN_OR_RETURN_ERRNO( - auto fd, Open(JoinPath(verity_dir.path(), filename), O_RDONLY, 0777)); - RETURN_ERROR_IF_SYSCALL_FAIL(ioctl(fd.get(), FS_IOC_ENABLE_VERITY)); - for (const EnableTarget& target : targets) { ASSIGN_OR_RETURN_ERRNO( auto target_fd, @@ -92,6 +86,7 @@ PosixErrorOr MountVerity(std::string tmpfs_dir, ASSIGN_OR_RETURN_ERRNO(TempPath verity_with_hash_dir, TempPath::CreateDir()); RETURN_ERROR_IF_SYSCALL_FAIL(mount("", verity_with_hash_dir.path().c_str(), "verity", 0, mount_opts.c_str())); + // Verity directories should not be deleted. Release the TempPath objects to // prevent those directories from being deleted by the destructor. verity_dir.release(); diff --git a/test/util/verity_util.h b/test/util/verity_util.h index 44863f322..ebb78b4bb 100644 --- a/test/util/verity_util.h +++ b/test/util/verity_util.h @@ -76,7 +76,6 @@ PosixError FlipRandomBit(int fd, int size); // Mount a verity on the tmpfs and enable both the file and the direcotry. Then // mount a new verity with measured root hash. PosixErrorOr MountVerity(std::string tmpfs_dir, - std::string filename, std::vector targets); } // namespace testing