1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fcntl.h>
18 #include <filesystem>
19 #include <fstream>
20 #include <iomanip>
21 #include <iostream>
22 #include <iterator>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/scopeguard.h>
31 #include <logwrap/logwrap.h>
32 #include <odrefresh/odrefresh.h>
33
34 #include "CertUtils.h"
35 #include "KeystoreKey.h"
36 #include "StatsReporter.h"
37 #include "VerityUtils.h"
38
39 #include "odsign_info.pb.h"
40
41 using android::base::ErrnoError;
42 using android::base::Error;
43 using android::base::Result;
44 using android::base::SetProperty;
45
46 using OdsignInfo = ::odsign::proto::OdsignInfo;
47
48 // Keystore boot level that the odsign key uses
49 const int kKeyBootLevel = 30;
50 const std::string kPublicKeySignature = "/data/misc/odsign/publickey.signature";
51 const android::String16 kKeyAlias{"ondevice-signing"};
52 constexpr int kKeyNspace = 101; // odsign_key
53
54 const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
55 const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
56 const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
57
58 const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
59
60 constexpr const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
61 constexpr const char* kCompOsVerifyPath = "/apex/com.android.compos/bin/compos_verify";
62
63 constexpr bool kForceCompilation = false;
64 constexpr bool kUseCompOs = true;
65
66 const std::string kCompOsPendingArtifactsDir = "/data/misc/apexdata/com.android.art/compos-pending";
67 const std::string kCompOsInfo = kArtArtifactsDir + "/compos.info";
68 const std::string kCompOsInfoSignature = kCompOsInfo + ".signature";
69
70 constexpr const char* kCompOsPendingInfoPath =
71 "/data/misc/apexdata/com.android.art/compos-pending/compos.info";
72 constexpr const char* kCompOsPendingInfoSignaturePath =
73 "/data/misc/apexdata/com.android.art/compos-pending/compos.info.signature";
74
75 constexpr const char* kOdsignVerificationDoneProp = "odsign.verification.done";
76 constexpr const char* kOdsignKeyDoneProp = "odsign.key.done";
77
78 constexpr const char* kOdsignVerificationStatusProp = "odsign.verification.success";
79 constexpr const char* kOdsignVerificationStatusValid = "1";
80 constexpr const char* kOdsignVerificationStatusError = "0";
81
82 constexpr const char* kStopServiceProp = "ctl.stop";
83
84 enum class CompOsInstance { kCurrent, kPending };
85
86 namespace {
87
rename(const std::string & from,const std::string & to)88 bool rename(const std::string& from, const std::string& to) {
89 std::error_code ec;
90 std::filesystem::rename(from, to, ec);
91 if (ec) {
92 LOG(ERROR) << "Can't rename " << from << " to " << to << ": " << ec.message();
93 return false;
94 }
95 return true;
96 }
97
removeDirectory(const std::string & directory)98 int removeDirectory(const std::string& directory) {
99 std::error_code ec;
100 auto num_removed = std::filesystem::remove_all(directory, ec);
101 if (ec) {
102 LOG(ERROR) << "Can't remove " << directory << ": " << ec.message();
103 return 0;
104 } else {
105 if (num_removed > 0) {
106 LOG(INFO) << "Removed " << num_removed << " entries from " << directory;
107 }
108 return num_removed;
109 }
110 }
111
directoryHasContent(const std::string & directory)112 bool directoryHasContent(const std::string& directory) {
113 std::error_code ec;
114 return std::filesystem::is_directory(directory, ec) &&
115 !std::filesystem::is_empty(directory, ec);
116 }
117
compileArtifacts(bool force)118 art::odrefresh::ExitCode compileArtifacts(bool force) {
119 const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
120 const int exit_code =
121 logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
122 return static_cast<art::odrefresh::ExitCode>(exit_code);
123 }
124
checkArtifacts()125 art::odrefresh::ExitCode checkArtifacts() {
126 const char* const argv[] = {kOdrefreshPath, "--check"};
127 const int exit_code =
128 logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
129 return static_cast<art::odrefresh::ExitCode>(exit_code);
130 }
131
toHex(const std::vector<uint8_t> & digest)132 std::string toHex(const std::vector<uint8_t>& digest) {
133 std::stringstream ss;
134 for (auto it = digest.begin(); it != digest.end(); ++it) {
135 ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned>(*it);
136 }
137 return ss.str();
138 }
139
compOsPresent()140 bool compOsPresent() {
141 // We must have the CompOS APEX
142 return access(kCompOsVerifyPath, X_OK) == 0;
143 }
144
verifyExistingRootCert(const SigningKey & key)145 Result<void> verifyExistingRootCert(const SigningKey& key) {
146 if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
147 return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
148 }
149 auto trustedPublicKey = key.getPublicKey();
150 if (!trustedPublicKey.ok()) {
151 return Error() << "Failed to retrieve signing public key: " << trustedPublicKey.error();
152 }
153
154 auto publicKeyFromExistingCert = extractPublicKeyFromX509(kSigningKeyCert);
155 if (!publicKeyFromExistingCert.ok()) {
156 return publicKeyFromExistingCert.error();
157 }
158 if (publicKeyFromExistingCert.value() != trustedPublicKey.value()) {
159 return Error() << "Public key of existing certificate at " << kSigningKeyCert
160 << " does not match signing public key.";
161 }
162
163 // At this point, we know the cert is for our key; it's unimportant whether it's
164 // actually self-signed.
165 return {};
166 }
167
createX509RootCert(const SigningKey & key,const std::string & outPath)168 Result<void> createX509RootCert(const SigningKey& key, const std::string& outPath) {
169 auto publicKey = key.getPublicKey();
170
171 if (!publicKey.ok()) {
172 return publicKey.error();
173 }
174
175 auto keySignFunction = [&](const std::string& to_be_signed) { return key.sign(to_be_signed); };
176 return createSelfSignedCertificate(*publicKey, keySignFunction, outPath);
177 }
178
computeDigests(const std::string & path)179 Result<std::map<std::string, std::string>> computeDigests(const std::string& path) {
180 std::error_code ec;
181 std::map<std::string, std::string> digests;
182
183 auto it = std::filesystem::recursive_directory_iterator(path, ec);
184 auto end = std::filesystem::recursive_directory_iterator();
185
186 while (!ec && it != end) {
187 if (it->is_regular_file()) {
188 auto digest = createDigest(it->path());
189 if (!digest.ok()) {
190 return Error() << "Failed to compute digest for " << it->path() << ": "
191 << digest.error();
192 }
193 digests[it->path()] = toHex(*digest);
194 }
195 ++it;
196 }
197 if (ec) {
198 return Error() << "Failed to iterate " << path << ": " << ec;
199 }
200
201 return digests;
202 }
203
verifyDigests(const std::map<std::string,std::string> & digests,const std::map<std::string,std::string> & trusted_digests)204 Result<void> verifyDigests(const std::map<std::string, std::string>& digests,
205 const std::map<std::string, std::string>& trusted_digests) {
206 for (const auto& path_digest : digests) {
207 auto path = path_digest.first;
208 auto digest = path_digest.second;
209 if (trusted_digests.count(path) == 0) {
210 return Error() << "Couldn't find digest for " << path;
211 }
212 if (trusted_digests.at(path) != digest) {
213 return Error() << "Digest mismatch for " << path;
214 }
215 }
216
217 // All digests matched!
218 if (digests.size() > 0) {
219 LOG(INFO) << "All root hashes match.";
220 }
221 return {};
222 }
223
verifyIntegrityFsVerity(const std::map<std::string,std::string> & trusted_digests)224 Result<void> verifyIntegrityFsVerity(const std::map<std::string, std::string>& trusted_digests) {
225 // Just verify that the files are in verity, and get their digests
226 auto result = verifyAllFilesInVerity(kArtArtifactsDir);
227 if (!result.ok()) {
228 return result.error();
229 }
230
231 return verifyDigests(*result, trusted_digests);
232 }
233
verifyIntegrityNoFsVerity(const std::map<std::string,std::string> & trusted_digests)234 Result<void> verifyIntegrityNoFsVerity(const std::map<std::string, std::string>& trusted_digests) {
235 // On these devices, just compute the digests, and verify they match the ones we trust
236 auto result = computeDigests(kArtArtifactsDir);
237 if (!result.ok()) {
238 return result.error();
239 }
240
241 return verifyDigests(*result, trusted_digests);
242 }
243
getAndVerifyOdsignInfo(const SigningKey & key)244 Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
245 std::string persistedSignature;
246 OdsignInfo odsignInfo;
247
248 if (!android::base::ReadFileToString(kOdsignInfoSignature, &persistedSignature)) {
249 return ErrnoError() << "Failed to read " << kOdsignInfoSignature;
250 }
251
252 std::fstream odsign_info(kOdsignInfo, std::ios::in | std::ios::binary);
253 if (!odsign_info) {
254 return Error() << "Failed to open " << kOdsignInfo;
255 }
256 odsign_info.seekg(0);
257 // Verify the hash
258 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
259 std::istreambuf_iterator<char>());
260
261 auto publicKey = key.getPublicKey();
262 auto signResult = verifySignature(odsign_info_str, persistedSignature, *publicKey);
263 if (!signResult.ok()) {
264 return Error() << kOdsignInfoSignature << " does not match.";
265 } else {
266 LOG(INFO) << kOdsignInfoSignature << " matches.";
267 }
268
269 odsign_info.seekg(0);
270 if (!odsignInfo.ParseFromIstream(&odsign_info)) {
271 return Error() << "Failed to parse " << kOdsignInfo;
272 }
273
274 LOG(INFO) << "Loaded " << kOdsignInfo;
275 return odsignInfo;
276 }
277
getTrustedDigests(const SigningKey & key)278 std::map<std::string, std::string> getTrustedDigests(const SigningKey& key) {
279 std::map<std::string, std::string> trusted_digests;
280
281 if (access(kOdsignInfo.c_str(), F_OK) != 0) {
282 // no odsign info file, which is not necessarily an error - just return
283 // an empty list of digests.
284 LOG(INFO) << kOdsignInfo << " not found.";
285 return trusted_digests;
286 }
287 auto signInfo = getAndVerifyOdsignInfo(key);
288
289 if (signInfo.ok()) {
290 trusted_digests.insert(signInfo->file_hashes().begin(), signInfo->file_hashes().end());
291 } else {
292 // This is not expected, since the file did exist. Log an error and
293 // return an empty list of digests.
294 LOG(ERROR) << "Couldn't load trusted digests: " << signInfo.error();
295 }
296
297 return trusted_digests;
298 }
299
persistDigests(const std::map<std::string,std::string> & digests,const SigningKey & key)300 Result<void> persistDigests(const std::map<std::string, std::string>& digests,
301 const SigningKey& key) {
302 OdsignInfo signInfo;
303 google::protobuf::Map<std::string, std::string> proto_hashes(digests.begin(), digests.end());
304 auto map = signInfo.mutable_file_hashes();
305 *map = proto_hashes;
306
307 std::fstream odsign_info(kOdsignInfo,
308 std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
309 if (!signInfo.SerializeToOstream(&odsign_info)) {
310 return Error() << "Failed to persist root hashes in " << kOdsignInfo;
311 }
312
313 // Sign the signatures with our key itself, and write that to storage
314 odsign_info.seekg(0, std::ios::beg);
315 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
316 std::istreambuf_iterator<char>());
317 auto signResult = key.sign(odsign_info_str);
318 if (!signResult.ok()) {
319 return Error() << "Failed to sign " << kOdsignInfo;
320 }
321 android::base::WriteStringToFile(*signResult, kOdsignInfoSignature);
322 return {};
323 }
324
verifyArtifactsIntegrity(const std::map<std::string,std::string> & trusted_digests,bool supportsFsVerity)325 Result<void> verifyArtifactsIntegrity(const std::map<std::string, std::string>& trusted_digests,
326 bool supportsFsVerity) {
327 Result<void> integrityStatus;
328
329 if (supportsFsVerity) {
330 integrityStatus = verifyIntegrityFsVerity(trusted_digests);
331 } else {
332 integrityStatus = verifyIntegrityNoFsVerity(trusted_digests);
333 }
334 if (!integrityStatus.ok()) {
335 return integrityStatus.error();
336 }
337
338 return {};
339 }
340
getComposInfo()341 Result<OdsignInfo> getComposInfo() {
342 const char* const argv[] = {kCompOsVerifyPath, "--instance", "current"};
343 int result =
344 logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
345 if (result != 0) {
346 return Error() << kCompOsVerifyPath << " returned " << result;
347 }
348
349 std::string compos_info_str;
350 if (!android::base::ReadFileToString(kCompOsInfo, &compos_info_str)) {
351 return ErrnoError() << "Failed to read " << kCompOsInfo;
352 }
353
354 // Delete the files - we don't need them any more, and they'd confuse
355 // artifact verification
356 if (unlink(kCompOsInfo.c_str()) != 0 || unlink(kCompOsInfoSignature.c_str()) != 0) {
357 return ErrnoError() << "Unable to delete CompOS info/signature file";
358 }
359
360 OdsignInfo compos_info;
361 if (!compos_info.ParseFromString(compos_info_str)) {
362 return Error() << "Failed to parse " << kCompOsInfo;
363 }
364
365 LOG(INFO) << "Loaded " << kCompOsInfo;
366 return compos_info;
367 }
368
CheckCompOsPendingArtifacts(const SigningKey & signing_key,bool * digests_verified,StatsReporter * stats_reporter)369 art::odrefresh::ExitCode CheckCompOsPendingArtifacts(const SigningKey& signing_key,
370 bool* digests_verified,
371 StatsReporter* stats_reporter) {
372 StatsReporter::CompOsArtifactsCheckRecord* compos_check_record =
373 stats_reporter->GetComposArtifactsCheckRecord();
374
375 if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
376 // No pending CompOS artifacts, all that matters is the current ones.
377 art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
378 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
379 compos_check_record->current_artifacts_ok = true;
380 }
381 return odrefresh_status;
382 }
383
384 compos_check_record->comp_os_pending_artifacts_exists = true;
385
386 // CompOS has generated some artifacts that may, or may not, match the
387 // current state. But if there are already valid artifacts present the
388 // CompOS ones are redundant.
389 art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
390 if (odrefresh_status != art::odrefresh::ExitCode::kCompilationRequired) {
391 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
392 compos_check_record->current_artifacts_ok = true;
393 LOG(INFO) << "Current artifacts are OK, deleting pending artifacts";
394 removeDirectory(kCompOsPendingArtifactsDir);
395 }
396 return odrefresh_status;
397 }
398
399 // No useful current artifacts, lets see if the CompOS ones are ok
400 if (access(kCompOsPendingInfoPath, R_OK) != 0 ||
401 access(kCompOsPendingInfoSignaturePath, R_OK) != 0) {
402 LOG(INFO) << "Missing CompOS info/signature, deleting pending artifacts";
403 removeDirectory(kCompOsPendingArtifactsDir);
404 return art::odrefresh::ExitCode::kCompilationRequired;
405 }
406
407 LOG(INFO) << "Current artifacts are out of date, switching to pending artifacts";
408 removeDirectory(kArtArtifactsDir);
409 if (!rename(kCompOsPendingArtifactsDir, kArtArtifactsDir)) {
410 removeDirectory(kCompOsPendingArtifactsDir);
411 return art::odrefresh::ExitCode::kCompilationRequired;
412 }
413
414 // Make sure the artifacts we have are genuinely produced by the current
415 // instance of CompOS.
416 auto compos_info = getComposInfo();
417 if (!compos_info.ok()) {
418 LOG(WARNING) << compos_info.error();
419 } else {
420 std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
421 compos_info->file_hashes().end());
422
423 auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests, signing_key);
424 if (!status.ok()) {
425 LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
426 } else {
427 LOG(INFO) << "CompOS artifacts successfully verified.";
428 odrefresh_status = checkArtifacts();
429 switch (odrefresh_status) {
430 case art::odrefresh::ExitCode::kCompilationRequired:
431 // We have verified all the files, and we need to make sure
432 // we don't check them against odsign.info which will be out
433 // of date.
434 *digests_verified = true;
435 return odrefresh_status;
436 case art::odrefresh::ExitCode::kOkay: {
437 // We have digests of all the files, so we can just sign them & save them now.
438 // We need to make sure we don't check them against odsign.info which will
439 // be out of date.
440 auto persisted = persistDigests(compos_digests, signing_key);
441 if (!persisted.ok()) {
442 LOG(ERROR) << persisted.error();
443 // Don't try to compile again - if we can't write the digests, things
444 // are pretty bad.
445 return art::odrefresh::ExitCode::kCleanupFailed;
446 }
447 compos_check_record->use_comp_os_generated_artifacts = true;
448 LOG(INFO) << "Persisted CompOS digests.";
449 *digests_verified = true;
450 return odrefresh_status;
451 }
452 default:
453 return odrefresh_status;
454 }
455 }
456 }
457
458 // We can't use the existing artifacts, so we will need to generate new
459 // ones.
460 if (removeDirectory(kArtArtifactsDir) == 0) {
461 // We have unsigned artifacts that we can't delete, so it's not safe to continue.
462 LOG(ERROR) << "Unable to delete invalid CompOS artifacts";
463 return art::odrefresh::ExitCode::kCleanupFailed;
464 }
465
466 return art::odrefresh::ExitCode::kCompilationRequired;
467 }
468 } // namespace
469
main(int,char ** argv)470 int main(int /* argc */, char** argv) {
471 // stats_reporter is a pointer so that we can explicitly delete it
472 // instead of waiting for the program to die & its destrcutor be called
473 auto stats_reporter = std::make_unique<StatsReporter>();
474 android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
475
476 auto errorScopeGuard = []() {
477 // In case we hit any error, remove the artifacts and tell Zygote not to use
478 // anything
479 removeDirectory(kArtArtifactsDir);
480 removeDirectory(kCompOsPendingArtifactsDir);
481 // Tell init we don't need to use our key anymore
482 SetProperty(kOdsignKeyDoneProp, "1");
483 // Tell init we're done with verification, and that it was an error
484 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusError);
485 SetProperty(kOdsignVerificationDoneProp, "1");
486 // Tell init it shouldn't try to restart us - see odsign.rc
487 SetProperty(kStopServiceProp, "odsign");
488 };
489 auto scope_guard = android::base::make_scope_guard(errorScopeGuard);
490
491 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
492 LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
493 return 0;
494 }
495 auto keystoreResult =
496 KeystoreKey::getInstance(kPublicKeySignature, kKeyAlias, kKeyNspace, kKeyBootLevel);
497 if (!keystoreResult.ok()) {
498 LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error();
499 return -1;
500 }
501 SigningKey* key = keystoreResult.value();
502
503 bool supportsFsVerity = SupportsFsVerity();
504 if (!supportsFsVerity) {
505 LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
506 }
507
508 bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent();
509
510 if (supportsFsVerity) {
511 auto existing_cert = verifyExistingRootCert(*key);
512 if (!existing_cert.ok()) {
513 LOG(WARNING) << existing_cert.error();
514
515 // Try to create a new cert
516 auto new_cert = createX509RootCert(*key, kSigningKeyCert);
517 if (!new_cert.ok()) {
518 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error();
519 // TODO apparently the key become invalid - delete the blob / cert
520 return -1;
521 }
522 } else {
523 LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
524 }
525 auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert, "fsv_ods");
526 if (!cert_add_result.ok()) {
527 LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
528 << cert_add_result.error();
529 return -1;
530 }
531 }
532
533 bool digests_verified = false;
534 art::odrefresh::ExitCode odrefresh_status =
535 useCompOs ? CheckCompOsPendingArtifacts(*key, &digests_verified, stats_reporter.get())
536 : checkArtifacts();
537
538 // Explicitly reset the pointer - We rely on stats_reporter's
539 // destructor for actually writing the buffered metrics. This will otherwise not be called
540 // if the program doesn't exit normally (for ex, killed by init, which actually happens
541 // because odsign (after it finishes) sets kStopServiceProp instructing init to kill it).
542 stats_reporter.reset();
543
544 // The artifacts dir doesn't necessarily need to exist; if the existing
545 // artifacts on the system partition are valid, those can be used.
546 int err = access(kArtArtifactsDir.c_str(), F_OK);
547 // If we receive any error other than ENOENT, be suspicious
548 bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
549
550 if (artifactsPresent && !digests_verified &&
551 (odrefresh_status == art::odrefresh::ExitCode::kOkay ||
552 odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired)) {
553 // If we haven't verified the digests yet, we need to validate them. We
554 // need to do this both in case the existing artifacts are okay, but
555 // also if odrefresh said that a recompile is required. In the latter
556 // case, odrefresh may use partial compilation, and leave some
557 // artifacts unchanged.
558 auto trusted_digests = getTrustedDigests(*key);
559
560 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
561 // Tell init we're done with the key; this is a boot time optimization
562 // in particular for the no fs-verity case, where we need to do a
563 // costly verification. If the files haven't been tampered with, which
564 // should be the common path, the verification will succeed, and we won't
565 // need the key anymore. If it turns out the artifacts are invalid (eg not
566 // in fs-verity) or the hash doesn't match, we won't be able to generate
567 // new artifacts without the key, so in those cases, remove the artifacts,
568 // and use JIT zygote for the current boot. We should recover automatically
569 // by the next boot.
570 SetProperty(kOdsignKeyDoneProp, "1");
571 }
572
573 auto verificationResult = verifyArtifactsIntegrity(trusted_digests, supportsFsVerity);
574 if (!verificationResult.ok()) {
575 int num_removed = removeDirectory(kArtArtifactsDir);
576 if (num_removed == 0) {
577 // If we can't remove the bad artifacts, we shouldn't continue, and
578 // instead prevent Zygote from using them (which is taken care of
579 // in the exit handler).
580 LOG(ERROR) << "Failed to remove unknown artifacts.";
581 return -1;
582 }
583 }
584 }
585
586 // Now that we verified existing artifacts, compile if we need to.
587 if (odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired) {
588 odrefresh_status = compileArtifacts(kForceCompilation);
589 }
590
591 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
592 // No new artifacts generated, and we verified existing ones above, nothing left to do.
593 LOG(INFO) << "odrefresh said artifacts are VALID";
594 } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
595 odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
596 const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;
597 LOG(INFO) << "odrefresh compiled " << (compiled_all ? "all" : "partial")
598 << " artifacts, returned " << odrefresh_status;
599 Result<std::map<std::string, std::string>> digests;
600 if (supportsFsVerity) {
601 digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
602 } else {
603 // If we can't use verity, just compute the root hashes and store
604 // those, so we can reverify them at the next boot.
605 digests = computeDigests(kArtArtifactsDir);
606 }
607 if (!digests.ok()) {
608 LOG(ERROR) << digests.error();
609 return -1;
610 }
611 auto persistStatus = persistDigests(*digests, *key);
612 if (!persistStatus.ok()) {
613 LOG(ERROR) << persistStatus.error();
614 return -1;
615 }
616 } else if (odrefresh_status == art::odrefresh::ExitCode::kCleanupFailed) {
617 LOG(ERROR) << "odrefresh failed cleaning up existing artifacts";
618 return -1;
619 } else {
620 LOG(ERROR) << "odrefresh exited unexpectedly, returned " << odrefresh_status;
621 return -1;
622 }
623
624 LOG(INFO) << "On-device signing done.";
625
626 scope_guard.Disable();
627 // At this point, we're done with the key for sure
628 SetProperty(kOdsignKeyDoneProp, "1");
629 // And we did a successful verification
630 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusValid);
631 SetProperty(kOdsignVerificationDoneProp, "1");
632
633 // Tell init it shouldn't try to restart us - see odsign.rc
634 SetProperty(kStopServiceProp, "odsign");
635 return 0;
636 }
637