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