diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-01-20 18:08:01 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-01-20 18:08:01 +0000 |
commit | 2584ceff1628ef9b3d5079c0caf53763a6501b44 (patch) | |
tree | 4092577b8206991d7a58795c34f03909f3a2d8c0 | |
parent | 8308930023601c86e55650c49e8f0461bb830343 (diff) | |
parent | ce7f7e2e2810181ea29912c85f55c92b9ebef6c0 (diff) | |
download | security-android12-platform-release.tar.gz |
Merge cherrypicks of [16511960] into sc-platform-release.android-platform-12.0.0_r9android-platform-12.0.0_r8android-platform-12.0.0_r7android-platform-12.0.0_r6android-platform-12.0.0_r5android-platform-12.0.0_r31android-platform-12.0.0_r30android-platform-12.0.0_r29android-platform-12.0.0_r28android-platform-12.0.0_r27android-platform-12.0.0_r26android-platform-12.0.0_r25android-platform-12.0.0_r24android-platform-12.0.0_r23android-platform-12.0.0_r22android-platform-12.0.0_r21android-platform-12.0.0_r20android-platform-12.0.0_r19android-platform-12.0.0_r18android-platform-12.0.0_r17android-platform-12.0.0_r16android-platform-12.0.0_r15android-platform-12.0.0_r14android-platform-12.0.0_r13android-platform-12.0.0_r12android-platform-12.0.0_r11android-platform-12.0.0_r10android12-platform-release
Change-Id: I14798fdabfe79810602b62b95fc2b067e5c6170b
-rw-r--r-- | ondevice-signing/odsign_main.cpp | 127 |
1 files changed, 95 insertions, 32 deletions
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp index c4433406..425776bd 100644 --- a/ondevice-signing/odsign_main.cpp +++ b/ondevice-signing/odsign_main.cpp @@ -66,6 +66,20 @@ static const char* kOdsignVerificationStatusError = "0"; 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 @@ Result<void> createX509Cert(const SigningKey& key, const std::string& outPath) { 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 @@ Result<void> verifyDigests(const std::map<std::string, std::string>& digests, 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 @@ Result<void> verifyIntegrityNoFsVerity(const std::map<std::string, std::string>& 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 @@ Result<OdsignInfo> getOdsignInfo(const SigningKey& key) { 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 int removeArtifacts() { } } -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 @@ int main(int /* argc */, char** /* argv */) { } } - 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; |