• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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