github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/util/verity_util.cc (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "test/util/verity_util.h" 16 17 #include "test/util/fs_util.h" 18 #include "test/util/mount_util.h" 19 #include "test/util/temp_path.h" 20 21 namespace gvisor { 22 namespace testing { 23 24 std::string BytesToHexString(uint8_t bytes[], int size) { 25 std::stringstream ss; 26 ss << std::hex; 27 for (int i = 0; i < size; ++i) { 28 ss << std::setw(2) << std::setfill('0') << static_cast<int>(bytes[i]); 29 } 30 return ss.str(); 31 } 32 33 std::string MerklePath(absl::string_view path) { 34 return JoinPath(Dirname(path), 35 std::string(kMerklePrefix) + std::string(Basename(path))); 36 } 37 38 std::string MerkleRootPath(absl::string_view path) { 39 return JoinPath(Dirname(path), 40 std::string(kMerkleRootPrefix) + std::string(Basename(path))); 41 } 42 43 PosixError FlipRandomBit(int fd, int size) { 44 // Generate a random offset in the file. 45 srand(time(nullptr)); 46 unsigned int seed = 0; 47 int random_offset = rand_r(&seed) % size; 48 49 // Read a random byte and flip a bit in it. 50 char buf[1]; 51 RETURN_ERROR_IF_SYSCALL_FAIL(PreadFd(fd, buf, 1, random_offset)); 52 buf[0] ^= 1; 53 RETURN_ERROR_IF_SYSCALL_FAIL(PwriteFd(fd, buf, 1, random_offset)); 54 return NoError(); 55 } 56 57 PosixErrorOr<std::string> MountVerity(std::string tmpfs_dir, 58 std::string filename) { 59 // Mount a verity fs on the existing tmpfs mount. 60 std::string mount_opts = "lower_path=" + tmpfs_dir; 61 ASSIGN_OR_RETURN_ERRNO(TempPath verity_dir, TempPath::CreateDir()); 62 RETURN_ERROR_IF_SYSCALL_FAIL( 63 mount("", verity_dir.path().c_str(), "verity", 0, mount_opts.c_str())); 64 65 // Enable both the file and the directory. 66 ASSIGN_OR_RETURN_ERRNO( 67 auto fd, Open(JoinPath(verity_dir.path(), filename), O_RDONLY, 0777)); 68 RETURN_ERROR_IF_SYSCALL_FAIL(ioctl(fd.get(), FS_IOC_ENABLE_VERITY)); 69 ASSIGN_OR_RETURN_ERRNO(auto dir_fd, Open(verity_dir.path(), O_RDONLY, 0777)); 70 RETURN_ERROR_IF_SYSCALL_FAIL(ioctl(dir_fd.get(), FS_IOC_ENABLE_VERITY)); 71 72 // Measure the root hash. 73 uint8_t digest_array[sizeof(struct fsverity_digest) + kMaxDigestSize] = {0}; 74 struct fsverity_digest* digest = 75 reinterpret_cast<struct fsverity_digest*>(digest_array); 76 digest->digest_size = kMaxDigestSize; 77 RETURN_ERROR_IF_SYSCALL_FAIL( 78 ioctl(dir_fd.get(), FS_IOC_MEASURE_VERITY, digest)); 79 80 // Mount a verity fs with specified root hash. 81 mount_opts += 82 ",root_hash=" + BytesToHexString(digest->digest, digest->digest_size); 83 ASSIGN_OR_RETURN_ERRNO(TempPath verity_with_hash_dir, TempPath::CreateDir()); 84 RETURN_ERROR_IF_SYSCALL_FAIL(mount("", verity_with_hash_dir.path().c_str(), 85 "verity", 0, mount_opts.c_str())); 86 // Verity directories should not be deleted. Release the TempPath objects to 87 // prevent those directories from being deleted by the destructor. 88 verity_dir.release(); 89 return verity_with_hash_dir.release(); 90 } 91 92 } // namespace testing 93 } // namespace gvisor