Merge "Keystore 2.0: Add CREATE_DATETIME unconditionally." into sc-v2-dev
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
index 32067b9..a064f65 100644
--- a/keystore2/src/metrics_store.rs
+++ b/keystore2/src/metrics_store.rs
@@ -17,7 +17,7 @@
 //!    stores them in an in-memory store.
 //! 2. Returns the collected metrics when requested by the statsd proxy.
 
-use crate::error::get_error_code;
+use crate::error::{get_error_code, Error};
 use crate::globals::DB;
 use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
 use crate::operation::Outcome;
@@ -44,6 +44,7 @@
     RkpPoolStats::RkpPoolStats, SecurityLevel::SecurityLevel as MetricsSecurityLevel,
     Storage::Storage as MetricsStorage,
 };
+use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
 use anyhow::{Context, Result};
 use keystore2_system_property::{write, PropertyWatcher, PropertyWatcherError};
 use lazy_static::lazy_static;
@@ -560,10 +561,14 @@
 fn pull_attestation_pool_stats() -> Result<Vec<KeystoreAtom>> {
     let mut atoms = Vec::<KeystoreAtom>::new();
     for sec_level in &[SecurityLevel::TRUSTED_ENVIRONMENT, SecurityLevel::STRONGBOX] {
+        // set the expired_by date to be three days from now
         let expired_by = SystemTime::now()
+            .checked_add(Duration::from_secs(60 * 60 * 24 * 3))
+            .ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR))
+            .context("In pull_attestation_pool_stats: Failed to compute expired by system time.")?
             .duration_since(UNIX_EPOCH)
-            .unwrap_or_else(|_| Duration::new(0, 0))
-            .as_secs() as i64;
+            .context("In pull_attestation_pool_stats: Failed to compute expired by duration.")?
+            .as_millis() as i64;
 
         let result = get_pool_status(expired_by, *sec_level);
 
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 0bb3979..cd38308 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -172,32 +172,6 @@
     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);
-    auto end = std::filesystem::recursive_directory_iterator();
-
-    while (!ec && it != end) {
-        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;
-        }
-        ++it;
-    }
-    if (ec) {
-        return Error() << "Failed to iterate " << path << ": " << ec;
-    }
-
-    return digests;
-}
-
 Result<std::string> isFileInVerity(const std::string& path) {
     unsigned int flags;
 
@@ -223,6 +197,38 @@
     return toHex({&d->digest[0], &d->digest[d->digest_size]});
 }
 
+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);
+    auto end = std::filesystem::recursive_directory_iterator();
+
+    while (!ec && it != end) {
+        if (it->is_regular_file()) {
+            auto digest = isFileInVerity(it->path());
+            if (!digest.ok()) {
+                LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
+                auto result = enableFsVerity(it->path(), 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;
+            }
+        }
+        ++it;
+    }
+    if (ec) {
+        return Error() << "Failed to iterate " << path << ": " << ec;
+    }
+
+    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 84af319..a834e61 100644
--- a/ondevice-signing/VerityUtils.h
+++ b/ondevice-signing/VerityUtils.h
@@ -24,5 +24,8 @@
 android::base::Result<std::vector<uint8_t>> createDigest(const std::string& path);
 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);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index c443340..425776b 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -66,6 +66,20 @@
 
 static const char* kStopServiceProp = "ctl.stop";
 
+static int removeDirectory(const std::string& directory) {
+    std::error_code ec;
+    auto num_removed = std::filesystem::remove_all(directory, ec);
+    if (ec) {
+        LOG(ERROR) << "Can't remove " << directory << ": " << ec.message();
+        return 0;
+    } else {
+        if (num_removed > 0) {
+            LOG(INFO) << "Removed " << num_removed << " entries from " << directory;
+        }
+        return num_removed;
+    }
+}
+
 Result<void> verifyExistingCert(const SigningKey& key) {
     if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
         return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
@@ -100,6 +114,13 @@
     return {};
 }
 
