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 "VerityUtils.h"
37 
38 #include "odsign_info.pb.h"
39 
40 using android::base::ErrnoError;
41 using android::base::Error;
42 using android::base::Result;
43 using android::base::SetProperty;
44 
45 using OdsignInfo = ::odsign::proto::OdsignInfo;
46 
47 const std::string kSigningKeyBlob = "/data/misc/odsign/key.blob";
48 const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
49 const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
50 const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
51 
52 const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
53 
54 static const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
55 
56 static const char* kFsVerityProcPath = "/proc/sys/fs/verity";
57 
58 static const bool kForceCompilation = false;
59 
60 static const char* kOdsignVerificationDoneProp = "odsign.verification.done";
61 static const char* kOdsignKeyDoneProp = "odsign.key.done";
62 
63 static const char* kOdsignVerificationStatusProp = "odsign.verification.success";
64 static const char* kOdsignVerificationStatusValid = "1";
65 static const char* kOdsignVerificationStatusError = "0";
66 
67 static const char* kStopServiceProp = "ctl.stop";
68 
removeDirectory(const std::string & directory)69 static int removeDirectory(const std::string& directory) {
70     std::error_code ec;
71     auto num_removed = std::filesystem::remove_all(directory, ec);
72     if (ec) {
73         LOG(ERROR) << "Can't remove " << directory << ": " << ec.message();
74         return 0;
75     } else {
76         if (num_removed > 0) {
77             LOG(INFO) << "Removed " << num_removed << " entries from " << directory;
78         }
79         return num_removed;
80     }
81 }
82 
verifyExistingCert(const SigningKey & key)83 Result<void> verifyExistingCert(const SigningKey& key) {
84     if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
85         return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
86     }
87     auto trustedPublicKey = key.getPublicKey();
88     if (!trustedPublicKey.ok()) {
89         return Error() << "Failed to retrieve signing public key.";
90     }
91 
92     auto publicKeyFromExistingCert = extractPublicKeyFromX509(kSigningKeyCert);
93     if (!publicKeyFromExistingCert.ok()) {
94         return publicKeyFromExistingCert.error();
95     }
96     if (publicKeyFromExistingCert.value() != trustedPublicKey.value()) {
97         return Error() << "Public key of existing certificate at " << kSigningKeyCert
98                        << " does not match signing public key.";
99     }
100 
101     // At this point, we know the cert matches
102     return {};
103 }
104 
createX509Cert(const SigningKey & key,const std::string & outPath)105 Result<void> createX509Cert(const SigningKey& key, const std::string& outPath) {
106     auto publicKey = key.getPublicKey();
107 
108     if (!publicKey.ok()) {
109         return publicKey.error();
110     }
111 
112     auto keySignFunction = [&](const std::string& to_be_signed) { return key.sign(to_be_signed); };
113     createSelfSignedCertificate(*publicKey, keySignFunction, outPath);
114     return {};
115 }
116 
checkArtifacts()117 art::odrefresh::ExitCode checkArtifacts() {
118     const char* const argv[] = {kOdrefreshPath, "--check"};
119     const int exit_code =
120         logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
121     return static_cast<art::odrefresh::ExitCode>(exit_code);
122 }
123 
compileArtifacts(bool force)124 art::odrefresh::ExitCode compileArtifacts(bool force) {
125     const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
126     const int exit_code =
127         logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
128     return static_cast<art::odrefresh::ExitCode>(exit_code);
129 }
130 
toHex(const std::vector<uint8_t> & digest)131 static std::string toHex(const std::vector<uint8_t>& digest) {
132     std::stringstream ss;
133     for (auto it = digest.begin(); it != digest.end(); ++it) {
134         ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned>(*it);
135     }
136     return ss.str();
137 }
138 
computeDigests(const std::string & path)139 Result<std::map<std::string, std::string>> computeDigests(const std::string& path) {
140     std::error_code ec;
141     std::map<std::string, std::string> digests;
142 
143     auto it = std::filesystem::recursive_directory_iterator(path, ec);
144     auto end = std::filesystem::recursive_directory_iterator();
145 
146     while (!ec && it != end) {
147         if (it->is_regular_file()) {
148             auto digest = createDigest(it->path());
149             if (!digest.ok()) {
150                 return Error() << "Failed to compute digest for " << it->path();
151             }
152             digests[it->path()] = toHex(*digest);
153         }
154         ++it;
155     }
156     if (ec) {
157         return Error() << "Failed to iterate " << path << ": " << ec;
158     }
159 
160     return digests;
161 }
162 
verifyDigests(const std::map<std::string,std::string> & digests,const std::map<std::string,std::string> & trusted_digests)163 Result<void> verifyDigests(const std::map<std::string, std::string>& digests,
164                            const std::map<std::string, std::string>& trusted_digests) {
165     for (const auto& path_digest : digests) {
166         auto path = path_digest.first;
167         auto digest = path_digest.second;
168         if (trusted_digests.count(path) == 0) {
169             return Error() << "Couldn't find digest for " << path;
170         }
171         if (trusted_digests.at(path) != digest) {
172             return Error() << "Digest mismatch for " << path;
173         }
174     }
175 
176     // All digests matched!
177     if (digests.size() > 0) {
178         LOG(INFO) << "All root hashes match.";
179     }
180     return {};
181 }
182 
verifyIntegrityFsVerity(const std::map<std::string,std::string> & trusted_digests)183 Result<void> verifyIntegrityFsVerity(const std::map<std::string, std::string>& trusted_digests) {
184     // Just verify that the files are in verity, and get their digests
185     auto result = verifyAllFilesInVerity(kArtArtifactsDir);
186     if (!result.ok()) {
187         return result.error();
188     }
189 
190     return verifyDigests(*result, trusted_digests);
191 }
192 
verifyIntegrityNoFsVerity(const std::map<std::string,std::string> & trusted_digests)193 Result<void> verifyIntegrityNoFsVerity(const std::map<std::string, std::string>& trusted_digests) {
194     // On these devices, just compute the digests, and verify they match the ones we trust
195     auto result = computeDigests(kArtArtifactsDir);
196     if (!result.ok()) {
197         return result.error();
198     }
199 
200     return verifyDigests(*result, trusted_digests);
201 }
202 
getAndVerifyOdsignInfo(const SigningKey & key)203 Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
204     std::string persistedSignature;
205     OdsignInfo odsignInfo;
206 
207     if (!android::base::ReadFileToString(kOdsignInfoSignature, &persistedSignature)) {
208         return ErrnoError() << "Failed to read " << kOdsignInfoSignature;
209     }
210 
211     std::fstream odsign_info(kOdsignInfo, std::ios::in | std::ios::binary);
212     if (!odsign_info) {
213         return Error() << "Failed to open " << kOdsignInfo;
214     }
215     odsign_info.seekg(0);
216     // Verify the hash
217     std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
218                                 std::istreambuf_iterator<char>());
219 
220     auto publicKey = key.getPublicKey();
221     auto signResult = verifySignature(odsign_info_str, persistedSignature, *publicKey);
222     if (!signResult.ok()) {
223         return Error() << kOdsignInfoSignature << " does not match.";
224     } else {
225         LOG(INFO) << kOdsignInfoSignature << " matches.";
226     }
227 
228     odsign_info.seekg(0);
229     if (!odsignInfo.ParseFromIstream(&odsign_info)) {
230         return Error() << "Failed to parse " << kOdsignInfo;
231     }
232 
233     LOG(INFO) << "Loaded " << kOdsignInfo;
234     return odsignInfo;
235 }
236 
getTrustedDigests(const SigningKey & key)237 std::map<std::string, std::string> getTrustedDigests(const SigningKey& key) {
238     std::map<std::string, std::string> trusted_digests;
239 
240     if (access(kOdsignInfo.c_str(), F_OK) != 0) {
241         // no odsign info file, which is not necessarily an error - just return
242         // an empty list of digests.
243         LOG(INFO) << kOdsignInfo << " not found.";
244         return trusted_digests;
245     }
246     auto signInfo = getAndVerifyOdsignInfo(key);
247 
248     if (signInfo.ok()) {
249         trusted_digests.insert(signInfo->file_hashes().begin(), signInfo->file_hashes().end());
250     } else {
251         // This is not expected, since the file did exist. Log an error and
252         // return an empty list of digests.
253         LOG(ERROR) << "Couldn't load trusted digests: " << signInfo.error();
254     }
255 
256     return trusted_digests;
257 }
258 
persistDigests(const std::map<std::string,std::string> & digests,const SigningKey & key)259 Result<void> persistDigests(const std::map<std::string, std::string>& digests,
260                             const SigningKey& key) {
261     OdsignInfo signInfo;
262     google::protobuf::Map<std::string, std::string> proto_hashes(digests.begin(), digests.end());
263     auto map = signInfo.mutable_file_hashes();
264     *map = proto_hashes;
265 
266     std::fstream odsign_info(kOdsignInfo,
267                              std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
268     if (!signInfo.SerializeToOstream(&odsign_info)) {
269         return Error() << "Failed to persist root hashes in " << kOdsignInfo;
270     }
271 
272     // Sign the signatures with our key itself, and write that to storage
273     odsign_info.seekg(0, std::ios::beg);
274     std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
275                                 std::istreambuf_iterator<char>());
276     auto signResult = key.sign(odsign_info_str);
277     if (!signResult.ok()) {
278         return Error() << "Failed to sign " << kOdsignInfo;
279     }
280     android::base::WriteStringToFile(*signResult, kOdsignInfoSignature);
281     return {};
282 }
283 
removeArtifacts()284 static int removeArtifacts() {
285     std::error_code ec;
286     auto num_removed = std::filesystem::remove_all(kArtArtifactsDir, ec);
287     if (ec) {
288         LOG(ERROR) << "Can't remove " << kArtArtifactsDir << ": " << ec.message();
289         return 0;
290     } else {
291         if (num_removed > 0) {
292             LOG(INFO) << "Removed " << num_removed << " entries from " << kArtArtifactsDir;
293         }
294         return num_removed;
295     }
296 }
297 
verifyArtifacts(const std::map<std::string,std::string> & trusted_digests,bool supportsFsVerity)298 static Result<void> verifyArtifacts(const std::map<std::string, std::string>& trusted_digests,
299                                     bool supportsFsVerity) {
300     Result<void> integrityStatus;
301 
302     if (supportsFsVerity) {
303         integrityStatus = verifyIntegrityFsVerity(trusted_digests);
304     } else {
305         integrityStatus = verifyIntegrityNoFsVerity(trusted_digests);
306     }
307     if (!integrityStatus.ok()) {
308         return Error() << integrityStatus.error().message();
309     }
310 
311     return {};
312 }
313 
main(int,char **)314 int main(int /* argc */, char** /* argv */) {
315     auto errorScopeGuard = []() {
316         // In case we hit any error, remove the artifacts and tell Zygote not to use anything
317         removeArtifacts();
318         // Tell init we don't need to use our key anymore
319         SetProperty(kOdsignKeyDoneProp, "1");
320         // Tell init we're done with verification, and that it was an error
321         SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusError);
322         SetProperty(kOdsignVerificationDoneProp, "1");
323         // Tell init it shouldn't try to restart us - see odsign.rc
324         SetProperty(kStopServiceProp, "odsign");
325     };
326     auto scope_guard = android::base::make_scope_guard(errorScopeGuard);
327 
328     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
329         LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
330         return 0;
331     }
332 
333     auto keystoreResult = KeystoreKey::getInstance();
334     if (!keystoreResult.ok()) {
335         LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error().message();
336         return -1;
337     }
338     SigningKey* key = keystoreResult.value();
339 
340     bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
341     if (!supportsFsVerity) {
342         LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
343     }
344 
345     if (supportsFsVerity) {
346         auto existing_cert = verifyExistingCert(*key);
347         if (!existing_cert.ok()) {
348             LOG(WARNING) << existing_cert.error().message();
349 
350             // Try to create a new cert
351             auto new_cert = createX509Cert(*key, kSigningKeyCert);
352             if (!new_cert.ok()) {
353                 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error().message();
354                 // TODO apparently the key become invalid - delete the blob / cert
355                 return -1;
356             }
357         } else {
358             LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
359         }
360         auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert);
361         if (!cert_add_result.ok()) {
362             LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
363                        << cert_add_result.error().message();
364             return -1;
365         }
366     }
367 
368     art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
369 
370     // The artifacts dir doesn't necessarily need to exist; if the existing
371     // artifacts on the system partition are valid, those can be used.
372     int err = access(kArtArtifactsDir.c_str(), F_OK);
373     // If we receive any error other than ENOENT, be suspicious
374     bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
375 
376     if (artifactsPresent && (odrefresh_status == art::odrefresh::ExitCode::kOkay ||
377                              odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired)) {
378         // If we haven't verified the digests yet, we need to validate them. We
379         // need to do this both in case the existing artifacts are okay, but
380         // also if odrefresh said that a recompile is required. In the latter
381         // case, odrefresh may use partial compilation, and leave some
382         // artifacts unchanged.
383         auto trusted_digests = getTrustedDigests(*key);
384 
385         if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
386             // Tell init we're done with the key; this is a boot time optimization
387             // in particular for the no fs-verity case, where we need to do a
388             // costly verification. If the files haven't been tampered with, which
389             // should be the common path, the verification will succeed, and we won't
390             // need the key anymore. If it turns out the artifacts are invalid (eg not
391             // in fs-verity) or the hash doesn't match, we won't be able to generate
392             // new artifacts without the key, so in those cases, remove the artifacts,
393             // and use JIT zygote for the current boot. We should recover automatically
394             // by the next boot.
395             SetProperty(kOdsignKeyDoneProp, "1");
396         }
397 
398         auto verificationResult = verifyArtifacts(trusted_digests, supportsFsVerity);
399         if (!verificationResult.ok()) {
400             int num_removed = removeDirectory(kArtArtifactsDir);
401             if (num_removed == 0) {
402                 // If we can't remove the bad artifacts, we shouldn't continue, and
403                 // instead prevent Zygote from using them (which is taken care of
404                 // in the exit handler).
405                 LOG(ERROR) << "Failed to remove unknown artifacts.";
406                 return -1;
407             }
408         }
409     }
410 
411     // Now that we verified existing artifacts, compile if we need to.
412     if (odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired) {
413         odrefresh_status = compileArtifacts(kForceCompilation);
414     }
415 
416     if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
417         // No new artifacts generated, and we verified existing ones above, nothing left to do.
418         LOG(INFO) << "odrefresh said artifacts are VALID";
419     } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
420                odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
421         const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;
422         LOG(INFO) << "odrefresh compiled " << (compiled_all ? "all" : "partial")
423                   << " artifacts, returned " << odrefresh_status;
424         Result<std::map<std::string, std::string>> digests;
425         if (supportsFsVerity) {
426             digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
427         } else {
428             // If we can't use verity, just compute the root hashes and store
429             // those, so we can reverify them at the next boot.
430             digests = computeDigests(kArtArtifactsDir);
431         }
432         if (!digests.ok()) {
433             LOG(ERROR) << digests.error().message();
434             return -1;
435         }
436         auto persistStatus = persistDigests(*digests, *key);
437         if (!persistStatus.ok()) {
438             LOG(ERROR) << persistStatus.error().message();
439             return -1;
440         }
441     } else if (odrefresh_status == art::odrefresh::ExitCode::kCleanupFailed) {
442         LOG(ERROR) << "odrefresh failed cleaning up existing artifacts";
443         return -1;
444     } else {
445         LOG(ERROR) << "odrefresh exited unexpectedly, returned " << odrefresh_status;
446         return -1;
447     }
448 
449     LOG(INFO) << "On-device signing done.";
450 
451     scope_guard.Disable();
452     // At this point, we're done with the key for sure
453     SetProperty(kOdsignKeyDoneProp, "1");
454     // And we did a successful verification
455     SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusValid);
456     SetProperty(kOdsignVerificationDoneProp, "1");
457 
458     // Tell init it shouldn't try to restart us - see odsign.rc
459     SetProperty(kStopServiceProp, "odsign");
460     return 0;
461 }
462