xref: /aosp_15_r20/system/security/ondevice-signing/VerityUtils.cpp (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker /*
2*e1997b9aSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*e1997b9aSAndroid Build Coastguard Worker  *
4*e1997b9aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e1997b9aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e1997b9aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e1997b9aSAndroid Build Coastguard Worker  *
8*e1997b9aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e1997b9aSAndroid Build Coastguard Worker  *
10*e1997b9aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e1997b9aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e1997b9aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e1997b9aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e1997b9aSAndroid Build Coastguard Worker  * limitations under the License.
15*e1997b9aSAndroid Build Coastguard Worker  */
16*e1997b9aSAndroid Build Coastguard Worker 
17*e1997b9aSAndroid Build Coastguard Worker #include <charconv>
18*e1997b9aSAndroid Build Coastguard Worker #include <filesystem>
19*e1997b9aSAndroid Build Coastguard Worker #include <map>
20*e1997b9aSAndroid Build Coastguard Worker #include <span>
21*e1997b9aSAndroid Build Coastguard Worker #include <string>
22*e1997b9aSAndroid Build Coastguard Worker #include <vector>
23*e1997b9aSAndroid Build Coastguard Worker 
24*e1997b9aSAndroid Build Coastguard Worker #include <fcntl.h>
25*e1997b9aSAndroid Build Coastguard Worker #include <linux/fs.h>
26*e1997b9aSAndroid Build Coastguard Worker #include <sys/stat.h>
27*e1997b9aSAndroid Build Coastguard Worker #include <sys/types.h>
28*e1997b9aSAndroid Build Coastguard Worker 
29*e1997b9aSAndroid Build Coastguard Worker #include "android-base/errors.h"
30*e1997b9aSAndroid Build Coastguard Worker #include <android-base/file.h>
31*e1997b9aSAndroid Build Coastguard Worker #include <android-base/logging.h>
32*e1997b9aSAndroid Build Coastguard Worker #include <android-base/result.h>
33*e1997b9aSAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
34*e1997b9aSAndroid Build Coastguard Worker #include <asm/byteorder.h>
35*e1997b9aSAndroid Build Coastguard Worker #include <libfsverity.h>
36*e1997b9aSAndroid Build Coastguard Worker #include <linux/fsverity.h>
37*e1997b9aSAndroid Build Coastguard Worker 
38*e1997b9aSAndroid Build Coastguard Worker #define FS_VERITY_MAX_DIGEST_SIZE 64
39*e1997b9aSAndroid Build Coastguard Worker 
40*e1997b9aSAndroid Build Coastguard Worker using android::base::ErrnoError;
41*e1997b9aSAndroid Build Coastguard Worker using android::base::Error;
42*e1997b9aSAndroid Build Coastguard Worker using android::base::Result;
43*e1997b9aSAndroid Build Coastguard Worker using android::base::unique_fd;
44*e1997b9aSAndroid Build Coastguard Worker 
45*e1997b9aSAndroid Build Coastguard Worker static const char* kFsVerityProcPath = "/proc/sys/fs/verity";
46*e1997b9aSAndroid Build Coastguard Worker 
SupportsFsVerity()47*e1997b9aSAndroid Build Coastguard Worker bool SupportsFsVerity() {
48*e1997b9aSAndroid Build Coastguard Worker     return access(kFsVerityProcPath, F_OK) == 0;
49*e1997b9aSAndroid Build Coastguard Worker }
50*e1997b9aSAndroid Build Coastguard Worker 
toHex(std::span<const uint8_t> data)51*e1997b9aSAndroid Build Coastguard Worker static std::string toHex(std::span<const uint8_t> data) {
52*e1997b9aSAndroid Build Coastguard Worker     std::stringstream ss;
53*e1997b9aSAndroid Build Coastguard Worker     for (auto it = data.begin(); it != data.end(); ++it) {
54*e1997b9aSAndroid Build Coastguard Worker         ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned>(*it);
55*e1997b9aSAndroid Build Coastguard Worker     }
56*e1997b9aSAndroid Build Coastguard Worker     return ss.str();
57*e1997b9aSAndroid Build Coastguard Worker }
58*e1997b9aSAndroid Build Coastguard Worker 
read_callback(void * file,void * buf,size_t count)59*e1997b9aSAndroid Build Coastguard Worker static int read_callback(void* file, void* buf, size_t count) {
60*e1997b9aSAndroid Build Coastguard Worker     int* fd = (int*)file;
61*e1997b9aSAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(read(*fd, buf, count)) < 0) return errno ? -errno : -EIO;
62*e1997b9aSAndroid Build Coastguard Worker     return 0;
63*e1997b9aSAndroid Build Coastguard Worker }
64*e1997b9aSAndroid Build Coastguard Worker 
createDigest(int fd)65*e1997b9aSAndroid Build Coastguard Worker static Result<std::vector<uint8_t>> createDigest(int fd) {
66*e1997b9aSAndroid Build Coastguard Worker     struct stat filestat;
67*e1997b9aSAndroid Build Coastguard Worker     int ret = fstat(fd, &filestat);
68*e1997b9aSAndroid Build Coastguard Worker     if (ret < 0) {
69*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Failed to fstat";
70*e1997b9aSAndroid Build Coastguard Worker     }
71*e1997b9aSAndroid Build Coastguard Worker     struct libfsverity_merkle_tree_params params = {
72*e1997b9aSAndroid Build Coastguard Worker         .version = 1,
73*e1997b9aSAndroid Build Coastguard Worker         .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
74*e1997b9aSAndroid Build Coastguard Worker         .file_size = static_cast<uint64_t>(filestat.st_size),
75*e1997b9aSAndroid Build Coastguard Worker         .block_size = 4096,
76*e1997b9aSAndroid Build Coastguard Worker     };
77*e1997b9aSAndroid Build Coastguard Worker 
78*e1997b9aSAndroid Build Coastguard Worker     struct libfsverity_digest* digest;
79*e1997b9aSAndroid Build Coastguard Worker     ret = libfsverity_compute_digest(&fd, &read_callback, &params, &digest);
80*e1997b9aSAndroid Build Coastguard Worker     if (ret < 0) {
81*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Failed to compute fs-verity digest";
82*e1997b9aSAndroid Build Coastguard Worker     }
83*e1997b9aSAndroid Build Coastguard Worker     int expected_digest_size = libfsverity_get_digest_size(FS_VERITY_HASH_ALG_SHA256);
84*e1997b9aSAndroid Build Coastguard Worker     if (digest->digest_size != expected_digest_size) {
85*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Digest does not have expected size: " << expected_digest_size
86*e1997b9aSAndroid Build Coastguard Worker                        << " actual: " << digest->digest_size;
87*e1997b9aSAndroid Build Coastguard Worker     }
88*e1997b9aSAndroid Build Coastguard Worker     std::vector<uint8_t> digestVector(&digest->digest[0], &digest->digest[expected_digest_size]);
89*e1997b9aSAndroid Build Coastguard Worker     free(digest);
90*e1997b9aSAndroid Build Coastguard Worker     return digestVector;
91*e1997b9aSAndroid Build Coastguard Worker }
92*e1997b9aSAndroid Build Coastguard Worker 
createDigest(const std::string & path)93*e1997b9aSAndroid Build Coastguard Worker Result<std::vector<uint8_t>> createDigest(const std::string& path) {
94*e1997b9aSAndroid Build Coastguard Worker     unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
95*e1997b9aSAndroid Build Coastguard Worker     if (!fd.ok()) {
96*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Unable to open";
97*e1997b9aSAndroid Build Coastguard Worker     }
98*e1997b9aSAndroid Build Coastguard Worker     return createDigest(fd.get());
99*e1997b9aSAndroid Build Coastguard Worker }
100*e1997b9aSAndroid Build Coastguard Worker 
101*e1997b9aSAndroid Build Coastguard Worker namespace {
102*e1997b9aSAndroid Build Coastguard Worker template <typename T> struct DeleteAsPODArray {
operator ()__anone6e9360d0111::DeleteAsPODArray103*e1997b9aSAndroid Build Coastguard Worker     void operator()(T* x) {
104*e1997b9aSAndroid Build Coastguard Worker         if (x) {
105*e1997b9aSAndroid Build Coastguard Worker             x->~T();
106*e1997b9aSAndroid Build Coastguard Worker             delete[](uint8_t*) x;
107*e1997b9aSAndroid Build Coastguard Worker         }
108*e1997b9aSAndroid Build Coastguard Worker     }
109*e1997b9aSAndroid Build Coastguard Worker };
110*e1997b9aSAndroid Build Coastguard Worker 
111*e1997b9aSAndroid Build Coastguard Worker template <typename T> using trailing_unique_ptr = std::unique_ptr<T, DeleteAsPODArray<T>>;
112*e1997b9aSAndroid Build Coastguard Worker 
113*e1997b9aSAndroid Build Coastguard Worker template <typename T>
makeUniqueWithTrailingData(size_t trailing_data_size)114*e1997b9aSAndroid Build Coastguard Worker static trailing_unique_ptr<T> makeUniqueWithTrailingData(size_t trailing_data_size) {
115*e1997b9aSAndroid Build Coastguard Worker     uint8_t* memory = new uint8_t[sizeof(T) + trailing_data_size];
116*e1997b9aSAndroid Build Coastguard Worker     T* ptr = new (memory) T;
117*e1997b9aSAndroid Build Coastguard Worker     return trailing_unique_ptr<T>{ptr};
118*e1997b9aSAndroid Build Coastguard Worker }
119*e1997b9aSAndroid Build Coastguard Worker 
measureFsVerity(int fd)120*e1997b9aSAndroid Build Coastguard Worker static Result<std::string> measureFsVerity(int fd) {
121*e1997b9aSAndroid Build Coastguard Worker     auto d = makeUniqueWithTrailingData<fsverity_digest>(FS_VERITY_MAX_DIGEST_SIZE);
122*e1997b9aSAndroid Build Coastguard Worker     d->digest_size = FS_VERITY_MAX_DIGEST_SIZE;
123*e1997b9aSAndroid Build Coastguard Worker 
124*e1997b9aSAndroid Build Coastguard Worker     if (ioctl(fd, FS_IOC_MEASURE_VERITY, d.get()) != 0) {
125*e1997b9aSAndroid Build Coastguard Worker         if (errno == ENODATA) {
126*e1997b9aSAndroid Build Coastguard Worker             return Error() << "File is not in fs-verity";
127*e1997b9aSAndroid Build Coastguard Worker         } else {
128*e1997b9aSAndroid Build Coastguard Worker             return ErrnoError() << "Failed to FS_IOC_MEASURE_VERITY";
129*e1997b9aSAndroid Build Coastguard Worker         }
130*e1997b9aSAndroid Build Coastguard Worker     }
131*e1997b9aSAndroid Build Coastguard Worker 
132*e1997b9aSAndroid Build Coastguard Worker     return toHex({&d->digest[0], &d->digest[d->digest_size]});
133*e1997b9aSAndroid Build Coastguard Worker }
134*e1997b9aSAndroid Build Coastguard Worker 
measureFsVerity(const std::string & path)135*e1997b9aSAndroid Build Coastguard Worker static Result<std::string> measureFsVerity(const std::string& path) {
136*e1997b9aSAndroid Build Coastguard Worker     unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
137*e1997b9aSAndroid Build Coastguard Worker     if (!fd.ok()) {
138*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Failed to open " << path;
139*e1997b9aSAndroid Build Coastguard Worker     }
140*e1997b9aSAndroid Build Coastguard Worker 
141*e1997b9aSAndroid Build Coastguard Worker     return measureFsVerity(fd.get());
142*e1997b9aSAndroid Build Coastguard Worker }
143*e1997b9aSAndroid Build Coastguard Worker 
144*e1997b9aSAndroid Build Coastguard Worker }  // namespace
145*e1997b9aSAndroid Build Coastguard Worker 
enableFsVerity(int fd)146*e1997b9aSAndroid Build Coastguard Worker static Result<void> enableFsVerity(int fd) {
147*e1997b9aSAndroid Build Coastguard Worker     struct fsverity_enable_arg arg = {.version = 1};
148*e1997b9aSAndroid Build Coastguard Worker 
149*e1997b9aSAndroid Build Coastguard Worker     arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
150*e1997b9aSAndroid Build Coastguard Worker     arg.block_size = 4096;
151*e1997b9aSAndroid Build Coastguard Worker 
152*e1997b9aSAndroid Build Coastguard Worker     int ret = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg);
153*e1997b9aSAndroid Build Coastguard Worker 
154*e1997b9aSAndroid Build Coastguard Worker     if (ret != 0) {
155*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Failed to call FS_IOC_ENABLE_VERITY";
156*e1997b9aSAndroid Build Coastguard Worker     }
157*e1997b9aSAndroid Build Coastguard Worker 
158*e1997b9aSAndroid Build Coastguard Worker     return {};
159*e1997b9aSAndroid Build Coastguard Worker }
160*e1997b9aSAndroid Build Coastguard Worker 
enableFsVerity(const std::string & path)161*e1997b9aSAndroid Build Coastguard Worker Result<void> enableFsVerity(const std::string& path) {
162*e1997b9aSAndroid Build Coastguard Worker     unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
163*e1997b9aSAndroid Build Coastguard Worker     if (!fd.ok()) {
164*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Can't open " << path;
165*e1997b9aSAndroid Build Coastguard Worker     }
166*e1997b9aSAndroid Build Coastguard Worker 
167*e1997b9aSAndroid Build Coastguard Worker     return enableFsVerity(fd.get());
168*e1997b9aSAndroid Build Coastguard Worker }
169*e1997b9aSAndroid Build Coastguard Worker 
isFileInVerity(int fd)170*e1997b9aSAndroid Build Coastguard Worker static Result<bool> isFileInVerity(int fd) {
171*e1997b9aSAndroid Build Coastguard Worker     unsigned int flags;
172*e1997b9aSAndroid Build Coastguard Worker     if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0) {
173*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "ioctl(FS_IOC_GETFLAGS) failed";
174*e1997b9aSAndroid Build Coastguard Worker     }
175*e1997b9aSAndroid Build Coastguard Worker     return (flags & FS_VERITY_FL) != 0;
176*e1997b9aSAndroid Build Coastguard Worker }
177*e1997b9aSAndroid Build Coastguard Worker 
addFilesToVerityRecursive(const std::string & path)178*e1997b9aSAndroid Build Coastguard Worker Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path) {
179*e1997b9aSAndroid Build Coastguard Worker     std::map<std::string, std::string> digests;
180*e1997b9aSAndroid Build Coastguard Worker 
181*e1997b9aSAndroid Build Coastguard Worker     std::error_code ec;
182*e1997b9aSAndroid Build Coastguard Worker     auto it = std::filesystem::recursive_directory_iterator(path, ec);
183*e1997b9aSAndroid Build Coastguard Worker     for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) {
184*e1997b9aSAndroid Build Coastguard Worker         if (it->is_regular_file()) {
185*e1997b9aSAndroid Build Coastguard Worker             unique_fd fd(TEMP_FAILURE_RETRY(open(it->path().c_str(), O_RDONLY | O_CLOEXEC)));
186*e1997b9aSAndroid Build Coastguard Worker             if (!fd.ok()) {
187*e1997b9aSAndroid Build Coastguard Worker                 return ErrnoError() << "Failed to open " << path;
188*e1997b9aSAndroid Build Coastguard Worker             }
189*e1997b9aSAndroid Build Coastguard Worker             auto enabled = OR_RETURN(isFileInVerity(fd));
190*e1997b9aSAndroid Build Coastguard Worker             if (!enabled) {
191*e1997b9aSAndroid Build Coastguard Worker                 LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
192*e1997b9aSAndroid Build Coastguard Worker                 OR_RETURN(enableFsVerity(fd));
193*e1997b9aSAndroid Build Coastguard Worker             } else {
194*e1997b9aSAndroid Build Coastguard Worker                 LOG(INFO) << it->path() << " was already in fs-verity.";
195*e1997b9aSAndroid Build Coastguard Worker             }
196*e1997b9aSAndroid Build Coastguard Worker             auto digest = OR_RETURN(measureFsVerity(fd));
197*e1997b9aSAndroid Build Coastguard Worker             digests[it->path()] = digest;
198*e1997b9aSAndroid Build Coastguard Worker         }
199*e1997b9aSAndroid Build Coastguard Worker     }
200*e1997b9aSAndroid Build Coastguard Worker     if (ec) {
201*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to iterate " << path << ": " << ec.message();
202*e1997b9aSAndroid Build Coastguard Worker     }
203*e1997b9aSAndroid Build Coastguard Worker 
204*e1997b9aSAndroid Build Coastguard Worker     return digests;
205*e1997b9aSAndroid Build Coastguard Worker }
206*e1997b9aSAndroid Build Coastguard Worker 
verifyAllFilesInVerity(const std::string & path)207*e1997b9aSAndroid Build Coastguard Worker Result<std::map<std::string, std::string>> verifyAllFilesInVerity(const std::string& path) {
208*e1997b9aSAndroid Build Coastguard Worker     std::map<std::string, std::string> digests;
209*e1997b9aSAndroid Build Coastguard Worker     std::error_code ec;
210*e1997b9aSAndroid Build Coastguard Worker 
211*e1997b9aSAndroid Build Coastguard Worker     auto it = std::filesystem::recursive_directory_iterator(path, ec);
212*e1997b9aSAndroid Build Coastguard Worker     auto end = std::filesystem::recursive_directory_iterator();
213*e1997b9aSAndroid Build Coastguard Worker 
214*e1997b9aSAndroid Build Coastguard Worker     while (!ec && it != end) {
215*e1997b9aSAndroid Build Coastguard Worker         if (it->is_regular_file()) {
216*e1997b9aSAndroid Build Coastguard Worker             // Verify the file is in fs-verity
217*e1997b9aSAndroid Build Coastguard Worker             auto result = OR_RETURN(measureFsVerity(it->path()));
218*e1997b9aSAndroid Build Coastguard Worker             digests[it->path()] = result;
219*e1997b9aSAndroid Build Coastguard Worker         } else if (it->is_directory()) {
220*e1997b9aSAndroid Build Coastguard Worker             // These are fine to ignore
221*e1997b9aSAndroid Build Coastguard Worker         } else if (it->is_symlink()) {
222*e1997b9aSAndroid Build Coastguard Worker             return Error() << "Rejecting artifacts, symlink at " << it->path();
223*e1997b9aSAndroid Build Coastguard Worker         } else {
224*e1997b9aSAndroid Build Coastguard Worker             return Error() << "Rejecting artifacts, unexpected file type for " << it->path();
225*e1997b9aSAndroid Build Coastguard Worker         }
226*e1997b9aSAndroid Build Coastguard Worker         ++it;
227*e1997b9aSAndroid Build Coastguard Worker     }
228*e1997b9aSAndroid Build Coastguard Worker     if (ec) {
229*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to iterate " << path << ": " << ec;
230*e1997b9aSAndroid Build Coastguard Worker     }
231*e1997b9aSAndroid Build Coastguard Worker 
232*e1997b9aSAndroid Build Coastguard Worker     return digests;
233*e1997b9aSAndroid Build Coastguard Worker }
234*e1997b9aSAndroid Build Coastguard Worker 
verifyAllFilesUsingCompOs(const std::string & directory_path,const std::map<std::string,std::string> & digests)235*e1997b9aSAndroid Build Coastguard Worker Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
236*e1997b9aSAndroid Build Coastguard Worker                                        const std::map<std::string, std::string>& digests) {
237*e1997b9aSAndroid Build Coastguard Worker     std::error_code ec;
238*e1997b9aSAndroid Build Coastguard Worker     size_t verified_count = 0;
239*e1997b9aSAndroid Build Coastguard Worker     auto it = std::filesystem::recursive_directory_iterator(directory_path, ec);
240*e1997b9aSAndroid Build Coastguard Worker     for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) {
241*e1997b9aSAndroid Build Coastguard Worker         auto& path = it->path();
242*e1997b9aSAndroid Build Coastguard Worker         if (it->is_regular_file()) {
243*e1997b9aSAndroid Build Coastguard Worker             auto entry = digests.find(path);
244*e1997b9aSAndroid Build Coastguard Worker             if (entry == digests.end()) {
245*e1997b9aSAndroid Build Coastguard Worker                 return Error() << "Unexpected file found: " << path;
246*e1997b9aSAndroid Build Coastguard Worker             }
247*e1997b9aSAndroid Build Coastguard Worker             auto& compos_digest = entry->second;
248*e1997b9aSAndroid Build Coastguard Worker 
249*e1997b9aSAndroid Build Coastguard Worker             unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
250*e1997b9aSAndroid Build Coastguard Worker             if (!fd.ok()) {
251*e1997b9aSAndroid Build Coastguard Worker                 return ErrnoError() << "Can't open " << path;
252*e1997b9aSAndroid Build Coastguard Worker             }
253*e1997b9aSAndroid Build Coastguard Worker 
254*e1997b9aSAndroid Build Coastguard Worker             bool enabled = OR_RETURN(isFileInVerity(fd));
255*e1997b9aSAndroid Build Coastguard Worker             if (!enabled) {
256*e1997b9aSAndroid Build Coastguard Worker                 LOG(INFO) << "Enabling fs-verity for " << path;
257*e1997b9aSAndroid Build Coastguard Worker                 OR_RETURN(enableFsVerity(fd));
258*e1997b9aSAndroid Build Coastguard Worker             }
259*e1997b9aSAndroid Build Coastguard Worker 
260*e1997b9aSAndroid Build Coastguard Worker             auto actual_digest = OR_RETURN(measureFsVerity(fd));
261*e1997b9aSAndroid Build Coastguard Worker             // Make sure the file's fs-verity digest matches the known value.
262*e1997b9aSAndroid Build Coastguard Worker             if (actual_digest == compos_digest) {
263*e1997b9aSAndroid Build Coastguard Worker                 ++verified_count;
264*e1997b9aSAndroid Build Coastguard Worker             } else {
265*e1997b9aSAndroid Build Coastguard Worker                 return Error() << "fs-verity digest does not match CompOS digest: " << path;
266*e1997b9aSAndroid Build Coastguard Worker             }
267*e1997b9aSAndroid Build Coastguard Worker         } else if (it->is_directory()) {
268*e1997b9aSAndroid Build Coastguard Worker             // These are fine to ignore
269*e1997b9aSAndroid Build Coastguard Worker         } else if (it->is_symlink()) {
270*e1997b9aSAndroid Build Coastguard Worker             return Error() << "Rejecting artifacts, symlink at " << path;
271*e1997b9aSAndroid Build Coastguard Worker         } else {
272*e1997b9aSAndroid Build Coastguard Worker             return Error() << "Rejecting artifacts, unexpected file type for " << path;
273*e1997b9aSAndroid Build Coastguard Worker         }
274*e1997b9aSAndroid Build Coastguard Worker     }
275*e1997b9aSAndroid Build Coastguard Worker     if (ec) {
276*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to iterate " << directory_path << ": " << ec.message();
277*e1997b9aSAndroid Build Coastguard Worker     }
278*e1997b9aSAndroid Build Coastguard Worker 
279*e1997b9aSAndroid Build Coastguard Worker     // Make sure all the files we expected have been seen
280*e1997b9aSAndroid Build Coastguard Worker     if (verified_count != digests.size()) {
281*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Verified " << verified_count << " files, but expected "
282*e1997b9aSAndroid Build Coastguard Worker                        << digests.size();
283*e1997b9aSAndroid Build Coastguard Worker     }
284*e1997b9aSAndroid Build Coastguard Worker 
285*e1997b9aSAndroid Build Coastguard Worker     return {};
286*e1997b9aSAndroid Build Coastguard Worker }
287