+art::odrefresh::ExitCode checkArtifacts() {
+    const char* const argv[] = {kOdrefreshPath, "--check"};
+    const int exit_code =
+        logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
+    return static_cast<art::odrefresh::ExitCode>(exit_code);
+}
+
 art::odrefresh::ExitCode compileArtifacts(bool force) {
     const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
     const int exit_code =
@@ -144,7 +165,7 @@
     for (const auto& path_digest : digests) {
         auto path = path_digest.first;
         auto digest = path_digest.second;
-        if ((trusted_digests.count(path) == 0)) {
+        if (trusted_digests.count(path) == 0) {
             return Error() << "Couldn't find digest for " << path;
         }
         if (trusted_digests.at(path) != digest) {
@@ -179,7 +200,7 @@
     return verifyDigests(*result, trusted_digests);
 }
 
-Result<OdsignInfo> getOdsignInfo(const SigningKey& key) {
+Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
     std::string persistedSignature;
     OdsignInfo odsignInfo;
 
@@ -213,6 +234,28 @@
     return odsignInfo;
 }
 
+std::map<std::string, std::string> getTrustedDigests(const SigningKey& key) {
+    std::map<std::string, std::string> trusted_digests;
+
+    if (access(kOdsignInfo.c_str(), F_OK) != 0) {
+        // no odsign info file, which is not necessarily an error - just return
+        // an empty list of digests.
+        LOG(INFO) << kOdsignInfo << " not found.";
+        return trusted_digests;
+    }
+    auto signInfo = getAndVerifyOdsignInfo(key);
+
+    if (signInfo.ok()) {
+        trusted_digests.insert(signInfo->file_hashes().begin(), signInfo->file_hashes().end());
+    } else {
+        // This is not expected, since the file did exist. Log an error and
+        // return an empty list of digests.
+        LOG(ERROR) << "Couldn't load trusted digests: " << signInfo.error();
+    }
+
+    return trusted_digests;
+}
+
 Result<void> persistDigests(const std::map<std::string, std::string>& digests,
                             const SigningKey& key) {
     OdsignInfo signInfo;
@@ -252,23 +295,8 @@
     }
 }
 
-static Result<void> verifyArtifacts(const SigningKey& key, bool supportsFsVerity) {
-    auto signInfo = getOdsignInfo(key);
-    // Tell init we're done with the key; this is a boot time optimization
-    // in particular for the no fs-verity case, where we need to do a
-    // costly verification. If the files haven't been tampered with, which
-    // should be the common path, the verification will succeed, and we won't
-    // need the key anymore. If it turns out the artifacts are invalid (eg not
-    // in fs-verity) or the hash doesn't match, we won't be able to generate
-    // new artifacts without the key, so in those cases, remove the artifacts,
-    // and use JIT zygote for the current boot. We should recover automatically
-    // by the next boot.
-    SetProperty(kOdsignKeyDoneProp, "1");
-    if (!signInfo.ok()) {
-        return Error() << signInfo.error().message();
-    }
-    std::map<std::string, std::string> trusted_digests(signInfo->file_hashes().begin(),
-                                                       signInfo->file_hashes().end());
+static Result<void> verifyArtifacts(const std::map<std::string, std::string>& trusted_digests,
+                                    bool supportsFsVerity) {
     Result<void> integrityStatus;
 
     if (supportsFsVerity) {
@@ -337,22 +365,57 @@
         }
     }
 
-    art::odrefresh::ExitCode odrefresh_status = compileArtifacts(kForceCompilation);
-    if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
-        LOG(INFO) << "odrefresh said artifacts are VALID";
-        // A post-condition of validating artifacts is that if the ones on /system
-        // are used, kArtArtifactsDir is removed. Conversely, if kArtArtifactsDir
-        // exists, those are artifacts that will be used, and we should verify them.
-        int err = access(kArtArtifactsDir.c_str(), F_OK);
-        // If we receive any error other than ENOENT, be suspicious
-        bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
-        if (artifactsPresent) {
-            auto verificationResult = verifyArtifacts(*key, supportsFsVerity);
-            if (!verificationResult.ok()) {
-                LOG(ERROR) << verificationResult.error().message();
+    art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
+
+    // The artifacts dir doesn't necessarily need to exist; if the existing
+    // artifacts on the system partition are valid, those can be used.
+    int err = access(kArtArtifactsDir.c_str(), F_OK);
+    // If we receive any error other than ENOENT, be suspicious
+    bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
+
+    if (artifactsPresent && (odrefresh_status == art::odrefresh::ExitCode::kOkay ||
+                             odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired)) {
+        // If we haven't verified the digests yet, we need to validate them. We
+        // need to do this both in case the existing artifacts are okay, but
+        // also if odrefresh said that a recompile is required. In the latter
+        // case, odrefresh may use partial compilation, and leave some
+        // artifacts unchanged.
+        auto trusted_digests = getTrustedDigests(*key);
+
+        if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
+            // Tell init we're done with the key; this is a boot time optimization
+            // in particular for the no fs-verity case, where we need to do a
+            // costly verification. If the files haven't been tampered with, which
+            // should be the common path, the verification will succeed, and we won't
+            // need the key anymore. If it turns out the artifacts are invalid (eg not
+            // in fs-verity) or the hash doesn't match, we won't be able to generate
+            // new artifacts without the key, so in those cases, remove the artifacts,
+            // and use JIT zygote for the current boot. We should recover automatically
+            // by the next boot.
+            SetProperty(kOdsignKeyDoneProp, "1");
+        }
+
+        auto verificationResult = verifyArtifacts(trusted_digests, supportsFsVerity);
+        if (!verificationResult.ok()) {
+            int num_removed = removeDirectory(kArtArtifactsDir);
+            if (num_removed == 0) {
+                // If we can't remove the bad artifacts, we shouldn't continue, and
+                // instead prevent Zygote from using them (which is taken care of
+                // in the exit handler).
+                LOG(ERROR) << "Failed to remove unknown artifacts.";
                 return -1;
             }
         }
+    }
+
+    // Now that we verified existing artifacts, compile if we need to.
+    if (odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired) {
+        odrefresh_status = compileArtifacts(kForceCompilation);
+    }
+
+    if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
+        // No new artifacts generated, and we verified existing ones above, nothing left to do.
+        LOG(INFO) << "odrefresh said artifacts are VALID";
     } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
                odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
         const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;