blob: df27815d451358a98736b9edb8b04a30188fb239 [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>
32
33#include "CertUtils.h"
34#include "KeymasterSigningKey.h"
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010035#include "KeystoreKey.h"
Martijn Coenen95194842020-09-24 16:56:46 +020036#include "VerityUtils.h"
37
Martijn Coenen5588e492021-02-25 14:33:44 +010038#include "odsign_info.pb.h"
39
Martijn Coenen95194842020-09-24 16:56:46 +020040using android::base::ErrnoError;
41using android::base::Error;
42using android::base::Result;
Martijn Coenen688244f2021-03-15 13:43:45 +010043using android::base::SetProperty;
Martijn Coenen95194842020-09-24 16:56:46 +020044
Martijn Coenen5588e492021-02-25 14:33:44 +010045using OdsignInfo = ::odsign::proto::OdsignInfo;
46
Martijn Coenen95194842020-09-24 16:56:46 +020047const std::string kSigningKeyBlob = "/data/misc/odsign/key.blob";
48const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
Martijn Coenen5588e492021-02-25 14:33:44 +010049const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
50const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
Martijn Coenen95194842020-09-24 16:56:46 +020051
Martijn Coenenb6afe132021-02-19 09:32:48 +010052const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
Martijn Coenen95194842020-09-24 16:56:46 +020053
54static const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
55
Martijn Coenen5588e492021-02-25 14:33:44 +010056static const char* kFsVerityProcPath = "/proc/sys/fs/verity";
Martijn Coenen95194842020-09-24 16:56:46 +020057
58static const bool kForceCompilation = false;
Martijn Coenen0f6cea72021-03-19 11:31:24 +010059static const bool kUseKeystore = true;
Martijn Coenen95194842020-09-24 16:56:46 +020060
Martijn Coenen688244f2021-03-15 13:43:45 +010061static const char* kOdsignVerificationDoneProp = "odsign.verification.done";
62static const char* kOdsignKeyDoneProp = "odsign.key.done";
63
64static const char* kOdsignVerificationStatusProp = "odsign.verification.success";
65static const char* kOdsignVerificationStatusValid = "1";
66static const char* kOdsignVerificationStatusError = "0";
67
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010068Result<void> verifyExistingCert(const SigningKey& key) {
Martijn Coenen95194842020-09-24 16:56:46 +020069 if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
70 return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
71 }
72 auto trustedPublicKey = key.getPublicKey();
73 if (!trustedPublicKey.ok()) {
74 return Error() << "Failed to retrieve signing public key.";
75 }
76
77 auto publicKeyFromExistingCert = extractPublicKeyFromX509(kSigningKeyCert);
78 if (!publicKeyFromExistingCert.ok()) {
79 return publicKeyFromExistingCert.error();
80 }
81 if (publicKeyFromExistingCert.value() != trustedPublicKey.value()) {
82 return Error() << "Public key of existing certificate at " << kSigningKeyCert
83 << " does not match signing public key.";
84 }
85
Martijn Coenen95194842020-09-24 16:56:46 +020086 // At this point, we know the cert matches
87 return {};
88}
89
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010090Result<void> createX509Cert(const SigningKey& key, const std::string& outPath) {
91 auto publicKey = key.getPublicKey();
Martijn Coenen95194842020-09-24 16:56:46 +020092
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010093 if (!publicKey.ok()) {
94 return publicKey.error();
Martijn Coenen95194842020-09-24 16:56:46 +020095 }
96
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010097 auto keymasterSignFunction = [&](const std::string& to_be_signed) {
98 return key.sign(to_be_signed);
99 };
100 createSelfSignedCertificate(*publicKey, keymasterSignFunction, outPath);
101 return {};
Martijn Coenen95194842020-09-24 16:56:46 +0200102}
103
104bool compileArtifacts(bool force) {
105 const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
106
107 return logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr) ==
108 0;
109}
110
111bool validateArtifacts() {
112 const char* const argv[] = {kOdrefreshPath, "--check"};
113
114 return logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr) ==
115 0;
116}
117
Martijn Coenen5588e492021-02-25 14:33:44 +0100118static std::string toHex(const std::vector<uint8_t>& digest) {
119 std::stringstream ss;
120 for (auto it = digest.begin(); it != digest.end(); ++it) {
121 ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned>(*it);
122 }
123 return ss.str();
124}
125
126Result<std::map<std::string, std::string>> computeDigests(const std::string& path) {
127 std::error_code ec;
128 std::map<std::string, std::string> digests;
129
130 auto it = std::filesystem::recursive_directory_iterator(path, ec);
131 auto end = std::filesystem::recursive_directory_iterator();
132
133 while (!ec && it != end) {
134 if (it->is_regular_file()) {
135 auto digest = createDigest(it->path());
136 if (!digest.ok()) {
137 return Error() << "Failed to compute digest for " << it->path();
138 }
139 digests[it->path()] = toHex(*digest);
140 }
141 ++it;
142 }
143 if (ec) {
144 return Error() << "Failed to iterate " << path << ": " << ec;
145 }
146
147 return digests;
148}
149
150Result<void> verifyDigests(const std::map<std::string, std::string>& digests,
151 const std::map<std::string, std::string>& trusted_digests) {
152 for (const auto& path_digest : digests) {
153 auto path = path_digest.first;
154 auto digest = path_digest.second;
155 if ((trusted_digests.count(path) == 0)) {
156 return Error() << "Couldn't find digest for " << path;
157 }
158 if (trusted_digests.at(path) != digest) {
159 return Error() << "Digest mismatch for " << path;
160 }
161 }
162
163 // All digests matched!
164 if (digests.size() > 0) {
165 LOG(INFO) << "All root hashes match.";
166 }
167 return {};
168}
169
170Result<void> verifyIntegrityFsVerity(const std::map<std::string, std::string>& trusted_digests) {
171 // Just verify that the files are in verity, and get their digests
172 auto result = verifyAllFilesInVerity(kArtArtifactsDir);
173 if (!result.ok()) {
174 return result.error();
175 }
176
177 return verifyDigests(*result, trusted_digests);
178}
179
180Result<void> verifyIntegrityNoFsVerity(const std::map<std::string, std::string>& trusted_digests) {
181 // On these devices, just compute the digests, and verify they match the ones we trust
182 auto result = computeDigests(kArtArtifactsDir);
183 if (!result.ok()) {
184 return result.error();
185 }
186
187 return verifyDigests(*result, trusted_digests);
188}
189
Martijn Coenendc05bb32021-03-08 10:52:48 +0100190Result<OdsignInfo> getOdsignInfo(const SigningKey& key) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100191 std::string persistedSignature;
192 OdsignInfo odsignInfo;
193
194 if (!android::base::ReadFileToString(kOdsignInfoSignature, &persistedSignature)) {
195 return ErrnoError() << "Failed to read " << kOdsignInfoSignature;
196 }
197
198 std::fstream odsign_info(kOdsignInfo, std::ios::in | std::ios::binary);
199 if (!odsign_info) {
200 return Error() << "Failed to open " << kOdsignInfo;
201 }
Martijn Coenendc05bb32021-03-08 10:52:48 +0100202 odsign_info.seekg(0);
Martijn Coenen5588e492021-02-25 14:33:44 +0100203 // Verify the hash
204 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
205 std::istreambuf_iterator<char>());
206
Martijn Coenendc05bb32021-03-08 10:52:48 +0100207 auto publicKey = key.getPublicKey();
208 auto signResult = verifySignature(odsign_info_str, persistedSignature, *publicKey);
209 if (!signResult.ok()) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100210 return Error() << kOdsignInfoSignature << " does not match.";
211 } else {
212 LOG(INFO) << kOdsignInfoSignature << " matches.";
213 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100214
Martijn Coenendc05bb32021-03-08 10:52:48 +0100215 odsign_info.seekg(0);
Martijn Coenen5588e492021-02-25 14:33:44 +0100216 if (!odsignInfo.ParseFromIstream(&odsign_info)) {
217 return Error() << "Failed to parse " << kOdsignInfo;
218 }
219
220 LOG(INFO) << "Loaded " << kOdsignInfo;
221 return odsignInfo;
222}
223
224Result<void> persistDigests(const std::map<std::string, std::string>& digests,
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100225 const SigningKey& key) {
Martijn Coenen5588e492021-02-25 14:33:44 +0100226 OdsignInfo signInfo;
227 google::protobuf::Map<std::string, std::string> proto_hashes(digests.begin(), digests.end());
228 auto map = signInfo.mutable_file_hashes();
229 *map = proto_hashes;
230
Martijn Coenendc05bb32021-03-08 10:52:48 +0100231 std::fstream odsign_info(kOdsignInfo,
232 std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
Martijn Coenen5588e492021-02-25 14:33:44 +0100233 if (!signInfo.SerializeToOstream(&odsign_info)) {
234 return Error() << "Failed to persist root hashes in " << kOdsignInfo;
235 }
236
Martijn Coenendc05bb32021-03-08 10:52:48 +0100237 // Sign the signatures with our key itself, and write that to storage
238 odsign_info.seekg(0, std::ios::beg);
Martijn Coenen5588e492021-02-25 14:33:44 +0100239 std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
240 std::istreambuf_iterator<char>());
241 auto signResult = key.sign(odsign_info_str);
242 if (!signResult.ok()) {
243 return Error() << "Failed to sign " << kOdsignInfo;
244 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100245 android::base::WriteStringToFile(*signResult, kOdsignInfoSignature);
246 return {};
247}
248
Martijn Coenen688244f2021-03-15 13:43:45 +0100249static int removeArtifacts() {
250 std::error_code ec;
251 auto num_removed = std::filesystem::remove_all(kArtArtifactsDir, ec);
252 if (ec) {
253 LOG(ERROR) << "Can't remove " << kArtArtifactsDir << ": " << ec.message();
254 return 0;
255 } else {
256 if (num_removed > 0) {
257 LOG(INFO) << "Removed " << num_removed << " entries from " << kArtArtifactsDir;
Martijn Coenen95194842020-09-24 16:56:46 +0200258 }
Martijn Coenen688244f2021-03-15 13:43:45 +0100259 return num_removed;
260 }
261}
262
263static Result<void> verifyArtifacts(const SigningKey& key, bool supportsFsVerity) {
264 auto signInfo = getOdsignInfo(key);
265 // Tell init we're done with the key; this is a boot time optimization
266 // in particular for the no fs-verity case, where we need to do a
267 // costly verification. If the files haven't been tampered with, which
268 // should be the common path, the verification will succeed, and we won't
269 // need the key anymore. If it turns out the artifacts are invalid (eg not
270 // in fs-verity) or the hash doesn't match, we won't be able to generate
271 // new artifacts without the key, so in those cases, remove the artifacts,
272 // and use JIT zygote for the current boot. We should recover automatically
273 // by the next boot.
274 SetProperty(kOdsignKeyDoneProp, "1");
275 if (!signInfo.ok()) {
276 return Error() << signInfo.error().message();
277 }
278 std::map<std::string, std::string> trusted_digests(signInfo->file_hashes().begin(),
279 signInfo->file_hashes().end());
280 Result<void> integrityStatus;
281
282 if (supportsFsVerity) {
283 integrityStatus = verifyIntegrityFsVerity(trusted_digests);
284 } else {
285 integrityStatus = verifyIntegrityNoFsVerity(trusted_digests);
286 }
287 if (!integrityStatus.ok()) {
288 return Error() << integrityStatus.error().message();
289 }
290
291 return {};
292}
293
294int main(int /* argc */, char** /* argv */) {
295 auto errorScopeGuard = []() {
296 // In case we hit any error, remove the artifacts and tell Zygote not to use anything
297 removeArtifacts();
298 // Tell init we don't need to use our key anymore
299 SetProperty(kOdsignKeyDoneProp, "1");
300 // Tell init we're done with verification, and that it was an error
301 SetProperty(kOdsignVerificationDoneProp, "1");
302 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusError);
Martijn Coenen95194842020-09-24 16:56:46 +0200303 };
Martijn Coenen688244f2021-03-15 13:43:45 +0100304 auto scope_guard = android::base::make_scope_guard(errorScopeGuard);
Martijn Coenen95194842020-09-24 16:56:46 +0200305
Martijn Coenene9e9b702021-03-23 17:30:46 +0100306 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
307 LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
308 return 0;
309 }
310
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100311 SigningKey* key;
312 if (kUseKeystore) {
313 auto keystoreResult = KeystoreKey::getInstance();
314 if (!keystoreResult.ok()) {
315 LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error().message();
Martijn Coenen95194842020-09-24 16:56:46 +0200316 return -1;
317 }
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100318 key = keystoreResult.value();
Martijn Coenen95194842020-09-24 16:56:46 +0200319 } else {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100320 // TODO - keymaster will go away
321 auto keymasterResult = KeymasterSigningKey::getInstance();
322 if (!keymasterResult.ok()) {
323 LOG(ERROR) << "Failed to create keymaster key: " << keymasterResult.error().message();
324 return -1;
325 }
326 key = keymasterResult.value();
Martijn Coenen95194842020-09-24 16:56:46 +0200327 }
328
Martijn Coenen5588e492021-02-25 14:33:44 +0100329 bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
330 if (!supportsFsVerity) {
331 LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
332 }
Martijn Coenen95194842020-09-24 16:56:46 +0200333
Martijn Coenen5588e492021-02-25 14:33:44 +0100334 if (supportsFsVerity) {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100335 auto existing_cert = verifyExistingCert(*key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100336 if (!existing_cert.ok()) {
337 LOG(WARNING) << existing_cert.error().message();
338
339 // Try to create a new cert
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100340 auto new_cert = createX509Cert(*key, kSigningKeyCert);
Martijn Coenen5588e492021-02-25 14:33:44 +0100341 if (!new_cert.ok()) {
342 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error().message();
343 // TODO apparently the key become invalid - delete the blob / cert
344 return -1;
345 }
346 } else {
347 LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
348 }
349 auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert);
350 if (!cert_add_result.ok()) {
351 LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
352 << cert_add_result.error().message();
Martijn Coenen95194842020-09-24 16:56:46 +0200353 return -1;
354 }
Martijn Coenen5588e492021-02-25 14:33:44 +0100355 }
356
Martijn Coenen5588e492021-02-25 14:33:44 +0100357 // Ask ART whether it considers the artifacts valid
358 LOG(INFO) << "Asking odrefresh to verify artifacts (if present)...";
Martijn Coenen95194842020-09-24 16:56:46 +0200359 bool artifactsValid = validateArtifacts();
Martijn Coenen5588e492021-02-25 14:33:44 +0100360 LOG(INFO) << "odrefresh said they are " << (artifactsValid ? "VALID" : "INVALID");
Martijn Coenen95194842020-09-24 16:56:46 +0200361
Martijn Coenen688244f2021-03-15 13:43:45 +0100362 // A post-condition of validating artifacts is that if the ones on /system
363 // are used, kArtArtifactsDir is removed. Conversely, if kArtArtifactsDir
364 // exists, those are artifacts that will be used, and we should verify them.
365 int err = access(kArtArtifactsDir.c_str(), F_OK);
366 // If we receive any error other than ENOENT, be suspicious
367 bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
368 if (artifactsPresent) {
369 auto verificationResult = verifyArtifacts(*key, supportsFsVerity);
370 if (!verificationResult.ok()) {
371 LOG(ERROR) << verificationResult.error().message();
372 return -1;
373 }
374 }
375
Martijn Coenen95194842020-09-24 16:56:46 +0200376 if (!artifactsValid || kForceCompilation) {
Martijn Coenen95194842020-09-24 16:56:46 +0200377 LOG(INFO) << "Starting compilation... ";
378 bool ret = compileArtifacts(kForceCompilation);
379 LOG(INFO) << "Compilation done, returned " << ret;
380
Martijn Coenen5588e492021-02-25 14:33:44 +0100381 Result<std::map<std::string, std::string>> digests;
382 if (supportsFsVerity) {
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100383 digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100384 } else {
385 // If we can't use verity, just compute the root hashes and store
386 // those, so we can reverify them at the next boot.
387 digests = computeDigests(kArtArtifactsDir);
388 }
389 if (!digests.ok()) {
390 LOG(ERROR) << digests.error().message();
391 return -1;
392 }
Martijn Coenen95194842020-09-24 16:56:46 +0200393
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100394 auto persistStatus = persistDigests(*digests, *key);
Martijn Coenen5588e492021-02-25 14:33:44 +0100395 if (!persistStatus.ok()) {
396 LOG(ERROR) << persistStatus.error().message();
Martijn Coenen95194842020-09-24 16:56:46 +0200397 return -1;
398 }
399 }
400
Martijn Coenen95194842020-09-24 16:56:46 +0200401 LOG(INFO) << "On-device signing done.";
402
403 scope_guard.Disable();
Martijn Coenen688244f2021-03-15 13:43:45 +0100404 // At this point, we're done with the key for sure
405 SetProperty(kOdsignKeyDoneProp, "1");
406 // And we did a successful verification
407 SetProperty(kOdsignVerificationDoneProp, "1");
408 SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusValid);
Martijn Coenen95194842020-09-24 16:56:46 +0200409 return 0;
410}