blob: b019bb9b054d94c343ce799e50250288e04d05b8 [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>
19#include <iomanip>
20#include <iostream>
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <sys/wait.h>
24#include <unistd.h>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <android-base/scopeguard.h>
29#include <logwrap/logwrap.h>
30
31#include "CertUtils.h"
32#include "KeymasterSigningKey.h"
33#include "VerityUtils.h"
34
35using android::base::ErrnoError;
36using android::base::Error;
37using android::base::Result;
38
39const std::string kSigningKeyBlob = "/data/misc/odsign/key.blob";
40const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
41
Martijn Coenenb6afe132021-02-19 09:32:48 +010042const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
Martijn Coenen95194842020-09-24 16:56:46 +020043
44static const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
45
46static const char* kFsVerityInitPath = "/system/bin/fsverity_init";
47
48static const bool kForceCompilation = false;
49
50Result<void> addCertToFsVerityKeyring(const std::string& path) {
51 const char* const argv[] = {kFsVerityInitPath, "--load-extra-key", "fsv_ods"};
52
53 int fd = open(path.c_str(), O_RDONLY);
54 pid_t pid = fork();
55 if (pid == 0) {
56 dup2(fd, STDIN_FILENO);
57 close(fd);
58 int argc = arraysize(argv);
59 char* argv_child[argc + 1];
60 memcpy(argv_child, argv, argc * sizeof(char*));
61 argv_child[argc] = nullptr;
62 execvp(argv_child[0], const_cast<char**>(argv_child));
63 PLOG(ERROR) << "exec in ForkExecvp";
64 _exit(EXIT_FAILURE);
65 } else {
66 close(fd);
67 }
68 if (pid == -1) {
69 return ErrnoError() << "Failed to fork.";
70 }
71 int status;
72 if (waitpid(pid, &status, 0) == -1) {
73 return ErrnoError() << "waitpid() failed.";
74 }
75 if (!WIFEXITED(status)) {
76 return Error() << kFsVerityInitPath << ": abnormal process exit";
77 }
78 if (WEXITSTATUS(status)) {
79 if (status != 0) {
80 return Error() << kFsVerityInitPath << " exited with " << status;
81 }
82 }
83
84 return {};
85}
86
87Result<KeymasterSigningKey> loadAndVerifyExistingKey() {
88 if (access(kSigningKeyBlob.c_str(), F_OK) < 0) {
89 return ErrnoError() << "Key blob not found: " << kSigningKeyBlob;
90 }
91 return KeymasterSigningKey::loadFromBlobAndVerify(kSigningKeyBlob);
92}
93
Martijn Coenen799ce6e2021-02-23 10:14:41 +010094Result<void> verifyExistingCert(const KeymasterSigningKey& key) {
Martijn Coenen95194842020-09-24 16:56:46 +020095 if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
96 return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
97 }
98 auto trustedPublicKey = key.getPublicKey();
99 if (!trustedPublicKey.ok()) {
100 return Error() << "Failed to retrieve signing public key.";
101 }
102
103 auto publicKeyFromExistingCert = extractPublicKeyFromX509(kSigningKeyCert);
104 if (!publicKeyFromExistingCert.ok()) {
105 return publicKeyFromExistingCert.error();
106 }
107 if (publicKeyFromExistingCert.value() != trustedPublicKey.value()) {
108 return Error() << "Public key of existing certificate at " << kSigningKeyCert
109 << " does not match signing public key.";
110 }
111
Martijn Coenen95194842020-09-24 16:56:46 +0200112 // At this point, we know the cert matches
113 return {};
114}
115
116Result<KeymasterSigningKey> createAndPersistKey(const std::string& path) {
117 auto key = KeymasterSigningKey::createNewKey();
118
119 if (!key.ok()) {
120 return key.error();
121 }
122
123 auto result = key->saveKeyblob(path);
124 if (!result.ok()) {
125 return result.error();
126 }
127
128 return key;
129}
130
131bool compileArtifacts(bool force) {
132 const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
133
134 return logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr) ==
135 0;
136}
137
138bool validateArtifacts() {
139 const char* const argv[] = {kOdrefreshPath, "--check"};
140
141 return logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr) ==
142 0;
143}
144
145int main(int /* argc */, char** /* argv */) {
146 auto removeArtifacts = []() {
147 std::error_code ec;
148 auto num_removed = std::filesystem::remove_all(kArtArtifactsDir, ec);
149 if (ec) {
150 // TODO can't remove artifacts, signal Zygote shouldn't use them
151 LOG(ERROR) << "Can't remove " << kArtArtifactsDir << ": " << ec.message();
152 } else {
153 LOG(INFO) << "Removed " << num_removed << " entries from " << kArtArtifactsDir;
154 }
155 };
156 // Make sure we delete the artifacts in all early (error) exit paths
157 auto scope_guard = android::base::make_scope_guard(removeArtifacts);
158
159 auto key = loadAndVerifyExistingKey();
160 if (!key.ok()) {
161 LOG(WARNING) << key.error().message();
162
163 key = createAndPersistKey(kSigningKeyBlob);
164 if (!key.ok()) {
165 LOG(ERROR) << "Failed to create or persist new key: " << key.error().message();
166 return -1;
167 }
168 } else {
169 LOG(INFO) << "Found and verified existing key: " << kSigningKeyBlob;
170 }
171
Martijn Coenen799ce6e2021-02-23 10:14:41 +0100172 auto existing_cert = verifyExistingCert(key.value());
Martijn Coenen95194842020-09-24 16:56:46 +0200173 if (!existing_cert.ok()) {
174 LOG(WARNING) << existing_cert.error().message();
175
176 // Try to create a new cert
177 auto new_cert = key->createX509Cert(kSigningKeyCert);
178 if (!new_cert.ok()) {
179 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error().message();
180 // TODO apparently the key become invalid - delete the blob / cert
181 return -1;
182 }
Martijn Coenen95194842020-09-24 16:56:46 +0200183 } else {
184 LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
185 }
Martijn Coenen799ce6e2021-02-23 10:14:41 +0100186 auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert);
187 if (!cert_add_result.ok()) {
188 LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
189 << cert_add_result.error().message();
190 return -1;
191 }
Martijn Coenen95194842020-09-24 16:56:46 +0200192
193 auto verityStatus = verifyAllFilesInVerity(kArtArtifactsDir);
194 if (!verityStatus.ok()) {
195 LOG(WARNING) << verityStatus.error().message() << ", removing " << kArtArtifactsDir;
196 removeArtifacts();
197 }
198
199 bool artifactsValid = validateArtifacts();
200
201 if (!artifactsValid || kForceCompilation) {
202 removeArtifacts();
203
204 LOG(INFO) << "Starting compilation... ";
205 bool ret = compileArtifacts(kForceCompilation);
206 LOG(INFO) << "Compilation done, returned " << ret;
207
208 verityStatus = addFilesToVerityRecursive(kArtArtifactsDir, key.value());
209
210 if (!verityStatus.ok()) {
211 LOG(ERROR) << "Failed to add " << verityStatus.error().message();
212 return -1;
213 }
214 }
215
216 // TODO we want to make sure Zygote only picks up the artifacts if we deemed
217 // everything was ok here. We could use a sysprop, or some other mechanism?
218 LOG(INFO) << "On-device signing done.";
219
220 scope_guard.Disable();
221 return 0;
222}