diff options
author | Chong Cai <chongc@google.com> | 2021-04-15 22:10:17 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-04-15 22:12:37 -0700 |
commit | c980fe573d7a3488dc27c58f84aecf9ae1814f49 (patch) | |
tree | 3386a5b4493557f2d7c22b310befdd8258a3e633 | |
parent | 14b7d775c950070378ea799a0b6b7907f67a1f1e (diff) |
Add verity ioctl test for mount with root hash
PiperOrigin-RevId: 368779532
-rw-r--r-- | test/syscalls/linux/verity_ioctl.cc | 85 |
1 files changed, 70 insertions, 15 deletions
diff --git a/test/syscalls/linux/verity_ioctl.cc b/test/syscalls/linux/verity_ioctl.cc index dcd28f2c3..a81fe5724 100644 --- a/test/syscalls/linux/verity_ioctl.cc +++ b/test/syscalls/linux/verity_ioctl.cc @@ -12,8 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <stdint.h> #include <sys/mount.h> +#include <iomanip> +#include <sstream> + #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/util/capability_util.h" @@ -49,8 +53,9 @@ struct fsverity_digest { __u8 digest[]; }; -const int fsverity_max_digest_size = 64; -const int fsverity_default_digest_size = 32; +constexpr int kMaxDigestSize = 64; +constexpr int kDefaultDigestSize = 32; +constexpr char kContents[] = "foobarbaz"; class IoctlTest : public ::testing::Test { protected: @@ -65,7 +70,6 @@ class IoctlTest : public ::testing::Test { 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()); @@ -76,17 +80,26 @@ class IoctlTest : public ::testing::Test { std::string filename_; }; +// Provide a function to convert bytes to hex string, since +// absl::BytesToHexString does not seem to be compatible with golang +// hex.DecodeString used in verity due to zero-padding. +std::string BytesToHexString(uint8_t bytes[], int size) { + std::stringstream ss; + ss << std::hex; + for (int i = 0; i < size; ++i) { + ss << std::setw(2) << std::setfill('0') << static_cast<int>(bytes[i]); + } + return ss.str(); +} + TEST_F(IoctlTest, Enable) { - // mount a verity fs on the existing tmpfs mount. + // 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( @@ -101,7 +114,7 @@ TEST_F(IoctlTest, Enable) { } TEST_F(IoctlTest, Measure) { - // mount a verity fs on the existing tmpfs mount. + // 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( @@ -111,11 +124,10 @@ TEST_F(IoctlTest, Measure) { // 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; + uint8_t digest_array[sizeof(struct fsverity_digest) + kMaxDigestSize] = {0}; + struct fsverity_digest* digest = + reinterpret_cast<struct fsverity_digest*>(digest_array); + digest->digest_size = kMaxDigestSize; ASSERT_THAT(ioctl(fd.get(), FS_IOC_MEASURE_VERITY, digest), SyscallFailsWithErrno(ENODATA)); @@ -123,8 +135,51 @@ TEST_F(IoctlTest, Measure) { 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); + EXPECT_EQ(digest->digest_size, kDefaultDigestSize); +} + +TEST_F(IoctlTest, Mount) { + // Mount a verity fs on the existing tmpfs mount. + std::string mount_opts = "lower_path=" + tmpfs_dir_.path(); + auto verity_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + ASSERT_THAT( + mount("", verity_dir.path().c_str(), "verity", 0, mount_opts.c_str()), + SyscallSucceeds()); + + // Enable both the file and the directory. + auto const fd = ASSERT_NO_ERRNO_AND_VALUE( + Open(JoinPath(verity_dir.path(), filename_), O_RDONLY, 0777)); + ASSERT_THAT(ioctl(fd.get(), FS_IOC_ENABLE_VERITY), SyscallSucceeds()); + auto const dir_fd = + ASSERT_NO_ERRNO_AND_VALUE(Open(verity_dir.path(), O_RDONLY, 0777)); + ASSERT_THAT(ioctl(dir_fd.get(), FS_IOC_ENABLE_VERITY), SyscallSucceeds()); + + // Measure the root hash. + uint8_t digest_array[sizeof(struct fsverity_digest) + kMaxDigestSize] = {0}; + struct fsverity_digest* digest = + reinterpret_cast<struct fsverity_digest*>(digest_array); + digest->digest_size = kMaxDigestSize; + ASSERT_THAT(ioctl(dir_fd.get(), FS_IOC_MEASURE_VERITY, digest), + SyscallSucceeds()); + + // Mount a verity fs with specified root hash. + mount_opts += + ",root_hash=" + BytesToHexString(digest->digest, digest->digest_size); + auto verity_with_hash_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + ASSERT_THAT(mount("", verity_with_hash_dir.path().c_str(), "verity", 0, + mount_opts.c_str()), + SyscallSucceeds()); + + // Make sure the file can be open and read in the mounted verity fs. + auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE( + Open(JoinPath(verity_with_hash_dir.path(), filename_), O_RDONLY, 0777)); + char buf[16]; + EXPECT_THAT(ReadFd(fd.get(), buf, sizeof(kContents)), SyscallSucceeds()); + + // Verity directories should not be deleted. Release the TempPath objects to + // prevent those directories from being deleted by the destructor. + verity_dir.release(); + verity_with_hash_dir.release(); } } // namespace |