Allow previously signed fs-verity files.

AddFilesToVerityRecursive() would fail if any of the files considered
was already in fs-verity. This is not desirable in case of partial
compilation, where some files might already have been generated and
signed on a previous boot. Allow such files, because earlier code will
already have verified that their signature matched the signature that we
remember anyway.

Bug: 205276874
Test: atest odsign_e2e_tests
Change-Id: Iaf35607d0054bdcd00501c6102ad629ce9fe7ac3
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 2beb7eb..e5a872a 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -155,15 +155,10 @@
     return {};
 }
 
-Result<std::string> enableFsVerity(const std::string& path, const SigningKey& key) {
-    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (!fd.ok()) {
-        return ErrnoError() << "Failed to open " << path;
-    }
-
-    auto digest = createDigest(fd.get());
+Result<std::string> enableFsVerity(int fd, const SigningKey& key) {
+    auto digest = createDigest(fd);
     if (!digest.ok()) {
-        return Error() << digest.error() << ": " << path;
+        return Error() << digest.error();
     }
 
     auto signed_digest = signDigest(key, digest.value());
@@ -176,36 +171,26 @@
         return pkcs7_data.error();
     }
 
-    auto enabled = enableFsVerity(fd.get(), pkcs7_data.value());
+    auto enabled = enableFsVerity(fd, pkcs7_data.value());
     if (!enabled.ok()) {
-        return Error() << enabled.error() << ": " << path;
+        return Error() << enabled.error();
     }
 
     // Return the root hash as a hex string
     return toHex(digest.value());
 }
 
-Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path,
-                                                                     const SigningKey& key) {
-    std::map<std::string, std::string> digests;
-
-    std::error_code ec;
-    auto it = std::filesystem::recursive_directory_iterator(path, ec);
-    for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) {
-        if (it->is_regular_file()) {
-            LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
-            auto result = enableFsVerity(it->path(), key);
-            if (!result.ok()) {
-                return result.error();
-            }
-            digests[it->path()] = *result;
-        }
-    }
-    if (ec) {
-        return Error() << "Failed to iterate " << path << ": " << ec.message();
+Result<std::string> enableFsVerity(const std::string& path, const SigningKey& key) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (!fd.ok()) {
+        return ErrnoError() << "Failed to open " << path;
     }
 
-    return digests;
+    auto enableStatus = enableFsVerity(fd.get(), key);
+    if (!enableStatus.ok()) {
+        return Error() << path << ": " << enableStatus.error();
+    }
+    return enableStatus;
 }
 
 Result<std::string> isFileInVerity(int fd) {
@@ -228,7 +213,7 @@
         return ErrnoError() << "Failed to open " << path;
     }
 
-    auto digest = isFileInVerity(fd);
+    auto digest = isFileInVerity(fd.get());
     if (!digest.ok()) {
         return Error() << digest.error() << ": " << path;
     }
@@ -236,6 +221,39 @@
     return digest;
 }
 
+Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path,
+                                                                     const SigningKey& key) {
+    std::map<std::string, std::string> digests;
+
+    std::error_code ec;
+    auto it = std::filesystem::recursive_directory_iterator(path, ec);
+    for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) {
+        if (it->is_regular_file()) {
+            unique_fd fd(TEMP_FAILURE_RETRY(open(it->path().c_str(), O_RDONLY | O_CLOEXEC)));
+            if (!fd.ok()) {
+                return ErrnoError() << "Failed to open " << path;
+            }
+            auto digest = isFileInVerity(fd);
+            if (!digest.ok()) {
+                LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
+                auto result = enableFsVerity(fd, key);
+                if (!result.ok()) {
+                    return result.error();
+                }
+                digests[it->path()] = *result;
+            } else {
+                LOG(INFO) << it->path() << " was already in fs-verity.";
+                digests[it->path()] = *digest;
+            }
+        }
+    }
+    if (ec) {
+        return Error() << "Failed to iterate " << path << ": " << ec.message();
+    }
+
+    return digests;
+}
+
 Result<std::map<std::string, std::string>> verifyAllFilesInVerity(const std::string& path) {
     std::map<std::string, std::string> digests;
     std::error_code ec;
diff --git a/ondevice-signing/VerityUtils.h b/ondevice-signing/VerityUtils.h
index 8d8e62c..76b2229 100644
--- a/ondevice-signing/VerityUtils.h
+++ b/ondevice-signing/VerityUtils.h
@@ -25,6 +25,8 @@
 android::base::Result<std::map<std::string, std::string>>
 verifyAllFilesInVerity(const std::string& path);
 
+// Note that this function will skip files that are already in fs-verity, and
+// for those files it will return the existing digest.
 android::base::Result<std::map<std::string, std::string>>
 addFilesToVerityRecursive(const std::string& path, const SigningKey& key);