blob: a688ead6d3f4cd1699528a9fa1292c2bb78dd03d [file] [log] [blame]
Martijn Coenen95194842020-09-24 16:56:46 +02001/*
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>
Martijn Coenen5588e492021-02-25 14:33:44 +010019#include <fstream>
Martijn Coenen95194842020-09-24 16:56:46 +020020#include <iomanip>
21#include <iostream>
Martijn Coenen5588e492021-02-25 14:33:44 +010022#include <iterator>
Martijn Coenen95194842020-09-24 16:56:46 +020023#include <sys/stat.h>
24#include <sys/types.h>
Martijn Coenen95194842020-09-24 16:56:46 +020025#include <unistd.h>
26
27#include <android-base/file.h>
28#include <android-base/logging.h>
Martijn Coenen688244f2021-03-15 13:43:45 +010029#include <android-base/properties.h>
Martijn Coenen95194842020-09-24 16:56:46 +020030#include <android-base/scopeguard.h>
31#include <logwrap/logwrap.h>
Orion Hodson2f7807b2021-03-22 17:07:03 +000032#include <odrefresh/odrefresh.h>
Martijn Coenen95194842020-09-24 16:56:46 +020033
34#include "CertUtils.h"
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010035#include "KeystoreKey.h"
Shikha Panwar9429c9e2022-01-26 14:50:39 +000036#include "StatsReporter.h"
Martijn Coenen95194842020-09-24 16:56:46 +020037#include "VerityUtils.h"
Jiakai Zhang693854b2022-11-02 17:33:28 +000038#include "statslog_odsign.h"
Martijn Coenen95194842020-09-24 16:56:46 +020039
Martijn Coenen5588e492021-02-25 14:33:44 +010040#include "odsign_info.pb.h"
41
Martijn Coenen95194842020-09-24 16:56:46 +020042using android::base::ErrnoError;
43using android::base::Error;
44using android::base::Result;
Martijn Coenen688244f2021-03-15 13:43:45 +010045using android::base::SetProperty;
Martijn Coenen95194842020-09-24 16:56:46 +020046
Martijn Coenen5588e492021-02-25 14:33:44 +010047using OdsignInfo = ::odsign::proto::OdsignInfo;
48
Jeff Vander Stoepa20f50c2022-02-10 15:10:30 +010049// Keystore boot level that the odsign key uses
50const int kKeyBootLevel = 30;
51const std::string kPublicKeySignature = "/data/misc/odsign/publickey.signature";
52const android::String16 kKeyAlias{"ondevice-signing"};
53constexpr int kKeyNspace = 101; // odsign_key
54
Martijn Coenen95194842020-09-24 16:56:46 +020055const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
Martijn Coenen5588e492021-02-25 14:33:44 +010056const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
57const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
Martijn Coenen95194842020-09-24 16:56:46 +020058
Martijn Coenenb6afe132021-02-19 09:32:48 +010059const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
Martijn Coenen95194842020-09-24 16:56:46 +020060
Alan Stokescd193a92021-07-29 15:28:52 +010061constexpr const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
Alan Stokes4827dd52022-02-23 13:43:36 +000062constexpr const char* kCompOsVerifyPath = "/apex/com.android.compos/bin/compos_verify";
Martijn Coenen95194842020-09-24 16:56:46 +020063
Alan Stokescd193a92021-07-29 15:28:52 +010064constexpr bool kForceCompilation = false;
Alan Stokes359e3df2021-09-01 15:02:25 +010065constexpr bool kUseCompOs = true;
Alan Stokesb1821782021-06-07 14:57:15 +010066
Alan Stokesd2bfee02021-07-12 15:42:58 +010067const std::string kCompOsPendingArtifactsDir = "/data/misc/apexdata/com.android.art/compos-pending";
Alan Stokesd8a24472021-12-07 15:27:09 +000068const std::string kCompOsInfo = kArtArtifactsDir + "/compos.info";
69const std::string kCompOsInfoSignature = kCompOsInfo + ".signature";
70
71constexpr const char* kCompOsPendingInfoPath =
72 "/data/misc/apexdata/com.android.art/compos-pending/compos.info";
73constexpr const char* kCompOsPendingInfoSignaturePath =
74 "/data/misc/apexdata/com.android.art/compos-pending/compos.info.signature";
Martijn Coenen95194842020-09-24 16:56:46 +020075
Alan Stokescd193a92021-07-29 15:28:52 +010076constexpr const char* kOdsignVerificationDoneProp = "odsign.verification.done";
77constexpr const char* kOdsignKeyDoneProp = "odsign.key.done";
Martijn Coenen688244f2021-03-15 13:43:45 +010078
Alan Stokescd193a92021-07-29 15:28:52 +010079constexpr const char* kOdsignVerificationStatusProp = "odsign.verification.success";
80constexpr const char* kOdsignVerificationStatusValid = "1";
81constexpr const char* kOdsignVerificationStatusError = "0";
Martijn Coenen688244f2021-03-15 13:43:45 +010082
Alan Stokescd193a92021-07-29 15:28:52 +010083constexpr const char* kStopServiceProp = "ctl.stop";
Alan Stokesbfd2ec02021-06-09 18:00:54 +010084
Alan Stokes359e3df2021-09-01 15:02:25 +010085enum class CompOsInstance { kCurrent, kPending };
86
Alan Stokesb9b83f02021-12-08 11:44:20 +000087namespace {
88
Alan Stokesb9b83f02021-12-08 11:44:20 +000089bool rename(const std::string& from, const std::string& to) {
Alan Stokescd193a92021-07-29 15:28:52 +010090 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
Alan Stokesb9b83f02021-12-08 11:44:20 +000099int removeDirectory(const std::string& directory) {
Alan Stokes35049b62021-06-25 12:16:13 +0100100 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
Alan Stokesb9b83f02021-12-08 11:44:20 +0000113bool directoryHasContent(const std::string& directory) {
Alan Stokes35049b62021-06-25 12:16:13 +0100114 std::error_code ec;
115 return std::filesystem::is_directory(directory, ec) &&
116 !std::filesystem::is_empty(directory, ec);
117}
118
119art::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
126art::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
Alan Stokesb9b83f02021-12-08 11:44:20 +0000133std::string toHex(const std::vector<uint8_t>& digest) {
Alan Stokes35049b62021-06-25 12:16:13 +0100134 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
Alan Stokesb1821782021-06-07 14:57:15 +0100141bool compOsPresent() {
Alan Stokesa18130b2022-02-03 17:23:26 +0000142 // We must have the CompOS APEX
Alan Stokes4827dd52022-02-23 13:43:36 +0000143 return access(kCompOsVerifyPath, X_OK) == 0;
Alan Stokes359e3df2021-09-01 15:02:25 +0100144}
145
Alan Stokesb1821782021-06-07 14:57:15 +0100146Result<void> verifyExistingRootCert(const SigningKey& key) {
Martijn Coenen95194842020-09-24 16:56:46 +0200147 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()) {
Alan Stokesb1821782021-06-07 14:57:15 +0100152 return Error() << "Failed to retrieve signing public key: " << trustedPublicKey.error();
Martijn Coenen95194842020-09-24 16:56:46 +0200153 }
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
Alan Stokesb1821782021-06-07 14:57:15 +0100164 // At this point, we know the cert is for our key; it's unimportant whether it's
165 // actually self-signed.
Martijn Coenen95194842020-09-24 16:56:46 +0200166 return {};
167}
168
Alan Stokesb1821782021-06-07 14:57:15 +0100169Result<void> createX509RootCert(const SigningKey& key, const std::string& outPath) {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100170 auto publicKey = key.getPublicKey();
Martijn Coenen95194842020-09-24 16:56:46 +0200171
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100172 if (!publicKey.ok()) {
173 return publicKey.error();
Martijn Coenen95194842020-09-24 16:56:46 +0200174 }
175
Martijn Coenen9451c052021-05-19 13:06:55 +0200176 auto keySignFunction = [&](const std::string& to_be_signed) { return key.sign(to_be_signed); };
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100177 return createSelfSignedCertificate(*publicKey, keySignFunction, outPath);
Martijn Coenen95194842020-09-24 16:56:46 +0200178}
179
Martijn Coenen5588e492021-02-25 14:33:44 +0100180Result<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()) {
Alan Stokes35049b62021-06-25 12:16:13 +0100191 return Error() << "Failed to compute digest for " << it->path() << ": "
192 << digest.error();
Martijn Coenen5588e492021-02-25 14:33:44 +0100193 }
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
205Result<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;
Martijn Coenena01eac32021-11-19 16:46:28 +0100210 if (trusted_digests.count(path) == 0) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100211 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
225Result<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
235Result<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
Martijn Coenena01eac32021-11-19 16:46:28 +0100245Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100246 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 }
Martijn Coenendc05bb32021-03-08 10:52:48 +0100257 odsign_info.seekg(0);
Martijn Coenen5588e492021-02-25 14:33:44 +0100258 // Verify the hash
259 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
260 std::istreambuf_iterator<char>());
261
Martijn Coenendc05bb32021-03-08 10:52:48 +0100262 auto publicKey = key.getPublicKey();
263 auto signResult = verifySignature(odsign_info_str, persistedSignature, *publicKey);
264 if (!signResult.ok()) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100265 return Error() << kOdsignInfoSignature << " does not match.";
266 } else {
267 LOG(INFO) << kOdsignInfoSignature << " matches.";
268 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100269
Martijn Coenendc05bb32021-03-08 10:52:48 +0100270 odsign_info.seekg(0);
Martijn Coenen5588e492021-02-25 14:33:44 +0100271 if (!odsignInfo.ParseFromIstream(&odsign_info)) {
272 return Error() << "Failed to parse " << kOdsignInfo;
273 }
274
275 LOG(INFO) << "Loaded " << kOdsignInfo;
276 return odsignInfo;
277}
278
Martijn Coenena01eac32021-11-19 16:46:28 +0100279std::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
Martijn Coenen5588e492021-02-25 14:33:44 +0100301Result<void> persistDigests(const std::map<std::string, std::string>& digests,
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100302 const SigningKey& key) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100303 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
Martijn Coenendc05bb32021-03-08 10:52:48 +0100308 std::fstream odsign_info(kOdsignInfo,
309 std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
Martijn Coenen5588e492021-02-25 14:33:44 +0100310 if (!signInfo.SerializeToOstream(&odsign_info)) {
311 return Error() << "Failed to persist root hashes in " << kOdsignInfo;
312 }
313
Martijn Coenendc05bb32021-03-08 10:52:48 +0100314 // Sign the signatures with our key itself, and write that to storage
315 odsign_info.seekg(0, std::ios::beg);
Martijn Coenen5588e492021-02-25 14:33:44 +0100316 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 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100322 android::base::WriteStringToFile(*signResult, kOdsignInfoSignature);
323 return {};
324}
325
Alan Stokes59f655d2021-12-08 11:44:20 +0000326Result<void> verifyArtifactsIntegrity(const std::map<std::string, std::string>& trusted_digests,
327 bool supportsFsVerity) {
Martijn Coenen688244f2021-03-15 13:43:45 +0100328 Result<void> integrityStatus;
329
330 if (supportsFsVerity) {
331 integrityStatus = verifyIntegrityFsVerity(trusted_digests);
332 } else {
333 integrityStatus = verifyIntegrityNoFsVerity(trusted_digests);
334 }
335 if (!integrityStatus.ok()) {
Alan Stokesb1821782021-06-07 14:57:15 +0100336 return integrityStatus.error();
Martijn Coenen688244f2021-03-15 13:43:45 +0100337 }
338
339 return {};
340}
341
Alan Stokes4827dd52022-02-23 13:43:36 +0000342Result<OdsignInfo> getComposInfo() {
343 const char* const argv[] = {kCompOsVerifyPath, "--instance", "current"};
Alan Stokes466ed1f2022-02-15 14:52:27 +0000344 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;
Alan Stokesd8a24472021-12-07 15:27:09 +0000348 }
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
Alan Stokes466ed1f2022-02-15 14:52:27 +0000355 // Delete the files - we don't need them any more, and they'd confuse
356 // artifact verification
Alan Stokesd8a24472021-12-07 15:27:09 +0000357 if (unlink(kCompOsInfo.c_str()) != 0 || unlink(kCompOsInfoSignature.c_str()) != 0) {
358 return ErrnoError() << "Unable to delete CompOS info/signature file";
359 }
360
Alan Stokesd8a24472021-12-07 15:27:09 +0000361 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
Shikha Panwar9429c9e2022-01-26 14:50:39 +0000370art::odrefresh::ExitCode CheckCompOsPendingArtifacts(const SigningKey& signing_key,
371 bool* digests_verified,
372 StatsReporter* stats_reporter) {
373 StatsReporter::CompOsArtifactsCheckRecord* compos_check_record =
Jiakai Zhang693854b2022-11-02 17:33:28 +0000374 stats_reporter->GetOrCreateComposArtifactsCheckRecord();
Shikha Panwar9429c9e2022-01-26 14:50:39 +0000375
Alan Stokesd2bfee02021-07-12 15:42:58 +0100376 if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
Alan Stokes7f6912c2022-02-01 15:35:35 +0000377 // No pending CompOS artifacts, all that matters is the current ones.
Shikha Panwar4d7f9052022-05-24 14:52:20 +0000378 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;
Alan Stokes35049b62021-06-25 12:16:13 +0100383 }
384
Shikha Panwar9429c9e2022-01-26 14:50:39 +0000385 compos_check_record->comp_os_pending_artifacts_exists = true;
386
Alan Stokesd8a24472021-12-07 15:27:09 +0000387 // CompOS has generated some artifacts that may, or may not, match the
Alan Stokes35049b62021-06-25 12:16:13 +0100388 // current state. But if there are already valid artifacts present the
Alan Stokesd8a24472021-12-07 15:27:09 +0000389 // CompOS ones are redundant.
Alan Stokes35049b62021-06-25 12:16:13 +0100390 art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
391 if (odrefresh_status != art::odrefresh::ExitCode::kCompilationRequired) {
392 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
Shikha Panwar9429c9e2022-01-26 14:50:39 +0000393 compos_check_record->current_artifacts_ok = true;
Alan Stokes35049b62021-06-25 12:16:13 +0100394 LOG(INFO) << "Current artifacts are OK, deleting pending artifacts";
Alan Stokesd2bfee02021-07-12 15:42:58 +0100395 removeDirectory(kCompOsPendingArtifactsDir);
Alan Stokes35049b62021-06-25 12:16:13 +0100396 }
397 return odrefresh_status;
398 }
399
Alan Stokesd8a24472021-12-07 15:27:09 +0000400 // 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
Alan Stokes35049b62021-06-25 12:16:13 +0100408 LOG(INFO) << "Current artifacts are out of date, switching to pending artifacts";
409 removeDirectory(kArtArtifactsDir);
Alan Stokescd193a92021-07-29 15:28:52 +0100410 if (!rename(kCompOsPendingArtifactsDir, kArtArtifactsDir)) {
Alan Stokesd2bfee02021-07-12 15:42:58 +0100411 removeDirectory(kCompOsPendingArtifactsDir);
Alan Stokes35049b62021-06-25 12:16:13 +0100412 return art::odrefresh::ExitCode::kCompilationRequired;
413 }
Alan Stokescd193a92021-07-29 15:28:52 +0100414
Alan Stokes25870872022-01-10 10:59:39 +0000415 // Make sure the artifacts we have are genuinely produced by the current
416 // instance of CompOS.
Alan Stokes4827dd52022-02-23 13:43:36 +0000417 auto compos_info = getComposInfo();
Alan Stokesd8a24472021-12-07 15:27:09 +0000418 if (!compos_info.ok()) {
419 LOG(WARNING) << compos_info.error();
Alan Stokes35049b62021-06-25 12:16:13 +0100420 } else {
Alan Stokesd8a24472021-12-07 15:27:09 +0000421 std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
422 compos_info->file_hashes().end());
423
Victor Hsiehf2ac7c62022-11-17 16:58:10 -0800424 auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests);
Alan Stokesd8a24472021-12-07 15:27:09 +0000425 if (!status.ok()) {
Alan Stokes25870872022-01-10 10:59:39 +0000426 LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
Alan Stokesd8a24472021-12-07 15:27:09 +0000427 } else {
Alan Stokes25870872022-01-10 10:59:39 +0000428 LOG(INFO) << "CompOS artifacts successfully verified.";
429 odrefresh_status = checkArtifacts();
Alan Stokes63c5dfc2022-01-10 10:59:39 +0000430 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.
Alan Stokesd8a24472021-12-07 15:27:09 +0000435 *digests_verified = true;
Alan Stokes63c5dfc2022-01-10 10:59:39 +0000436 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.
Alan Stokes25870872022-01-10 10:59:39 +0000441 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 }
Shikha Panwar9429c9e2022-01-26 14:50:39 +0000448 compos_check_record->use_comp_os_generated_artifacts = true;
Alan Stokes25870872022-01-10 10:59:39 +0000449 LOG(INFO) << "Persisted CompOS digests.";
Alan Stokesd8a24472021-12-07 15:27:09 +0000450 *digests_verified = true;
Alan Stokes63c5dfc2022-01-10 10:59:39 +0000451 return odrefresh_status;
Alan Stokesd8a24472021-12-07 15:27:09 +0000452 }
Alan Stokes63c5dfc2022-01-10 10:59:39 +0000453 default:
454 return odrefresh_status;
Alan Stokesd8a24472021-12-07 15:27:09 +0000455 }
456 }
Alan Stokes35049b62021-06-25 12:16:13 +0100457 }
458
459 // We can't use the existing artifacts, so we will need to generate new
460 // ones.
Alan Stokes25870872022-01-10 10:59:39 +0000461 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
Alan Stokes35049b62021-06-25 12:16:13 +0100467 return art::odrefresh::ExitCode::kCompilationRequired;
468}
Alan Stokesb9b83f02021-12-08 11:44:20 +0000469} // namespace
Alan Stokes35049b62021-06-25 12:16:13 +0100470
Orion Hodson646e4b92021-09-27 13:50:36 +0100471int main(int /* argc */, char** argv) {
472 android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
473
Jiakai Zhang693854b2022-11-02 17:33:28 +0000474 auto scope_guard = android::base::make_scope_guard([]() {
Alan Stokes359e3df2021-09-01 15:02:25 +0100475 // In case we hit any error, remove the artifacts and tell Zygote not to use
476 // anything
Alan Stokes35049b62021-06-25 12:16:13 +0100477 removeDirectory(kArtArtifactsDir);
Alan Stokesd2bfee02021-07-12 15:42:58 +0100478 removeDirectory(kCompOsPendingArtifactsDir);
Martijn Coenen688244f2021-03-15 13:43:45 +0100479 // 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
Martijn Coenen688244f2021-03-15 13:43:45 +0100482 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusError);
Martijn Coenen2e8a9842021-07-27 13:40:23 +0200483 SetProperty(kOdsignVerificationDoneProp, "1");
484 // Tell init it shouldn't try to restart us - see odsign.rc
485 SetProperty(kStopServiceProp, "odsign");
Jiakai Zhang693854b2022-11-02 17:33:28 +0000486 });
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();
Martijn Coenen95194842020-09-24 16:56:46 +0200492
Martijn Coenene9e9b702021-03-23 17:30:46 +0100493 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
494 LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
Jiakai Zhang693854b2022-11-02 17:33:28 +0000495 stats_reporter->SetOdsignRecordEnabled(false);
Martijn Coenene9e9b702021-03-23 17:30:46 +0100496 return 0;
497 }
Jeff Vander Stoepa20f50c2022-02-10 15:10:30 +0100498 auto keystoreResult =
499 KeystoreKey::getInstance(kPublicKeySignature, kKeyAlias, kKeyNspace, kKeyBootLevel);
Martijn Coenen9451c052021-05-19 13:06:55 +0200500 if (!keystoreResult.ok()) {
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100501 LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error();
Jiakai Zhang693854b2022-11-02 17:33:28 +0000502 odsign_record->status =
503 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_KEYSTORE_FAILED;
Martijn Coenen9451c052021-05-19 13:06:55 +0200504 return -1;
Martijn Coenen95194842020-09-24 16:56:46 +0200505 }
Martijn Coenen9451c052021-05-19 13:06:55 +0200506 SigningKey* key = keystoreResult.value();
Martijn Coenen95194842020-09-24 16:56:46 +0200507
Jeff Vander Stoepa20f50c2022-02-10 15:10:30 +0100508 bool supportsFsVerity = SupportsFsVerity();
Martijn Coenen5588e492021-02-25 14:33:44 +0100509 if (!supportsFsVerity) {
510 LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
511 }
Martijn Coenen95194842020-09-24 16:56:46 +0200512
Alan Stokes181c8252022-01-12 10:18:05 +0000513 bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent();
Alan Stokesb1821782021-06-07 14:57:15 +0100514
Martijn Coenen5588e492021-02-25 14:33:44 +0100515 if (supportsFsVerity) {
Alan Stokesb1821782021-06-07 14:57:15 +0100516 auto existing_cert = verifyExistingRootCert(*key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100517 if (!existing_cert.ok()) {
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100518 LOG(WARNING) << existing_cert.error();
Martijn Coenen5588e492021-02-25 14:33:44 +0100519
520 // Try to create a new cert
Alan Stokesb1821782021-06-07 14:57:15 +0100521 auto new_cert = createX509RootCert(*key, kSigningKeyCert);
Martijn Coenen5588e492021-02-25 14:33:44 +0100522 if (!new_cert.ok()) {
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100523 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error();
Martijn Coenen5588e492021-02-25 14:33:44 +0100524 // TODO apparently the key become invalid - delete the blob / cert
Jiakai Zhang693854b2022-11-02 17:33:28 +0000525 odsign_record->status =
526 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CERT_FAILED;
Martijn Coenen5588e492021-02-25 14:33:44 +0100527 return -1;
528 }
529 } else {
530 LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
531 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100532 }
533
Alan Stokes35049b62021-06-25 12:16:13 +0100534 bool digests_verified = false;
Alan Stokes4827dd52022-02-23 13:43:36 +0000535 art::odrefresh::ExitCode odrefresh_status =
Shikha Panwar9429c9e2022-01-26 14:50:39 +0000536 useCompOs ? CheckCompOsPendingArtifacts(*key, &digests_verified, stats_reporter.get())
537 : checkArtifacts();
538
Martijn Coenena01eac32021-11-19 16:46:28 +0100539 // 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.";
Jiakai Zhang693854b2022-11-02 17:33:28 +0000576 odsign_record->status =
577 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CLEANUP_FAILED;
Martijn Coenena01eac32021-11-19 16:46:28 +0100578 return -1;
579 }
580 }
581 }
582
583 // Now that we verified existing artifacts, compile if we need to.
Alan Stokes35049b62021-06-25 12:16:13 +0100584 if (odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired) {
585 odrefresh_status = compileArtifacts(kForceCompilation);
586 }
Martijn Coenena01eac32021-11-19 16:46:28 +0100587
Orion Hodson2f7807b2021-03-22 17:07:03 +0000588 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
Martijn Coenena01eac32021-11-19 16:46:28 +0100589 // No new artifacts generated, and we verified existing ones above, nothing left to do.
Orion Hodson2f7807b2021-03-22 17:07:03 +0000590 LOG(INFO) << "odrefresh said artifacts are VALID";
Jiakai Zhang693854b2022-11-02 17:33:28 +0000591 stats_reporter->SetOdsignRecordEnabled(false);
Orion Hodson2f7807b2021-03-22 17:07:03 +0000592 } 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;
Jiakai Zhang693854b2022-11-02 17:33:28 +0000597 // 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;
Martijn Coenen5588e492021-02-25 14:33:44 +0100601 Result<std::map<std::string, std::string>> digests;
602 if (supportsFsVerity) {
Victor Hsiehf2ac7c62022-11-17 16:58:10 -0800603 digests = addFilesToVerityRecursive(kArtArtifactsDir);
Martijn Coenen5588e492021-02-25 14:33:44 +0100604 } 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()) {
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100610 LOG(ERROR) << digests.error();
Jiakai Zhang693854b2022-11-02 17:33:28 +0000611 odsign_record->status =
612 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_SIGNING_FAILED;
Martijn Coenen5588e492021-02-25 14:33:44 +0100613 return -1;
614 }
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100615 auto persistStatus = persistDigests(*digests, *key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100616 if (!persistStatus.ok()) {
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100617 LOG(ERROR) << persistStatus.error();
Jiakai Zhang693854b2022-11-02 17:33:28 +0000618 odsign_record->status =
619 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_SIGNING_FAILED;
Martijn Coenen95194842020-09-24 16:56:46 +0200620 return -1;
621 }
Orion Hodson2f7807b2021-03-22 17:07:03 +0000622 } else if (odrefresh_status == art::odrefresh::ExitCode::kCleanupFailed) {
623 LOG(ERROR) << "odrefresh failed cleaning up existing artifacts";
Jiakai Zhang693854b2022-11-02 17:33:28 +0000624 odsign_record->status =
625 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ODREFRESH_FAILED;
Orion Hodson2f7807b2021-03-22 17:07:03 +0000626 return -1;
627 } else {
628 LOG(ERROR) << "odrefresh exited unexpectedly, returned " << odrefresh_status;
Jiakai Zhang693854b2022-11-02 17:33:28 +0000629 odsign_record->status =
630 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ODREFRESH_FAILED;
Orion Hodson2f7807b2021-03-22 17:07:03 +0000631 return -1;
Martijn Coenen95194842020-09-24 16:56:46 +0200632 }
633
Martijn Coenen95194842020-09-24 16:56:46 +0200634 LOG(INFO) << "On-device signing done.";
635
636 scope_guard.Disable();
Jiakai Zhang693854b2022-11-02 17:33:28 +0000637
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
Martijn Coenen688244f2021-03-15 13:43:45 +0100644 // At this point, we're done with the key for sure
645 SetProperty(kOdsignKeyDoneProp, "1");
646 // And we did a successful verification
Martijn Coenen688244f2021-03-15 13:43:45 +0100647 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusValid);
Martijn Coenen2e8a9842021-07-27 13:40:23 +0200648 SetProperty(kOdsignVerificationDoneProp, "1");
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100649
Martijn Coenen2e8a9842021-07-27 13:40:23 +0200650 // Tell init it shouldn't try to restart us - see odsign.rc
651 SetProperty(kStopServiceProp, "odsign");
Martijn Coenen95194842020-09-24 16:56:46 +0200652 return 0;
653}