Merge "Use the right path for compos_verify" am: 8895d4d295
Original change: https://android-review.googlesource.com/c/platform/system/security/+/1994990
Change-Id: I1f1926a9a5979a52ef8467bd5b1df39894d077ce
diff --git a/ondevice-signing/KeystoreHmacKey.cpp b/ondevice-signing/KeystoreHmacKey.cpp
index 09677d7..916cbbc 100644
--- a/ondevice-signing/KeystoreHmacKey.cpp
+++ b/ondevice-signing/KeystoreHmacKey.cpp
@@ -49,17 +49,14 @@
using android::base::unique_fd;
-// Keystore boot level that the odsign key uses
-static const int kOdsignBootLevel = 30;
-
-static KeyDescriptor getHmacKeyDescriptor() {
+static KeyDescriptor getHmacKeyDescriptor(const android::String16& keyAlias, int64_t keyNspace) {
// AIDL parcelable objects don't have constructor
static KeyDescriptor descriptor;
static std::once_flag flag;
std::call_once(flag, [&]() {
descriptor.domain = Domain::SELINUX;
- descriptor.alias = String16("ondevice-signing-hmac");
- descriptor.nspace = 101; // odsign_key
+ descriptor.alias = keyAlias + android::String16("-hmac");
+ descriptor.nspace = keyNspace;
});
return descriptor;
@@ -106,7 +103,7 @@
KeyParameter boot_level;
boot_level.tag = Tag::MAX_BOOT_LEVEL;
- boot_level.value = KeyParameterValue::make<KeyParameterValue::integer>(kOdsignBootLevel);
+ boot_level.value = KeyParameterValue::make<KeyParameterValue::integer>(mKeyBootLevel);
params.push_back(boot_level);
KeyMetadata metadata;
@@ -133,7 +130,7 @@
// Make sure this is an early boot key
for (const auto& auth : keyEntryResponse.metadata.authorizations) {
if (auth.keyParameter.tag == Tag::MAX_BOOT_LEVEL) {
- if (auth.keyParameter.value.get<KeyParameterValue::integer>() == kOdsignBootLevel) {
+ if (auth.keyParameter.value.get<KeyParameterValue::integer>() == mKeyBootLevel) {
keyValid = true;
break;
}
@@ -152,9 +149,9 @@
}
}
-KeystoreHmacKey::KeystoreHmacKey() {
- mDescriptor = getHmacKeyDescriptor();
-}
+KeystoreHmacKey::KeystoreHmacKey(const android::String16& keyAlias, int64_t keyNspace,
+ int keyBootLevel)
+ : mDescriptor(getHmacKeyDescriptor(keyAlias, keyNspace)), mKeyBootLevel(keyBootLevel) {}
static std::vector<KeyParameter> getVerifyOpParameters() {
std::vector<KeyParameter> opParameters;
diff --git a/ondevice-signing/KeystoreHmacKey.h b/ondevice-signing/KeystoreHmacKey.h
index 782969a..1a815a3 100644
--- a/ondevice-signing/KeystoreHmacKey.h
+++ b/ondevice-signing/KeystoreHmacKey.h
@@ -31,7 +31,7 @@
using KeyDescriptor = ::android::system::keystore2::KeyDescriptor;
public:
- KeystoreHmacKey();
+ KeystoreHmacKey(const android::String16& keyAlias, int64_t keyNspace, int keyBootLevel);
android::base::Result<void> initialize(android::sp<IKeystoreService> service,
android::sp<IKeystoreSecurityLevel> securityLevel);
android::base::Result<std::string> sign(const std::string& message) const;
@@ -44,4 +44,6 @@
KeyDescriptor mDescriptor;
android::sp<IKeystoreService> mService;
android::sp<IKeystoreSecurityLevel> mSecurityLevel;
+
+ int mKeyBootLevel;
};
diff --git a/ondevice-signing/KeystoreKey.cpp b/ondevice-signing/KeystoreKey.cpp
index 03bb6d5..6ce65d6 100644
--- a/ondevice-signing/KeystoreKey.cpp
+++ b/ondevice-signing/KeystoreKey.cpp
@@ -50,27 +50,24 @@
using android::base::Error;
using android::base::Result;
-// Keystore boot level that the odsign key uses
-static const int kOdsignBootLevel = 30;
-
-const std::string kPublicKeySignature = "/data/misc/odsign/publickey.signature";
-
-static KeyDescriptor getKeyDescriptor() {
+static KeyDescriptor getKeyDescriptor(const android::String16& keyAlias, int64_t keyNspace) {
// AIDL parcelable objects don't have constructor
static KeyDescriptor descriptor;
static std::once_flag flag;
std::call_once(flag, [&]() {
descriptor.domain = Domain::SELINUX;
- descriptor.alias = String16("ondevice-signing");
- descriptor.nspace = 101; // odsign_key
+ descriptor.alias = keyAlias;
+ descriptor.nspace = keyNspace;
});
return descriptor;
}
-KeystoreKey::KeystoreKey() {
- mDescriptor = getKeyDescriptor();
-}
+KeystoreKey::KeystoreKey(std::string signedPubKeyPath, const android::String16& keyAlias,
+ int64_t keyNspace, int keyBootLevel)
+ : mDescriptor(getKeyDescriptor(keyAlias, keyNspace)),
+ mHmacKey(keyAlias, keyNspace, keyBootLevel), mSignedPubKeyPath(std::move(signedPubKeyPath)),
+ mKeyBootLevel(keyBootLevel) {}
Result<std::vector<uint8_t>> KeystoreKey::createKey() {
std::vector<KeyParameter> params;
@@ -113,7 +110,7 @@
KeyParameter boot_level;
boot_level.tag = Tag::MAX_BOOT_LEVEL;
- boot_level.value = KeyParameterValue::make<KeyParameterValue::integer>(kOdsignBootLevel);
+ boot_level.value = KeyParameterValue::make<KeyParameterValue::integer>(mKeyBootLevel);
params.push_back(boot_level);
KeyMetadata metadata;
@@ -137,7 +134,7 @@
return Error() << "Failed to sign public key.";
}
- if (!android::base::WriteStringToFile(*signature, kPublicKeySignature)) {
+ if (!android::base::WriteStringToFile(*signature, mSignedPubKeyPath)) {
return Error() << "Can't write public key signature.";
}
@@ -206,7 +203,7 @@
bool foundBootLevel = false;
for (const auto& auth : keyEntryResponse.metadata.authorizations) {
if (auth.keyParameter.tag == Tag::MAX_BOOT_LEVEL) {
- if (auth.keyParameter.value.get<KeyParameterValue::integer>() == kOdsignBootLevel) {
+ if (auth.keyParameter.value.get<KeyParameterValue::integer>() == mKeyBootLevel) {
foundBootLevel = true;
break;
}
@@ -232,7 +229,7 @@
std::string publicKeyString = {publicKey->begin(), publicKey->end()};
std::string signature;
- if (!android::base::ReadFileToString(kPublicKeySignature, &signature)) {
+ if (!android::base::ReadFileToString(mSignedPubKeyPath, &signature)) {
return Error() << "Can't find signature for public key.";
}
@@ -256,13 +253,15 @@
return *existingKey;
}
-Result<SigningKey*> KeystoreKey::getInstance() {
- static KeystoreKey keystoreKey;
+Result<SigningKey*> KeystoreKey::getInstance(const std::string& signedPubKeyPath,
+ const android::String16& keyAlias, int64_t keyNspace,
+ int keyBootLevel) {
+ auto keystoreKey = new KeystoreKey(signedPubKeyPath, keyAlias, keyNspace, keyBootLevel);
- if (!keystoreKey.initialize()) {
+ if (!keystoreKey->initialize()) {
return Error() << "Failed to initialize keystore key.";
} else {
- return &keystoreKey;
+ return keystoreKey;
}
}
diff --git a/ondevice-signing/KeystoreKey.h b/ondevice-signing/KeystoreKey.h
index f2fbb70..3c9a0ab 100644
--- a/ondevice-signing/KeystoreKey.h
+++ b/ondevice-signing/KeystoreKey.h
@@ -36,13 +36,16 @@
public:
virtual ~KeystoreKey(){};
- static android::base::Result<SigningKey*> getInstance();
+ static android::base::Result<SigningKey*> getInstance(const std::string& signedPubKeyPath,
+ const android::String16& keyAlias,
+ int64_t KeyNspace, int keyBootLevel);
virtual android::base::Result<std::string> sign(const std::string& message) const;
virtual android::base::Result<std::vector<uint8_t>> getPublicKey() const;
private:
- KeystoreKey();
+ KeystoreKey(std::string signedPubKeyPath, const android::String16& keyAlias, int64_t keyNspace,
+ int keyBootLevel);
bool initialize();
android::base::Result<std::vector<uint8_t>> verifyExistingKey();
android::base::Result<std::vector<uint8_t>> createKey();
@@ -53,4 +56,7 @@
android::sp<IKeystoreService> mService;
android::sp<IKeystoreSecurityLevel> mSecurityLevel;
std::vector<uint8_t> mPublicKey;
+
+ std::string mSignedPubKeyPath;
+ int mKeyBootLevel;
};
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 24a46b9..8ea0727 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -43,6 +43,11 @@
using android::base::unique_fd;
static const char* kFsVerityInitPath = "/system/bin/fsverity_init";
+static const char* kFsVerityProcPath = "/proc/sys/fs/verity";
+
+bool SupportsFsVerity() {
+ return access(kFsVerityProcPath, F_OK) == 0;
+}
static std::string toHex(std::span<const uint8_t> data) {
std::stringstream ss;
@@ -165,7 +170,7 @@
return {};
}
-static Result<std::string> enableFsVerity(int fd, const SigningKey& key) {
+Result<std::string> enableFsVerity(int fd, const SigningKey& key) {
auto digest = createDigest(fd);
if (!digest.ok()) {
return Error() << digest.error();
diff --git a/ondevice-signing/include/VerityUtils.h b/ondevice-signing/include/VerityUtils.h
index 0559c35..0650563 100644
--- a/ondevice-signing/include/VerityUtils.h
+++ b/ondevice-signing/include/VerityUtils.h
@@ -26,6 +26,8 @@
android::base::Result<void> addCertToFsVerityKeyring(const std::string& path, const char* keyName);
android::base::Result<std::vector<uint8_t>> createDigest(const std::string& path);
+android::base::Result<std::string> enableFsVerity(int fd, const SigningKey& key);
+bool SupportsFsVerity();
android::base::Result<std::map<std::string, std::string>>
verifyAllFilesInVerity(const std::string& path);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index c41fae5..8cf398e 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -44,6 +44,12 @@
using OdsignInfo = ::odsign::proto::OdsignInfo;
+// Keystore boot level that the odsign key uses
+const int kKeyBootLevel = 30;
+const std::string kPublicKeySignature = "/data/misc/odsign/publickey.signature";
+const android::String16 kKeyAlias{"ondevice-signing"};
+constexpr int kKeyNspace = 101; // odsign_key
+
const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
@@ -52,7 +58,6 @@
constexpr const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
constexpr const char* kCompOsVerifyPath = "/apex/com.android.compos/bin/compos_verify_key";
-constexpr const char* kFsVerityProcPath = "/proc/sys/fs/verity";
constexpr bool kForceCompilation = false;
constexpr bool kUseCompOs = true;
@@ -207,7 +212,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) {
@@ -242,7 +247,7 @@
return verifyDigests(*result, trusted_digests);
}
-Result<OdsignInfo> getOdsignInfo(const SigningKey& key) {
+Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
std::string persistedSignature;
OdsignInfo odsignInfo;
@@ -276,6 +281,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;
@@ -301,23 +328,8 @@
return {};
}
-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 signInfo.error();
- }
- std::map<std::string, std::string> trusted_digests(signInfo->file_hashes().begin(),
- signInfo->file_hashes().end());
+Result<void> verifyArtifactsIntegrity(const std::map<std::string, std::string>& trusted_digests,
+ bool supportsFsVerity) {
Result<void> integrityStatus;
if (supportsFsVerity) {
@@ -369,7 +381,8 @@
const SigningKey& signing_key,
bool* digests_verified) {
if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
- return art::odrefresh::ExitCode::kCompilationRequired;
+ // No pending CompOS artifacts, all that matters is the current ones.
+ return checkArtifacts();
}
// CompOS has generated some artifacts that may, or may not, match the
@@ -414,9 +427,17 @@
} else {
LOG(INFO) << "CompOS artifacts successfully verified.";
odrefresh_status = checkArtifacts();
- if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
- // We have digests of all the files, and they aren't going to change, so
- // we can just sign them & save them now, and skip checking them later.
+ switch (odrefresh_status) {
+ case art::odrefresh::ExitCode::kCompilationRequired:
+ // We have verified all the files, and we need to make sure
+ // we don't check them against odsign.info which will be out
+ // of date.
+ *digests_verified = true;
+ return odrefresh_status;
+ case art::odrefresh::ExitCode::kOkay: {
+ // We have digests of all the files, so we can just sign them & save them now.
+ // We need to make sure we don't check them against odsign.info which will
+ // be out of date.
auto persisted = persistDigests(compos_digests, signing_key);
if (!persisted.ok()) {
LOG(ERROR) << persisted.error();
@@ -426,8 +447,11 @@
}
LOG(INFO) << "Persisted CompOS digests.";
*digests_verified = true;
+ return odrefresh_status;
}
- return odrefresh_status;
+ default:
+ return odrefresh_status;
+ }
}
}
@@ -465,15 +489,15 @@
LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
return 0;
}
-
- auto keystoreResult = KeystoreKey::getInstance();
+ auto keystoreResult =
+ KeystoreKey::getInstance(kPublicKeySignature, kKeyAlias, kKeyNspace, kKeyBootLevel);
if (!keystoreResult.ok()) {
LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error();
return -1;
}
SigningKey* key = keystoreResult.value();
- bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
+ bool supportsFsVerity = SupportsFsVerity();
if (!supportsFsVerity) {
LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
}
@@ -510,32 +534,65 @@
auto compos_key = addCompOsCertToFsVerityKeyring(*key);
if (!compos_key.ok()) {
LOG(WARNING) << compos_key.error();
+ odrefresh_status = checkArtifacts();
} else {
odrefresh_status =
checkCompOsPendingArtifacts(compos_key.value(), *key, &digests_verified);
}
+ } else {
+ 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 && !digests_verified &&
+ (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 = verifyArtifactsIntegrity(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";
- if (!digests_verified) {
- // 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();
- return -1;
- }
- }
- }
} else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;