summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChong Cai <chongc@google.com>2021-04-05 17:29:30 -0700
committergVisor bot <gvisor-bot@google.com>2021-04-05 17:31:48 -0700
commit63340e61388621d41a5abb08d8902a1565d02a96 (patch)
tree91092da84c466632de4b665a870a81c9d066e590
parent661e5ae7ae496332c0b5440980d0a9a00f9b9fbd (diff)
Add initial verity ioctl syscall tests
PiperOrigin-RevId: 366907152
-rw-r--r--test/syscalls/BUILD4
-rw-r--r--test/syscalls/linux/BUILD16
-rw-r--r--test/syscalls/linux/verity_ioctl.cc133
3 files changed, 153 insertions, 0 deletions
diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD
index 9d474569c..affcae8fd 100644
--- a/test/syscalls/BUILD
+++ b/test/syscalls/BUILD
@@ -244,6 +244,10 @@ syscall_test(
)
syscall_test(
+ test = "//test/syscalls/linux:verity_ioctl_test",
+)
+
+syscall_test(
test = "//test/syscalls/linux:iptables_test",
)
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 4571c706b..bc2c7c0e3 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -1014,6 +1014,22 @@ cc_binary(
],
)
+cc_binary(
+ name = "verity_ioctl_test",
+ testonly = 1,
+ srcs = ["verity_ioctl.cc"],
+ linkstatic = 1,
+ deps = [
+ "//test/util:capability_util",
+ gtest,
+ "//test/util:fs_util",
+ "//test/util:mount_util",
+ "//test/util:temp_path",
+ "//test/util:test_main",
+ "//test/util:test_util",
+ ],
+)
+
cc_library(
name = "iptables_types",
testonly = 1,
diff --git a/test/syscalls/linux/verity_ioctl.cc b/test/syscalls/linux/verity_ioctl.cc
new file mode 100644
index 000000000..dcd28f2c3
--- /dev/null
+++ b/test/syscalls/linux/verity_ioctl.cc
@@ -0,0 +1,133 @@
+// 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 <sys/mount.h>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "test/util/capability_util.h"
+#include "test/util/fs_util.h"
+#include "test/util/mount_util.h"
+#include "test/util/temp_path.h"
+#include "test/util/test_util.h"
+
+namespace gvisor {
+namespace testing {
+
+namespace {
+
+#ifndef FS_IOC_ENABLE_VERITY
+#define FS_IOC_ENABLE_VERITY 1082156677
+#endif
+
+#ifndef FS_IOC_MEASURE_VERITY
+#define FS_IOC_MEASURE_VERITY 3221513862
+#endif
+
+#ifndef FS_VERITY_FL
+#define FS_VERITY_FL 1048576
+#endif
+
+#ifndef FS_IOC_GETFLAGS
+#define FS_IOC_GETFLAGS 2148034049
+#endif
+
+struct fsverity_digest {
+ __u16 digest_algorithm;
+ __u16 digest_size; /* input/output */
+ __u8 digest[];
+};
+
+const int fsverity_max_digest_size = 64;
+const int fsverity_default_digest_size = 32;
+
+class IoctlTest : 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.
+ constexpr char kContents[] = "foobarbaz";
+ 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(IoctlTest, Enable) {
+ // mount a verity fs on the existing tmpfs mount.
+ std::string mount_opts = "lower_path=" + tmpfs_dir_.path();
+ auto const verity_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ ASSERT_THAT(
+ mount("", verity_dir.path().c_str(), "verity", 0, mount_opts.c_str()),
+ SyscallSucceeds());
+
+ printf("verity path: %s, filename: %s\n", verity_dir.path().c_str(),
+ filename_.c_str());
+ fflush(nullptr);
+ // Confirm that the verity flag is absent.
+ int flag = 0;
+ auto const fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(verity_dir.path(), filename_), O_RDONLY, 0777));
+ ASSERT_THAT(ioctl(fd.get(), FS_IOC_GETFLAGS, &flag), SyscallSucceeds());
+ EXPECT_EQ(flag & FS_VERITY_FL, 0);
+
+ // Enable the file and confirm that the verity flag is present.
+ ASSERT_THAT(ioctl(fd.get(), FS_IOC_ENABLE_VERITY), SyscallSucceeds());
+ ASSERT_THAT(ioctl(fd.get(), FS_IOC_GETFLAGS, &flag), SyscallSucceeds());
+ EXPECT_EQ(flag & FS_VERITY_FL, FS_VERITY_FL);
+}
+
+TEST_F(IoctlTest, Measure) {
+ // mount a verity fs on the existing tmpfs mount.
+ std::string mount_opts = "lower_path=" + tmpfs_dir_.path();
+ auto const verity_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ ASSERT_THAT(
+ mount("", verity_dir.path().c_str(), "verity", 0, mount_opts.c_str()),
+ SyscallSucceeds());
+
+ // Confirm that the file cannot be measured.
+ auto const fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(verity_dir.path(), filename_), O_RDONLY, 0777));
+ int digest_size = sizeof(struct fsverity_digest) + fsverity_max_digest_size;
+ struct fsverity_digest *digest =
+ reinterpret_cast<struct fsverity_digest *>(malloc(digest_size));
+ memset(digest, 0, digest_size);
+ digest->digest_size = fsverity_max_digest_size;
+ ASSERT_THAT(ioctl(fd.get(), FS_IOC_MEASURE_VERITY, digest),
+ SyscallFailsWithErrno(ENODATA));
+
+ // Enable the file and confirm that the file can be measured.
+ ASSERT_THAT(ioctl(fd.get(), FS_IOC_ENABLE_VERITY), SyscallSucceeds());
+ ASSERT_THAT(ioctl(fd.get(), FS_IOC_MEASURE_VERITY, digest),
+ SyscallSucceeds());
+ EXPECT_EQ(digest->digest_size, fsverity_default_digest_size);
+ free(digest);
+}
+
+} // namespace
+
+} // namespace testing
+} // namespace gvisor