blob: 6cab8b6aa6789e00b8d3a81e6c8ad8312ef8edb4 [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"
35#include "KeymasterSigningKey.h"
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010036#include "KeystoreKey.h"
Martijn Coenen95194842020-09-24 16:56:46 +020037#include "VerityUtils.h"
38
Martijn Coenen5588e492021-02-25 14:33:44 +010039#include "odsign_info.pb.h"
40
Martijn Coenen95194842020-09-24 16:56:46 +020041using android::base::ErrnoError;
42using android::base::Error;
43using android::base::Result;
Martijn Coenen688244f2021-03-15 13:43:45 +010044using android::base::SetProperty;
Martijn Coenen95194842020-09-24 16:56:46 +020045
Martijn Coenen5588e492021-02-25 14:33:44 +010046using OdsignInfo = ::odsign::proto::OdsignInfo;
47
Martijn Coenen95194842020-09-24 16:56:46 +020048const std::string kSigningKeyBlob = "/data/misc/odsign/key.blob";
49const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
Martijn Coenen5588e492021-02-25 14:33:44 +010050const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
51const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
Martijn Coenen95194842020-09-24 16:56:46 +020052
Martijn Coenenb6afe132021-02-19 09:32:48 +010053const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
Martijn Coenen95194842020-09-24 16:56:46 +020054
55static const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
56
Martijn Coenen5588e492021-02-25 14:33:44 +010057static const char* kFsVerityProcPath = "/proc/sys/fs/verity";
Martijn Coenen95194842020-09-24 16:56:46 +020058
59static const bool kForceCompilation = false;
Martijn Coenen0f6cea72021-03-19 11:31:24 +010060static const bool kUseKeystore = true;
Martijn Coenen95194842020-09-24 16:56:46 +020061
Martijn Coenen688244f2021-03-15 13:43:45 +010062static const char* kOdsignVerificationDoneProp = "odsign.verification.done";
63static const char* kOdsignKeyDoneProp = "odsign.key.done";
64
65static const char* kOdsignVerificationStatusProp = "odsign.verification.success";
66static const char* kOdsignVerificationStatusValid = "1";
67static const char* kOdsignVerificationStatusError = "0";
68
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010069Result<void> verifyExistingCert(const SigningKey& key) {
Martijn Coenen95194842020-09-24 16:56:46 +020070 if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
71 return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
72 }
73 auto trustedPublicKey = key.getPublicKey();
74 if (!trustedPublicKey.ok()) {
75 return Error() << "Failed to retrieve signing public key.";
76 }
77
78 auto publicKeyFromExistingCert = extractPublicKeyFromX509(kSigningKeyCert);
79 if (!publicKeyFromExistingCert.ok()) {
80 return publicKeyFromExistingCert.error();
81 }
82 if (publicKeyFromExistingCert.value() != trustedPublicKey.value()) {
83 return Error() << "Public key of existing certificate at " << kSigningKeyCert
84 << " does not match signing public key.";
85 }
86
Martijn Coenen95194842020-09-24 16:56:46 +020087 // At this point, we know the cert matches
88 return {};
89}
90
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010091Result<void> createX509Cert(const SigningKey& key, const std::string& outPath) {
92 auto publicKey = key.getPublicKey();
Martijn Coenen95194842020-09-24 16:56:46 +020093
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010094 if (!publicKey.ok()) {
95 return publicKey.error();
Martijn Coenen95194842020-09-24 16:56:46 +020096 }
97
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010098 auto keymasterSignFunction = [&](const std::string& to_be_signed) {
99 return key.sign(to_be_signed);
100 };
101 createSelfSignedCertificate(*publicKey, keymasterSignFunction, outPath);
102 return {};
Martijn Coenen95194842020-09-24 16:56:46 +0200103}
104
Orion Hodson2f7807b2021-03-22 17:07:03 +0000105art::odrefresh::ExitCode compileArtifacts(bool force) {
Martijn Coenen95194842020-09-24 16:56:46 +0200106 const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
Orion Hodson2f7807b2021-03-22 17:07:03 +0000107 const int exit_code =
108 logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
109 return static_cast<art::odrefresh::ExitCode>(exit_code);
Martijn Coenen95194842020-09-24 16:56:46 +0200110}
111
Martijn Coenen5588e492021-02-25 14:33:44 +0100112static std::string toHex(const std::vector<uint8_t>& digest) {
113 std::stringstream ss;
114 for (auto it = digest.begin(); it != digest.end(); ++it) {
115 ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned>(*it);
116 }
117 return ss.str();
118}
119
120Result<std::map<std::string, std::string>> computeDigests(const std::string& path) {
121 std::error_code ec;
122 std::map<std::string, std::string> digests;
123
124 auto it = std::filesystem::recursive_directory_iterator(path, ec);
125 auto end = std::filesystem::recursive_directory_iterator();
126
127 while (!ec && it != end) {
128 if (it->is_regular_file()) {
129 auto digest = createDigest(it->path());
130 if (!digest.ok()) {
131 return Error() << "Failed to compute digest for " << it->path();
132 }
133 digests[it->path()] = toHex(*digest);
134 }
135 ++it;
136 }
137 if (ec) {
138 return Error() << "Failed to iterate " << path << ": " << ec;
139 }
140
141 return digests;
142}
143
144Result<void> verifyDigests(const std::map<std::string, std::string>& digests,
145 const std::map<std::string, std::string>& trusted_digests) {
146 for (const auto& path_digest : digests) {
147 auto path = path_digest.first;
148 auto digest = path_digest.second;
149 if ((trusted_digests.count(path) == 0)) {
150 return Error() << "Couldn't find digest for " << path;
151 }
152 if (trusted_digests.at(path) != digest) {
153 return Error() << "Digest mismatch for " << path;
154 }
155 }
156
157 // All digests matched!
158 if (digests.size() > 0) {
159 LOG(INFO) << "All root hashes match.";
160 }
161 return {};
162}
163
164Result<void> verifyIntegrityFsVerity(const std::map<std::string, std::string>& trusted_digests) {
165 // Just verify that the files are in verity, and get their digests
166 auto result = verifyAllFilesInVerity(kArtArtifactsDir);
167 if (!result.ok()) {
168 return result.error();
169 }
170
171 return verifyDigests(*result, trusted_digests);
172}
173
174Result<void> verifyIntegrityNoFsVerity(const std::map<std::string, std::string>& trusted_digests) {
175 // On these devices, just compute the digests, and verify they match the ones we trust
176 auto result = computeDigests(kArtArtifactsDir);
177 if (!result.ok()) {
178 return result.error();
179 }
180
181 return verifyDigests(*result, trusted_digests);
182}
183
Martijn Coenendc05bb32021-03-08 10:52:48 +0100184Result<OdsignInfo> getOdsignInfo(const SigningKey& key) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100185 std::string persistedSignature;
186 OdsignInfo odsignInfo;
187
188 if (!android::base::ReadFileToString(kOdsignInfoSignature, &persistedSignature)) {
189 return ErrnoError() << "Failed to read " << kOdsignInfoSignature;
190 }
191
192 std::fstream odsign_info(kOdsignInfo, std::ios::in | std::ios::binary);
193 if (!odsign_info) {
194 return Error() << "Failed to open " << kOdsignInfo;
195 }
Martijn Coenendc05bb32021-03-08 10:52:48 +0100196 odsign_info.seekg(0);
Martijn Coenen5588e492021-02-25 14:33:44 +0100197 // Verify the hash
198 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
199 std::istreambuf_iterator<char>());
200
Martijn Coenendc05bb32021-03-08 10:52:48 +0100201 auto publicKey = key.getPublicKey();
202 auto signResult = verifySignature(odsign_info_str, persistedSignature, *publicKey);
203 if (!signResult.ok()) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100204 return Error() << kOdsignInfoSignature << " does not match.";
205 } else {
206 LOG(INFO) << kOdsignInfoSignature << " matches.";
207 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100208
Martijn Coenendc05bb32021-03-08 10:52:48 +0100209 odsign_info.seekg(0);
Martijn Coenen5588e492021-02-25 14:33:44 +0100210 if (!odsignInfo.ParseFromIstream(&odsign_info)) {
211 return Error() << "Failed to parse " << kOdsignInfo;
212 }
213
214 LOG(INFO) << "Loaded " << kOdsignInfo;
215 return odsignInfo;
216}
217
218Result<void> persistDigests(const std::map<std::string, std::string>& digests,
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100219 const SigningKey& key) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100220 OdsignInfo signInfo;
221 google::protobuf::Map<std::string, std::string> proto_hashes(digests.begin(), digests.end());
222 auto map = signInfo.mutable_file_hashes();
223 *map = proto_hashes;
224
Martijn Coenendc05bb32021-03-08 10:52:48 +0100225 std::fstream odsign_info(kOdsignInfo,
226 std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
Martijn Coenen5588e492021-02-25 14:33:44 +0100227 if (!signInfo.SerializeToOstream(&odsign_info)) {
228 return Error() << "Failed to persist root hashes in " << kOdsignInfo;
229 }
230
Martijn Coenendc05bb32021-03-08 10:52:48 +0100231 // Sign the signatures with our key itself, and write that to storage
232 odsign_info.seekg(0, std::ios::beg);
Martijn Coenen5588e492021-02-25 14:33:44 +0100233 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
234 std::istreambuf_iterator<char>());
235 auto signResult = key.sign(odsign_info_str);
236 if (!signResult.ok()) {
237 return Error() << "Failed to sign " << kOdsignInfo;
238 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100239 android::base::WriteStringToFile(*signResult, kOdsignInfoSignature);
240 return {};
241}
242
Martijn Coenen688244f2021-03-15 13:43:45 +0100243static int removeArtifacts() {
244 std::error_code ec;
245 auto num_removed = std::filesystem::remove_all(kArtArtifactsDir, ec);
246 if (ec) {
247 LOG(ERROR) << "Can't remove " << kArtArtifactsDir << ": " << ec.message();
248 return 0;
249 } else {
250 if (num_removed > 0) {
251 LOG(INFO) << "Removed " << num_removed << " entries from " << kArtArtifactsDir;
Martijn Coenen95194842020-09-24 16:56:46 +0200252 }
Martijn Coenen688244f2021-03-15 13:43:45 +0100253 return num_removed;
254 }
255}
256
257static Result<void> verifyArtifacts(const SigningKey& key, bool supportsFsVerity) {
258 auto signInfo = getOdsignInfo(key);
259 // Tell init we're done with the key; this is a boot time optimization
260 // in particular for the no fs-verity case, where we need to do a
261 // costly verification. If the files haven't been tampered with, which
262 // should be the common path, the verification will succeed, and we won't
263 // need the key anymore. If it turns out the artifacts are invalid (eg not
264 // in fs-verity) or the hash doesn't match, we won't be able to generate
265 // new artifacts without the key, so in those cases, remove the artifacts,
266 // and use JIT zygote for the current boot. We should recover automatically
267 // by the next boot.
268 SetProperty(kOdsignKeyDoneProp, "1");
269 if (!signInfo.ok()) {
270 return Error() << signInfo.error().message();
271 }
272 std::map<std::string, std::string> trusted_digests(signInfo->file_hashes().begin(),
273 signInfo->file_hashes().end());
274 Result<void> integrityStatus;
275
276 if (supportsFsVerity) {
277 integrityStatus = verifyIntegrityFsVerity(trusted_digests);
278 } else {
279 integrityStatus = verifyIntegrityNoFsVerity(trusted_digests);
280 }
281 if (!integrityStatus.ok()) {
282 return Error() << integrityStatus.error().message();
283 }
284
285 return {};
286}
287
288int main(int /* argc */, char** /* argv */) {
289 auto errorScopeGuard = []() {
290 // In case we hit any error, remove the artifacts and tell Zygote not to use anything
291 removeArtifacts();
292 // Tell init we don't need to use our key anymore
293 SetProperty(kOdsignKeyDoneProp, "1");
294 // Tell init we're done with verification, and that it was an error
295 SetProperty(kOdsignVerificationDoneProp, "1");
296 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusError);
Martijn Coenen95194842020-09-24 16:56:46 +0200297 };
Martijn Coenen688244f2021-03-15 13:43:45 +0100298 auto scope_guard = android::base::make_scope_guard(errorScopeGuard);
Martijn Coenen95194842020-09-24 16:56:46 +0200299
Martijn Coenene9e9b702021-03-23 17:30:46 +0100300 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
301 LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
302 return 0;
303 }
304
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100305 SigningKey* key;
306 if (kUseKeystore) {
307 auto keystoreResult = KeystoreKey::getInstance();
308 if (!keystoreResult.ok()) {
309 LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error().message();
Martijn Coenen95194842020-09-24 16:56:46 +0200310 return -1;
311 }
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100312 key = keystoreResult.value();
Martijn Coenen95194842020-09-24 16:56:46 +0200313 } else {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100314 // TODO - keymaster will go away
315 auto keymasterResult = KeymasterSigningKey::getInstance();
316 if (!keymasterResult.ok()) {
317 LOG(ERROR) << "Failed to create keymaster key: " << keymasterResult.error().message();
318 return -1;
319 }
320 key = keymasterResult.value();
Martijn Coenen95194842020-09-24 16:56:46 +0200321 }
322
Martijn Coenen5588e492021-02-25 14:33:44 +0100323 bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
324 if (!supportsFsVerity) {
325 LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
326 }
Martijn Coenen95194842020-09-24 16:56:46 +0200327
Martijn Coenen5588e492021-02-25 14:33:44 +0100328 if (supportsFsVerity) {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100329 auto existing_cert = verifyExistingCert(*key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100330 if (!existing_cert.ok()) {
331 LOG(WARNING) << existing_cert.error().message();
332
333 // Try to create a new cert
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100334 auto new_cert = createX509Cert(*key, kSigningKeyCert);
Martijn Coenen5588e492021-02-25 14:33:44 +0100335 if (!new_cert.ok()) {
336 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error().message();
337 // TODO apparently the key become invalid - delete the blob / cert
338 return -1;
339 }
340 } else {
341 LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
342 }
343 auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert);
344 if (!cert_add_result.ok()) {
345 LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
346 << cert_add_result.error().message();
Martijn Coenen95194842020-09-24 16:56:46 +0200347 return -1;
348 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100349 }
350
Orion Hodson2f7807b2021-03-22 17:07:03 +0000351 art::odrefresh::ExitCode odrefresh_status = compileArtifacts(kForceCompilation);
352 if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
353 LOG(INFO) << "odrefresh said artifacts are VALID";
354 // A post-condition of validating artifacts is that if the ones on /system
355 // are used, kArtArtifactsDir is removed. Conversely, if kArtArtifactsDir
356 // exists, those are artifacts that will be used, and we should verify them.
357 int err = access(kArtArtifactsDir.c_str(), F_OK);
358 // If we receive any error other than ENOENT, be suspicious
359 bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
360 if (artifactsPresent) {
361 auto verificationResult = verifyArtifacts(*key, supportsFsVerity);
362 if (!verificationResult.ok()) {
363 LOG(ERROR) << verificationResult.error().message();
364 return -1;
365 }
Martijn Coenen688244f2021-03-15 13:43:45 +0100366 }
Orion Hodson2f7807b2021-03-22 17:07:03 +0000367 } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
368 odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
369 const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;
370 LOG(INFO) << "odrefresh compiled " << (compiled_all ? "all" : "partial")
371 << " artifacts, returned " << odrefresh_status;
Martijn Coenen5588e492021-02-25 14:33:44 +0100372 Result<std::map<std::string, std::string>> digests;
373 if (supportsFsVerity) {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100374 digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100375 } else {
376 // If we can't use verity, just compute the root hashes and store
377 // those, so we can reverify them at the next boot.
378 digests = computeDigests(kArtArtifactsDir);
379 }
380 if (!digests.ok()) {
381 LOG(ERROR) << digests.error().message();
382 return -1;
383 }
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100384 auto persistStatus = persistDigests(*digests, *key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100385 if (!persistStatus.ok()) {
386 LOG(ERROR) << persistStatus.error().message();
Martijn Coenen95194842020-09-24 16:56:46 +0200387 return -1;
388 }
Orion Hodson2f7807b2021-03-22 17:07:03 +0000389 } else if (odrefresh_status == art::odrefresh::ExitCode::kCleanupFailed) {
390 LOG(ERROR) << "odrefresh failed cleaning up existing artifacts";
391 return -1;
392 } else {
393 LOG(ERROR) << "odrefresh exited unexpectedly, returned " << odrefresh_status;
394 return -1;
Martijn Coenen95194842020-09-24 16:56:46 +0200395 }
396
Martijn Coenen95194842020-09-24 16:56:46 +0200397 LOG(INFO) << "On-device signing done.";
398
399 scope_guard.Disable();
Martijn Coenen688244f2021-03-15 13:43:45 +0100400 // At this point, we're done with the key for sure
401 SetProperty(kOdsignKeyDoneProp, "1");
402 // And we did a successful verification
403 SetProperty(kOdsignVerificationDoneProp, "1");
404 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusValid);
Martijn Coenen95194842020-09-24 16:56:46 +0200405 return 0;
406}