Merge "fsverity_init: refactor into library + binary"
diff --git a/fsverity/Android.bp b/fsverity/Android.bp
index b1d8965..5fb38ae 100644
--- a/fsverity/Android.bp
+++ b/fsverity/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_security_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_security_license"],
+}
+
 python_library_host {
     name: "fsverity_digests_proto_python",
     srcs: [
diff --git a/fsverity/OWNERS b/fsverity/OWNERS
new file mode 100644
index 0000000..f9e7b25
--- /dev/null
+++ b/fsverity/OWNERS
@@ -0,0 +1,5 @@
+alanstokes@google.com
+ebiggers@google.com
+jeffv@google.com
+jiyong@google.com
+victorhsieh@google.com
diff --git a/fsverity_init/OWNERS b/fsverity_init/OWNERS
new file mode 100644
index 0000000..f9e7b25
--- /dev/null
+++ b/fsverity_init/OWNERS
@@ -0,0 +1,5 @@
+alanstokes@google.com
+ebiggers@google.com
+jeffv@google.com
+jiyong@google.com
+victorhsieh@google.com
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index 1cfb4f6..1e9126d 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -19,6 +19,7 @@
 #include <iostream>
 #include <memory>
 #include <string>
+#include <variant>
 #include <vector>
 
 #include <base/command_line.h>
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 3f6cf36..57abc26 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -215,6 +215,8 @@
 
     fn migrate_key_namespace(source: &KeyDescriptor, destination: &KeyDescriptor) -> Result<()> {
         let caller_uid = ThreadState::get_calling_uid();
+        let migrate_any_key_permission =
+            check_keystore_permission(KeystorePerm::MigrateAnyKey).is_ok();
 
         DB.with(|db| {
             let key_id_guard = match source.domain {
@@ -227,9 +229,12 @@
                                 KeyEntryLoadBits::NONE,
                                 caller_uid,
                                 |k, av| {
-                                    check_key_permission(KeyPerm::Use, k, &av)?;
-                                    check_key_permission(KeyPerm::Delete, k, &av)?;
-                                    check_key_permission(KeyPerm::Grant, k, &av)
+                                    if !migrate_any_key_permission {
+                                        check_key_permission(KeyPerm::Use, k, &av)?;
+                                        check_key_permission(KeyPerm::Delete, k, &av)?;
+                                        check_key_permission(KeyPerm::Grant, k, &av)?;
+                                    }
+                                    Ok(())
                                 },
                             )
                         })
@@ -245,7 +250,10 @@
             };
 
             db.borrow_mut().migrate_key_namespace(key_id_guard, destination, caller_uid, |k| {
-                check_key_permission(KeyPerm::Rebind, k, &None)
+                if !migrate_any_key_permission {
+                    check_key_permission(KeyPerm::Rebind, k, &None)?;
+                }
+                Ok(())
             })
         })
     }
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index f280341..e6d61b0 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -145,6 +145,10 @@
         /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
         #[selinux(name = delete_all_keys)]
         DeleteAllKeys,
+        /// Checked when migrating any key from any namespace to any other namespace. It was
+        /// introduced for migrating keys when an app leaves a sharedUserId.
+        #[selinux(name = migrate_any_key)]
+        MigrateAnyKey,
     }
 );
 
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);