1 /*
2  * Copyright (C) 2018 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 "apexd.h"
18 #include "apexd_private.h"
19 
20 #include "apex_constants.h"
21 #include "apex_database.h"
22 #include "apex_file.h"
23 #include "apex_manifest.h"
24 #include "apex_preinstalled_data.h"
25 #include "apex_shim.h"
26 #include "apexd_checkpoint.h"
27 #include "apexd_loop.h"
28 #include "apexd_prepostinstall.h"
29 #include "apexd_prop.h"
30 #include "apexd_rollback_utils.h"
31 #include "apexd_session.h"
32 #include "apexd_utils.h"
33 #include "apexd_verity.h"
34 #include "com_android_apex.h"
35 #include "string_log.h"
36 
37 #include <ApexProperties.sysprop.h>
38 #include <android-base/file.h>
39 #include <android-base/logging.h>
40 #include <android-base/macros.h>
41 #include <android-base/parseint.h>
42 #include <android-base/properties.h>
43 #include <android-base/scopeguard.h>
44 #include <android-base/stringprintf.h>
45 #include <android-base/strings.h>
46 #include <android-base/unique_fd.h>
47 #include <libavb/libavb.h>
48 #include <libdm/dm.h>
49 #include <libdm/dm_table.h>
50 #include <libdm/dm_target.h>
51 #include <selinux/android.h>
52 
53 #include <dirent.h>
54 #include <fcntl.h>
55 #include <linux/loop.h>
56 #include <stdlib.h>
57 #include <sys/inotify.h>
58 #include <sys/ioctl.h>
59 #include <sys/mount.h>
60 #include <sys/stat.h>
61 #include <sys/types.h>
62 #include <unistd.h>
63 
64 #include <algorithm>
65 #include <array>
66 #include <chrono>
67 #include <cstdlib>
68 #include <filesystem>
69 #include <fstream>
70 #include <iomanip>
71 #include <iterator>
72 #include <memory>
73 #include <optional>
74 #include <string>
75 #include <thread>
76 #include <unordered_map>
77 #include <unordered_set>
78 
79 using android::base::ErrnoError;
80 using android::base::Error;
81 using android::base::GetProperty;
82 using android::base::Join;
83 using android::base::ParseUint;
84 using android::base::ReadFully;
85 using android::base::Result;
86 using android::base::StartsWith;
87 using android::base::StringPrintf;
88 using android::base::unique_fd;
89 using android::dm::DeviceMapper;
90 using android::dm::DmDeviceState;
91 using android::dm::DmTable;
92 using android::dm::DmTargetVerity;
93 
94 using apex::proto::SessionState;
95 
96 namespace android {
97 namespace apex {
98 
99 using MountedApexData = MountedApexDatabase::MountedApexData;
100 
101 namespace {
102 
103 // These should be in-sync with system/sepolicy/private/property_contexts
104 static constexpr const char* kApexStatusSysprop = "apexd.status";
105 static constexpr const char* kApexStatusStarting = "starting";
106 static constexpr const char* kApexStatusActivated = "activated";
107 static constexpr const char* kApexStatusReady = "ready";
108 
109 static constexpr const char* kBuildFingerprintSysprop = "ro.build.fingerprint";
110 
111 // This should be in UAPI, but it's not :-(
112 static constexpr const char* kDmVerityRestartOnCorruption =
113     "restart_on_corruption";
114 
115 MountedApexDatabase gMountedApexes;
116 
117 CheckpointInterface* gVoldService;
118 bool gSupportsFsCheckpoints = false;
119 bool gInFsCheckpointMode = false;
120 
121 static constexpr size_t kLoopDeviceSetupAttempts = 3u;
122 
123 bool gBootstrap = false;
__anonb9f628140202() 124 static const std::vector<std::string> kBootstrapApexes = ([]() {
125   std::vector<std::string> ret = {
126       "com.android.art",
127       "com.android.i18n",
128       "com.android.runtime",
129       "com.android.tzdata",
130       "com.android.os.statsd",
131   };
132 
133   auto vendor_vndk_ver = GetProperty("ro.vndk.version", "");
134   if (vendor_vndk_ver != "") {
135     ret.push_back("com.android.vndk.v" + vendor_vndk_ver);
136   }
137   auto product_vndk_ver = GetProperty("ro.product.vndk.version", "");
138   if (product_vndk_ver != "" && product_vndk_ver != vendor_vndk_ver) {
139     ret.push_back("com.android.vndk.v" + product_vndk_ver);
140   }
141   return ret;
142 })();
143 
144 static constexpr const int kNumRetriesWhenCheckpointingEnabled = 2;
145 
isBootstrapApex(const ApexFile & apex)146 bool isBootstrapApex(const ApexFile& apex) {
147   return std::find(kBootstrapApexes.begin(), kBootstrapApexes.end(),
148                    apex.GetManifest().name()) != kBootstrapApexes.end();
149 }
150 
151 // Pre-allocate loop devices so that we don't have to wait for them
152 // later when actually activating APEXes.
preAllocateLoopDevices()153 Result<void> preAllocateLoopDevices() {
154   auto scan = FindApexes(kApexPackageBuiltinDirs);
155   if (!scan.ok()) {
156     return scan.error();
157   }
158 
159   auto size = 0;
160   for (const auto& path : *scan) {
161     auto apexFile = ApexFile::Open(path);
162     if (!apexFile.ok()) {
163       continue;
164     }
165     size++;
166     // bootstrap Apexes may be activated on separate namespaces.
167     if (isBootstrapApex(*apexFile)) {
168       size++;
169     }
170   }
171 
172   // note: do not call preAllocateLoopDevices() if size == 0.
173   // For devices (e.g. ARC) which doesn't support loop-control
174   // preAllocateLoopDevices() can cause problem when it tries
175   // to access /dev/loop-control.
176   if (size == 0) {
177     return {};
178   }
179   return loop::preAllocateLoopDevices(size);
180 }
181 
createVerityTable(const ApexVerityData & verity_data,const std::string & block_device,const std::string & hash_device,bool restart_on_corruption)182 std::unique_ptr<DmTable> createVerityTable(const ApexVerityData& verity_data,
183                                            const std::string& block_device,
184                                            const std::string& hash_device,
185                                            bool restart_on_corruption) {
186   AvbHashtreeDescriptor* desc = verity_data.desc.get();
187   auto table = std::make_unique<DmTable>();
188 
189   uint32_t hash_start_block = 0;
190   if (hash_device == block_device) {
191     hash_start_block = desc->tree_offset / desc->hash_block_size;
192   }
193 
194   auto target = std::make_unique<DmTargetVerity>(
195       0, desc->image_size / 512, desc->dm_verity_version, block_device,
196       hash_device, desc->data_block_size, desc->hash_block_size,
197       desc->image_size / desc->data_block_size, hash_start_block,
198       verity_data.hash_algorithm, verity_data.root_digest, verity_data.salt);
199 
200   target->IgnoreZeroBlocks();
201   if (restart_on_corruption) {
202     target->SetVerityMode(kDmVerityRestartOnCorruption);
203   }
204   table->AddTarget(std::move(target));
205 
206   table->set_readonly(true);
207 
208   return table;
209 }
210 
211 // Deletes a dm-verity device with a given name and path
212 // Synchronizes on the device actually being deleted from userspace.
DeleteVerityDevice(const std::string & name)213 Result<void> DeleteVerityDevice(const std::string& name) {
214   DeviceMapper& dm = DeviceMapper::Instance();
215   if (!dm.DeleteDevice(name, 750ms)) {
216     return Error() << "Failed to delete dm-device " << name;
217   }
218   return {};
219 }
220 
221 class DmVerityDevice {
222  public:
DmVerityDevice()223   DmVerityDevice() : cleared_(true) {}
DmVerityDevice(std::string name)224   explicit DmVerityDevice(std::string name)
225       : name_(std::move(name)), cleared_(false) {}
DmVerityDevice(std::string name,std::string dev_path)226   DmVerityDevice(std::string name, std::string dev_path)
227       : name_(std::move(name)),
228         dev_path_(std::move(dev_path)),
229         cleared_(false) {}
230 
DmVerityDevice(DmVerityDevice && other)231   DmVerityDevice(DmVerityDevice&& other) noexcept
232       : name_(std::move(other.name_)),
233         dev_path_(std::move(other.dev_path_)),
234         cleared_(other.cleared_) {
235     other.cleared_ = true;
236   }
237 
operator =(DmVerityDevice && other)238   DmVerityDevice& operator=(DmVerityDevice&& other) noexcept {
239     name_ = other.name_;
240     dev_path_ = other.dev_path_;
241     cleared_ = other.cleared_;
242     other.cleared_ = true;
243     return *this;
244   }
245 
~DmVerityDevice()246   ~DmVerityDevice() {
247     if (!cleared_) {
248       Result<void> ret = DeleteVerityDevice(name_);
249       if (!ret.ok()) {
250         LOG(ERROR) << ret.error();
251       }
252     }
253   }
254 
GetName() const255   const std::string& GetName() const { return name_; }
GetDevPath() const256   const std::string& GetDevPath() const { return dev_path_; }
257 
Release()258   void Release() { cleared_ = true; }
259 
260  private:
261   std::string name_;
262   std::string dev_path_;
263   bool cleared_;
264 };
265 
createVerityDevice(const std::string & name,const DmTable & table)266 Result<DmVerityDevice> createVerityDevice(const std::string& name,
267                                           const DmTable& table) {
268   DeviceMapper& dm = DeviceMapper::Instance();
269 
270   if (dm.GetState(name) != DmDeviceState::INVALID) {
271     // Delete dangling dm-device. This can happen if apexd fails to delete it
272     // while unmounting an apex.
273     LOG(WARNING) << "Deleting existing dm device " << name;
274     auto result = DeleteVerityDevice(name);
275     if (!result.ok()) {
276       return result.error();
277     }
278   }
279 
280   std::string dev_path;
281   if (!dm.CreateDevice(name, table, &dev_path, 500ms)) {
282     return Errorf("Couldn't create verity device.");
283   }
284   return DmVerityDevice(name, dev_path);
285 }
286 
RemovePreviouslyActiveApexFiles(const std::unordered_set<std::string> & affected_packages,const std::unordered_set<std::string> & files_to_keep)287 Result<void> RemovePreviouslyActiveApexFiles(
288     const std::unordered_set<std::string>& affected_packages,
289     const std::unordered_set<std::string>& files_to_keep) {
290   auto all_active_apex_files = FindApexFilesByName(kActiveApexPackagesDataDir);
291 
292   if (!all_active_apex_files.ok()) {
293     return all_active_apex_files.error();
294   }
295 
296   for (const std::string& path : *all_active_apex_files) {
297     Result<ApexFile> apex_file = ApexFile::Open(path);
298     if (!apex_file.ok()) {
299       return apex_file.error();
300     }
301 
302     const std::string& package_name = apex_file->GetManifest().name();
303     if (affected_packages.find(package_name) == affected_packages.end()) {
304       // This apex belongs to a package that wasn't part of this stage sessions,
305       // hence it should be kept.
306       continue;
307     }
308 
309     if (files_to_keep.find(apex_file->GetPath()) != files_to_keep.end()) {
310       // This is a path that was staged and should be kept.
311       continue;
312     }
313 
314     LOG(DEBUG) << "Deleting previously active apex " << apex_file->GetPath();
315     if (unlink(apex_file->GetPath().c_str()) != 0) {
316       return ErrnoError() << "Failed to unlink " << apex_file->GetPath();
317     }
318   }
319 
320   return {};
321 }
322 
323 // Reads the entire device to verify the image is authenticatic
readVerityDevice(const std::string & verity_device,uint64_t device_size)324 Result<void> readVerityDevice(const std::string& verity_device,
325                               uint64_t device_size) {
326   static constexpr int kBlockSize = 4096;
327   static constexpr size_t kBufSize = 1024 * kBlockSize;
328   std::vector<uint8_t> buffer(kBufSize);
329 
330   unique_fd fd(
331       TEMP_FAILURE_RETRY(open(verity_device.c_str(), O_RDONLY | O_CLOEXEC)));
332   if (fd.get() == -1) {
333     return ErrnoError() << "Can't open " << verity_device;
334   }
335 
336   size_t bytes_left = device_size;
337   while (bytes_left > 0) {
338     size_t to_read = std::min(bytes_left, kBufSize);
339     if (!android::base::ReadFully(fd.get(), buffer.data(), to_read)) {
340       return ErrnoError() << "Can't verify " << verity_device << "; corrupted?";
341     }
342     bytes_left -= to_read;
343   }
344 
345   return {};
346 }
347 
VerifyMountedImage(const ApexFile & apex,const std::string & mount_point)348 Result<void> VerifyMountedImage(const ApexFile& apex,
349                                 const std::string& mount_point) {
350   auto result = apex.VerifyManifestMatches(mount_point);
351   if (!result.ok()) {
352     return result;
353   }
354   if (shim::IsShimApex(apex)) {
355     return shim::ValidateShimApex(mount_point, apex);
356   }
357   return {};
358 }
359 
MountPackageImpl(const ApexFile & apex,const std::string & mountPoint,const std::string & device_name,const std::string & hashtree_file,bool verifyImage)360 Result<MountedApexData> MountPackageImpl(const ApexFile& apex,
361                                          const std::string& mountPoint,
362                                          const std::string& device_name,
363                                          const std::string& hashtree_file,
364                                          bool verifyImage) {
365   LOG(VERBOSE) << "Creating mount point: " << mountPoint;
366   // Note: the mount point could exist in case when the APEX was activated
367   // during the bootstrap phase (e.g., the runtime or tzdata APEX).
368   // Although we have separate mount namespaces to separate the early activated
369   // APEXes from the normally activate APEXes, the mount points themselves
370   // are shared across the two mount namespaces because /apex (a tmpfs) itself
371   // mounted at / which is (and has to be) a shared mount. Therefore, if apexd
372   // finds an empty directory under /apex, it's not a problem and apexd can use
373   // it.
374   auto exists = PathExists(mountPoint);
375   if (!exists.ok()) {
376     return exists.error();
377   }
378   if (!*exists && mkdir(mountPoint.c_str(), kMkdirMode) != 0) {
379     return ErrnoError() << "Could not create mount point " << mountPoint;
380   }
381   auto deleter = [&mountPoint]() {
382     if (rmdir(mountPoint.c_str()) != 0) {
383       PLOG(WARNING) << "Could not rmdir " << mountPoint;
384     }
385   };
386   auto scope_guard = android::base::make_scope_guard(deleter);
387   if (!IsEmptyDirectory(mountPoint)) {
388     return ErrnoError() << mountPoint << " is not empty";
389   }
390 
391   const std::string& full_path = apex.GetPath();
392 
393   loop::LoopbackDeviceUniqueFd loopbackDevice;
394   for (size_t attempts = 1;; ++attempts) {
395     Result<loop::LoopbackDeviceUniqueFd> ret = loop::createLoopDevice(
396         full_path, apex.GetImageOffset(), apex.GetImageSize());
397     if (ret.ok()) {
398       loopbackDevice = std::move(*ret);
399       break;
400     }
401     if (attempts >= kLoopDeviceSetupAttempts) {
402       return Error() << "Could not create loop device for " << full_path << ": "
403                      << ret.error();
404     }
405   }
406   LOG(VERBOSE) << "Loopback device created: " << loopbackDevice.name;
407 
408   auto verityData = apex.VerifyApexVerity();
409   if (!verityData.ok()) {
410     return Error() << "Failed to verify Apex Verity data for " << full_path
411                    << ": " << verityData.error();
412   }
413   std::string blockDevice = loopbackDevice.name;
414   MountedApexData apex_data(loopbackDevice.name, apex.GetPath(), mountPoint,
415                             /* device_name = */ "",
416                             /* hashtree_loop_name = */ "");
417 
418   // for APEXes in immutable partitions, we don't need to mount them on
419   // dm-verity because they are already in the dm-verity protected partition;
420   // system. However, note that we don't skip verification to ensure that APEXes
421   // are correctly signed.
422   const bool mountOnVerity = !isPathForBuiltinApexes(full_path);
423   DmVerityDevice verityDev;
424   loop::LoopbackDeviceUniqueFd loop_for_hash;
425   if (mountOnVerity) {
426     std::string hash_device = loopbackDevice.name;
427     if (verityData->desc->tree_size == 0) {
428       if (auto st = PrepareHashTree(apex, *verityData, hashtree_file);
429           !st.ok()) {
430         return st.error();
431       }
432       auto create_loop_status = loop::createLoopDevice(hashtree_file, 0, 0);
433       if (!create_loop_status.ok()) {
434         return create_loop_status.error();
435       }
436       loop_for_hash = std::move(*create_loop_status);
437       hash_device = loop_for_hash.name;
438       apex_data.hashtree_loop_name = hash_device;
439     }
440     auto verityTable =
441         createVerityTable(*verityData, loopbackDevice.name, hash_device,
442                           /* restart_on_corruption = */ !verifyImage);
443     Result<DmVerityDevice> verityDevRes =
444         createVerityDevice(device_name, *verityTable);
445     if (!verityDevRes.ok()) {
446       return Error() << "Failed to create Apex Verity device " << full_path
447                      << ": " << verityDevRes.error();
448     }
449     verityDev = std::move(*verityDevRes);
450     apex_data.device_name = device_name;
451     blockDevice = verityDev.GetDevPath();
452 
453     Result<void> readAheadStatus =
454         loop::configureReadAhead(verityDev.GetDevPath());
455     if (!readAheadStatus.ok()) {
456       return readAheadStatus.error();
457     }
458   }
459   // TODO(b/158467418): consider moving this inside RunVerifyFnInsideTempMount.
460   if (mountOnVerity && verifyImage) {
461     Result<void> verityStatus =
462         readVerityDevice(blockDevice, (*verityData).desc->image_size);
463     if (!verityStatus.ok()) {
464       return verityStatus.error();
465     }
466   }
467 
468   uint32_t mountFlags = MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY;
469   if (apex.GetManifest().nocode()) {
470     mountFlags |= MS_NOEXEC;
471   }
472 
473   if (mount(blockDevice.c_str(), mountPoint.c_str(), "ext4", mountFlags,
474             nullptr) == 0) {
475     LOG(INFO) << "Successfully mounted package " << full_path << " on "
476               << mountPoint;
477     auto status = VerifyMountedImage(apex, mountPoint);
478     if (!status.ok()) {
479       if (umount2(mountPoint.c_str(), UMOUNT_NOFOLLOW) != 0) {
480         PLOG(ERROR) << "Failed to umount " << mountPoint;
481       }
482       return Error() << "Failed to verify " << full_path << ": "
483                      << status.error();
484     }
485     // Time to accept the temporaries as good.
486     verityDev.Release();
487     loopbackDevice.CloseGood();
488     loop_for_hash.CloseGood();
489 
490     scope_guard.Disable();  // Accept the mount.
491     return apex_data;
492   } else {
493     return ErrnoError() << "Mounting failed for package " << full_path;
494   }
495 }
496 
GetHashTreeFileName(const ApexFile & apex,bool is_new)497 std::string GetHashTreeFileName(const ApexFile& apex, bool is_new) {
498   std::string ret =
499       std::string(kApexHashTreeDir) + "/" + GetPackageId(apex.GetManifest());
500   return is_new ? ret + ".new" : ret;
501 }
502 
VerifyAndTempMountPackage(const ApexFile & apex,const std::string & mount_point)503 Result<MountedApexData> VerifyAndTempMountPackage(
504     const ApexFile& apex, const std::string& mount_point) {
505   const std::string& package_id = GetPackageId(apex.GetManifest());
506   LOG(DEBUG) << "Temp mounting " << package_id << " to " << mount_point;
507   const std::string& temp_device_name = package_id + ".tmp";
508   std::string hashtree_file = GetHashTreeFileName(apex, /* is_new = */ true);
509   if (access(hashtree_file.c_str(), F_OK) == 0) {
510     LOG(DEBUG) << hashtree_file << " already exists. Deleting it";
511     if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
512       return ErrnoError() << "Failed to unlink " << hashtree_file;
513     }
514   }
515   auto ret = MountPackageImpl(apex, mount_point, temp_device_name,
516                               hashtree_file, /* verifyImage = */ true);
517   if (!ret.ok()) {
518     LOG(DEBUG) << "Cleaning up " << hashtree_file;
519     if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
520       PLOG(ERROR) << "Failed to unlink " << hashtree_file;
521     }
522   }
523   return ret;
524 }
525 
Unmount(const MountedApexData & data)526 Result<void> Unmount(const MountedApexData& data) {
527   LOG(DEBUG) << "Unmounting " << data.full_path << " from mount point "
528              << data.mount_point;
529   // Lazily try to umount whatever is mounted.
530   if (umount2(data.mount_point.c_str(), UMOUNT_NOFOLLOW) != 0 &&
531       errno != EINVAL && errno != ENOENT) {
532     return ErrnoError() << "Failed to unmount directory " << data.mount_point;
533   }
534   // Attempt to delete the folder. If the folder is retained, other
535   // data may be incorrect.
536   if (rmdir(data.mount_point.c_str()) != 0) {
537     PLOG(ERROR) << "Failed to rmdir directory " << data.mount_point;
538   }
539 
540   // Try to free up the device-mapper device.
541   if (!data.device_name.empty()) {
542     const auto& result = DeleteVerityDevice(data.device_name);
543     if (!result.ok()) {
544       return result;
545     }
546   }
547 
548   // Try to free up the loop device.
549   auto log_fn = [](const std::string& path, const std::string& /*id*/) {
550     LOG(VERBOSE) << "Freeing loop device " << path << " for unmount.";
551   };
552   if (!data.loop_name.empty()) {
553     loop::DestroyLoopDevice(data.loop_name, log_fn);
554   }
555   if (!data.hashtree_loop_name.empty()) {
556     loop::DestroyLoopDevice(data.hashtree_loop_name, log_fn);
557   }
558 
559   return {};
560 }
561 
562 template <typename VerifyFn>
RunVerifyFnInsideTempMount(const ApexFile & apex,const VerifyFn & verify_fn)563 Result<void> RunVerifyFnInsideTempMount(const ApexFile& apex,
564                                         const VerifyFn& verify_fn) {
565   // Temp mount image of this apex to validate it was properly signed;
566   // this will also read the entire block device through dm-verity, so
567   // we can be sure there is no corruption.
568   const std::string& temp_mount_point =
569       apexd_private::GetPackageTempMountPoint(apex.GetManifest());
570 
571   Result<MountedApexData> mount_status =
572       VerifyAndTempMountPackage(apex, temp_mount_point);
573   if (!mount_status.ok()) {
574     LOG(ERROR) << "Failed to temp mount to " << temp_mount_point << " : "
575                << mount_status.error();
576     return mount_status.error();
577   }
578   auto cleaner = [&]() {
579     LOG(DEBUG) << "Unmounting " << temp_mount_point;
580     Result<void> result = Unmount(*mount_status);
581     if (!result.ok()) {
582       LOG(WARNING) << "Failed to unmount " << temp_mount_point << " : "
583                    << result.error();
584     }
585   };
586   auto scope_guard = android::base::make_scope_guard(cleaner);
587   return verify_fn(temp_mount_point);
588 }
589 
590 template <typename HookFn, typename HookCall>
PrePostinstallPackages(const std::vector<ApexFile> & apexes,HookFn fn,HookCall call)591 Result<void> PrePostinstallPackages(const std::vector<ApexFile>& apexes,
592                                     HookFn fn, HookCall call) {
593   if (apexes.empty()) {
594     return Errorf("Empty set of inputs");
595   }
596 
597   // 1) Check whether the APEXes have hooks.
598   bool has_hooks = false;
599   for (const ApexFile& apex_file : apexes) {
600     if (!(apex_file.GetManifest().*fn)().empty()) {
601       has_hooks = true;
602       break;
603     }
604   }
605 
606   // 2) If we found hooks, run the pre/post-install.
607   if (has_hooks) {
608     Result<void> install_status = (*call)(apexes);
609     if (!install_status.ok()) {
610       return install_status;
611     }
612   }
613 
614   return {};
615 }
616 
PreinstallPackages(const std::vector<ApexFile> & apexes)617 Result<void> PreinstallPackages(const std::vector<ApexFile>& apexes) {
618   return PrePostinstallPackages(apexes, &ApexManifest::preinstallhook,
619                                 &StagePreInstall);
620 }
621 
PostinstallPackages(const std::vector<ApexFile> & apexes)622 Result<void> PostinstallPackages(const std::vector<ApexFile>& apexes) {
623   return PrePostinstallPackages(apexes, &ApexManifest::postinstallhook,
624                                 &StagePostInstall);
625 }
626 
627 // Converts a list of apex file paths into a list of ApexFile objects
628 //
629 // Returns error when trying to open empty set of inputs.
OpenApexFiles(const std::vector<std::string> & paths)630 Result<std::vector<ApexFile>> OpenApexFiles(
631     const std::vector<std::string>& paths) {
632   if (paths.empty()) {
633     return Errorf("Empty set of inputs");
634   }
635   std::vector<ApexFile> ret;
636   for (const std::string& path : paths) {
637     Result<ApexFile> apex_file = ApexFile::Open(path);
638     if (!apex_file.ok()) {
639       return apex_file.error();
640     }
641     ret.emplace_back(std::move(*apex_file));
642   }
643   return ret;
644 }
645 
ValidateStagingShimApex(const ApexFile & to)646 Result<void> ValidateStagingShimApex(const ApexFile& to) {
647   using android::base::StringPrintf;
648   auto system_shim = ApexFile::Open(
649       StringPrintf("%s/%s", kApexPackageSystemDir, shim::kSystemShimApexName));
650   if (!system_shim.ok()) {
651     return system_shim.error();
652   }
653   auto verify_fn = [&](const std::string& system_apex_path) {
654     return shim::ValidateUpdate(system_apex_path, to.GetPath());
655   };
656   return RunVerifyFnInsideTempMount(*system_shim, verify_fn);
657 }
658 
659 // A version of apex verification that happens during boot.
660 // This function should only verification checks that are necessary to run on
661 // each boot. Try to avoid putting expensive checks inside this function.
VerifyPackageBoot(const ApexFile & apex_file)662 Result<void> VerifyPackageBoot(const ApexFile& apex_file) {
663   Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
664   if (!verity_or.ok()) {
665     return verity_or.error();
666   }
667 
668   if (shim::IsShimApex(apex_file)) {
669     // Validating shim is not a very cheap operation, but it's fine to perform
670     // it here since it only runs during CTS tests and will never be triggered
671     // during normal flow.
672     const auto& result = ValidateStagingShimApex(apex_file);
673     if (!result.ok()) {
674       return result;
675     }
676   }
677   return {};
678 }
679 
680 // A version of apex verification that happens on submitStagedSession.
681 // This function contains checks that might be expensive to perform, e.g. temp
682 // mounting a package and reading entire dm-verity device, and shouldn't be run
683 // during boot.
VerifyPackageInstall(const ApexFile & apex_file)684 Result<void> VerifyPackageInstall(const ApexFile& apex_file) {
685   const auto& verify_package_boot_status = VerifyPackageBoot(apex_file);
686   if (!verify_package_boot_status.ok()) {
687     return verify_package_boot_status;
688   }
689   Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
690 
691   constexpr const auto kSuccessFn = [](const std::string& /*mount_point*/) {
692     return Result<void>{};
693   };
694   return RunVerifyFnInsideTempMount(apex_file, kSuccessFn);
695 }
696 
697 template <typename VerifyApexFn>
verifyPackages(const std::vector<std::string> & paths,const VerifyApexFn & verify_apex_fn)698 Result<std::vector<ApexFile>> verifyPackages(
699     const std::vector<std::string>& paths, const VerifyApexFn& verify_apex_fn) {
700   Result<std::vector<ApexFile>> apex_files = OpenApexFiles(paths);
701   if (!apex_files.ok()) {
702     return apex_files.error();
703   }
704 
705   LOG(DEBUG) << "verifyPackages() for " << Join(paths, ',');
706 
707   for (const ApexFile& apex_file : *apex_files) {
708     Result<void> result = verify_apex_fn(apex_file);
709     if (!result.ok()) {
710       return result.error();
711     }
712   }
713   return std::move(*apex_files);
714 }
715 
verifySessionDir(const int session_id)716 Result<ApexFile> verifySessionDir(const int session_id) {
717   std::string sessionDirPath = std::string(kStagedSessionsDir) + "/session_" +
718                                std::to_string(session_id);
719   LOG(INFO) << "Scanning " << sessionDirPath
720             << " looking for packages to be validated";
721   Result<std::vector<std::string>> scan = FindApexFilesByName(sessionDirPath);
722   if (!scan.ok()) {
723     LOG(WARNING) << scan.error();
724     return scan.error();
725   }
726 
727   if (scan->size() > 1) {
728     return Errorf(
729         "More than one APEX package found in the same session directory.");
730   }
731 
732   auto verified = verifyPackages(*scan, VerifyPackageInstall);
733   if (!verified.ok()) {
734     return verified.error();
735   }
736   return std::move((*verified)[0]);
737 }
738 
DeleteBackup()739 Result<void> DeleteBackup() {
740   auto exists = PathExists(std::string(kApexBackupDir));
741   if (!exists.ok()) {
742     return Error() << "Can't clean " << kApexBackupDir << " : "
743                    << exists.error();
744   }
745   if (!*exists) {
746     LOG(DEBUG) << kApexBackupDir << " does not exist. Nothing to clean";
747     return {};
748   }
749   return DeleteDirContent(std::string(kApexBackupDir));
750 }
751 
BackupActivePackages()752 Result<void> BackupActivePackages() {
753   LOG(DEBUG) << "Initializing  backup of " << kActiveApexPackagesDataDir;
754 
755   // Previous restore might've delete backups folder.
756   auto create_status = createDirIfNeeded(kApexBackupDir, 0700);
757   if (!create_status.ok()) {
758     return Error() << "Backup failed : " << create_status.error();
759   }
760 
761   auto apex_active_exists = PathExists(std::string(kActiveApexPackagesDataDir));
762   if (!apex_active_exists.ok()) {
763     return Error() << "Backup failed : " << apex_active_exists.error();
764   }
765   if (!*apex_active_exists) {
766     LOG(DEBUG) << kActiveApexPackagesDataDir
767                << " does not exist. Nothing to backup";
768     return {};
769   }
770 
771   auto active_packages = FindApexFilesByName(kActiveApexPackagesDataDir);
772   if (!active_packages.ok()) {
773     return Error() << "Backup failed : " << active_packages.error();
774   }
775 
776   auto cleanup_status = DeleteBackup();
777   if (!cleanup_status.ok()) {
778     return Error() << "Backup failed : " << cleanup_status.error();
779   }
780 
781   auto backup_path_fn = [](const ApexFile& apex_file) {
782     return StringPrintf("%s/%s%s", kApexBackupDir,
783                         GetPackageId(apex_file.GetManifest()).c_str(),
784                         kApexPackageSuffix);
785   };
786 
787   auto deleter = []() {
788     auto result = DeleteDirContent(std::string(kApexBackupDir));
789     if (!result.ok()) {
790       LOG(ERROR) << "Failed to cleanup " << kApexBackupDir << " : "
791                  << result.error();
792     }
793   };
794   auto scope_guard = android::base::make_scope_guard(deleter);
795 
796   for (const std::string& path : *active_packages) {
797     Result<ApexFile> apex_file = ApexFile::Open(path);
798     if (!apex_file.ok()) {
799       return Error() << "Backup failed : " << apex_file.error();
800     }
801     const auto& dest_path = backup_path_fn(*apex_file);
802     if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
803       return ErrnoError() << "Failed to backup " << apex_file->GetPath();
804     }
805   }
806 
807   scope_guard.Disable();  // Accept the backup.
808   return {};
809 }
810 
RestoreActivePackages()811 Result<void> RestoreActivePackages() {
812   LOG(DEBUG) << "Initializing  restore of " << kActiveApexPackagesDataDir;
813 
814   auto backup_exists = PathExists(std::string(kApexBackupDir));
815   if (!backup_exists.ok()) {
816     return backup_exists.error();
817   }
818   if (!*backup_exists) {
819     return Error() << kApexBackupDir << " does not exist";
820   }
821 
822   struct stat stat_data;
823   if (stat(kActiveApexPackagesDataDir, &stat_data) != 0) {
824     return ErrnoError() << "Failed to access " << kActiveApexPackagesDataDir;
825   }
826 
827   LOG(DEBUG) << "Deleting existing packages in " << kActiveApexPackagesDataDir;
828   auto delete_status =
829       DeleteDirContent(std::string(kActiveApexPackagesDataDir));
830   if (!delete_status.ok()) {
831     return delete_status;
832   }
833 
834   LOG(DEBUG) << "Renaming " << kApexBackupDir << " to "
835              << kActiveApexPackagesDataDir;
836   if (rename(kApexBackupDir, kActiveApexPackagesDataDir) != 0) {
837     return ErrnoError() << "Failed to rename " << kApexBackupDir << " to "
838                         << kActiveApexPackagesDataDir;
839   }
840 
841   LOG(DEBUG) << "Restoring original permissions for "
842              << kActiveApexPackagesDataDir;
843   if (chmod(kActiveApexPackagesDataDir, stat_data.st_mode & ALLPERMS) != 0) {
844     return ErrnoError() << "Failed to restore original permissions for "
845                         << kActiveApexPackagesDataDir;
846   }
847 
848   return {};
849 }
850 
UnmountPackage(const ApexFile & apex,bool allow_latest)851 Result<void> UnmountPackage(const ApexFile& apex, bool allow_latest) {
852   LOG(VERBOSE) << "Unmounting " << GetPackageId(apex.GetManifest());
853 
854   const ApexManifest& manifest = apex.GetManifest();
855 
856   std::optional<MountedApexData> data;
857   bool latest = false;
858 
859   auto fn = [&](const MountedApexData& d, bool l) {
860     if (d.full_path == apex.GetPath()) {
861       data.emplace(d);
862       latest = l;
863     }
864   };
865   gMountedApexes.ForallMountedApexes(manifest.name(), fn);
866 
867   if (!data) {
868     return Error() << "Did not find " << apex.GetPath();
869   }
870 
871   if (latest) {
872     if (!allow_latest) {
873       return Error() << "Package " << apex.GetPath() << " is active";
874     }
875     std::string mount_point = apexd_private::GetActiveMountPoint(manifest);
876     LOG(VERBOSE) << "Unmounting and deleting " << mount_point;
877     if (umount2(mount_point.c_str(), UMOUNT_NOFOLLOW) != 0) {
878       return ErrnoError() << "Failed to unmount " << mount_point;
879     }
880     if (rmdir(mount_point.c_str()) != 0) {
881       PLOG(ERROR) << "Could not rmdir " << mount_point;
882       // Continue here.
883     }
884   }
885 
886   // Clean up gMountedApexes now, even though we're not fully done.
887   gMountedApexes.RemoveMountedApex(manifest.name(), apex.GetPath());
888   return Unmount(*data);
889 }
890 
891 }  // namespace
892 
MountPackage(const ApexFile & apex,const std::string & mountPoint)893 Result<void> MountPackage(const ApexFile& apex, const std::string& mountPoint) {
894   auto ret =
895       MountPackageImpl(apex, mountPoint, GetPackageId(apex.GetManifest()),
896                        GetHashTreeFileName(apex, /* is_new = */ false),
897                        /* verifyImage = */ false);
898   if (!ret.ok()) {
899     return ret.error();
900   }
901 
902   gMountedApexes.AddMountedApex(apex.GetManifest().name(), false, *ret);
903   return {};
904 }
905 
906 namespace apexd_private {
907 
TempMountPackage(const ApexFile & apex,const std::string & mount_point)908 Result<MountedApexData> TempMountPackage(const ApexFile& apex,
909                                          const std::string& mount_point) {
910   // TODO(b/139041058): consolidate these two methods.
911   return android::apex::VerifyAndTempMountPackage(apex, mount_point);
912 }
913 
Unmount(const MountedApexData & data)914 Result<void> Unmount(const MountedApexData& data) {
915   // TODO(b/139041058): consolidate these two methods.
916   return android::apex::Unmount(data);
917 }
918 
IsMounted(const std::string & full_path)919 bool IsMounted(const std::string& full_path) {
920   bool found_mounted = false;
921   gMountedApexes.ForallMountedApexes([&](const std::string&,
922                                          const MountedApexData& data,
923                                          [[maybe_unused]] bool latest) {
924     if (full_path == data.full_path) {
925       found_mounted = true;
926     }
927   });
928   return found_mounted;
929 }
930 
GetPackageMountPoint(const ApexManifest & manifest)931 std::string GetPackageMountPoint(const ApexManifest& manifest) {
932   return StringPrintf("%s/%s", kApexRoot, GetPackageId(manifest).c_str());
933 }
934 
GetPackageTempMountPoint(const ApexManifest & manifest)935 std::string GetPackageTempMountPoint(const ApexManifest& manifest) {
936   return StringPrintf("%s.tmp", GetPackageMountPoint(manifest).c_str());
937 }
938 
GetActiveMountPoint(const ApexManifest & manifest)939 std::string GetActiveMountPoint(const ApexManifest& manifest) {
940   return StringPrintf("%s/%s", kApexRoot, manifest.name().c_str());
941 }
942 
943 }  // namespace apexd_private
944 
resumeRevertIfNeeded()945 Result<void> resumeRevertIfNeeded() {
946   auto sessions =
947       ApexSession::GetSessionsInState(SessionState::REVERT_IN_PROGRESS);
948   if (sessions.empty()) {
949     return {};
950   }
951   return revertActiveSessions("");
952 }
953 
activatePackageImpl(const ApexFile & apex_file)954 Result<void> activatePackageImpl(const ApexFile& apex_file) {
955   const ApexManifest& manifest = apex_file.GetManifest();
956 
957   if (gBootstrap && !isBootstrapApex(apex_file)) {
958     return {};
959   }
960 
961   // See whether we think it's active, and do not allow to activate the same
962   // version. Also detect whether this is the highest version.
963   // We roll this into a single check.
964   bool is_newest_version = true;
965   bool found_other_version = false;
966   bool version_found_mounted = false;
967   {
968     uint64_t new_version = manifest.version();
969     bool version_found_active = false;
970     gMountedApexes.ForallMountedApexes(
971         manifest.name(), [&](const MountedApexData& data, bool latest) {
972           Result<ApexFile> otherApex = ApexFile::Open(data.full_path);
973           if (!otherApex.ok()) {
974             return;
975           }
976           found_other_version = true;
977           if (static_cast<uint64_t>(otherApex->GetManifest().version()) ==
978               new_version) {
979             version_found_mounted = true;
980             version_found_active = latest;
981           }
982           if (static_cast<uint64_t>(otherApex->GetManifest().version()) >
983               new_version) {
984             is_newest_version = false;
985           }
986         });
987     if (version_found_active) {
988       LOG(DEBUG) << "Package " << manifest.name() << " with version "
989                  << manifest.version() << " already active";
990       return {};
991     }
992   }
993 
994   const std::string& mountPoint = apexd_private::GetPackageMountPoint(manifest);
995 
996   if (!version_found_mounted) {
997     auto mountStatus = MountPackage(apex_file, mountPoint);
998     if (!mountStatus.ok()) {
999       return mountStatus;
1000     }
1001   }
1002 
1003   bool mounted_latest = false;
1004   if (is_newest_version) {
1005     const Result<void>& update_st = apexd_private::BindMount(
1006         apexd_private::GetActiveMountPoint(manifest), mountPoint);
1007     mounted_latest = update_st.has_value();
1008     if (!update_st.ok()) {
1009       return Error() << "Failed to update package " << manifest.name()
1010                      << " to version " << manifest.version() << " : "
1011                      << update_st.error();
1012     }
1013   }
1014   if (mounted_latest) {
1015     gMountedApexes.SetLatest(manifest.name(), apex_file.GetPath());
1016   }
1017 
1018   LOG(DEBUG) << "Successfully activated " << apex_file.GetPath()
1019              << " package_name: " << manifest.name()
1020              << " version: " << manifest.version();
1021   return {};
1022 }
1023 
activatePackage(const std::string & full_path)1024 Result<void> activatePackage(const std::string& full_path) {
1025   LOG(INFO) << "Trying to activate " << full_path;
1026 
1027   Result<ApexFile> apex_file = ApexFile::Open(full_path);
1028   if (!apex_file.ok()) {
1029     return apex_file.error();
1030   }
1031   return activatePackageImpl(*apex_file);
1032 }
1033 
deactivatePackage(const std::string & full_path)1034 Result<void> deactivatePackage(const std::string& full_path) {
1035   LOG(INFO) << "Trying to deactivate " << full_path;
1036 
1037   Result<ApexFile> apexFile = ApexFile::Open(full_path);
1038   if (!apexFile.ok()) {
1039     return apexFile.error();
1040   }
1041 
1042   return UnmountPackage(*apexFile, /* allow_latest= */ true);
1043 }
1044 
getActivePackages()1045 std::vector<ApexFile> getActivePackages() {
1046   std::vector<ApexFile> ret;
1047   gMountedApexes.ForallMountedApexes(
1048       [&](const std::string&, const MountedApexData& data, bool latest) {
1049         if (!latest) {
1050           return;
1051         }
1052 
1053         Result<ApexFile> apexFile = ApexFile::Open(data.full_path);
1054         if (!apexFile.ok()) {
1055           return;
1056         }
1057         ret.emplace_back(std::move(*apexFile));
1058       });
1059 
1060   return ret;
1061 }
1062 
emitApexInfoList()1063 Result<void> emitApexInfoList() {
1064   // on a non-updatable device, we don't have APEX database to emit
1065   if (!android::sysprop::ApexProperties::updatable().value_or(false)) {
1066     return {};
1067   }
1068 
1069   std::vector<com::android::apex::ApexInfo> apexInfos;
1070 
1071   auto convertToAutogen = [&apexInfos](const ApexFile& apex, bool isActive) {
1072     auto preinstalledPath = getApexPreinstalledPath(apex.GetManifest().name());
1073     std::optional<std::string> preinstalledModulePath;
1074     if (preinstalledPath.ok()) {
1075       preinstalledModulePath = *preinstalledPath;
1076     }
1077     com::android::apex::ApexInfo apexInfo(
1078         apex.GetManifest().name(), apex.GetPath(), preinstalledModulePath,
1079         apex.GetManifest().version(), apex.GetManifest().versionname(),
1080         apex.IsBuiltin(), isActive);
1081     apexInfos.emplace_back(apexInfo);
1082   };
1083 
1084   // Apexd runs both in "bootstrap" and "default" mount namespace.
1085   // To expose /apex/apex-info-list.xml separately in each mount namespaces,
1086   // we write /apex/.<namespace>-apex-info-list .xml file first and then
1087   // bind mount it to the canonical file (/apex/apex-info-list.xml).
1088   const std::string fileName =
1089       fmt::format("{}/.{}-{}", kApexRoot, gBootstrap ? "bootstrap" : "default",
1090                   kApexInfoList);
1091 
1092   unique_fd fd(TEMP_FAILURE_RETRY(
1093       open(fileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)));
1094   if (fd.get() == -1) {
1095     return ErrnoErrorf("Can't open {}", fileName);
1096   }
1097 
1098   const auto& active = getActivePackages();
1099   for (const auto& apex : active) {
1100     convertToAutogen(apex, true /* isActive */);
1101   }
1102   // we skip for non-activated built-in apexes in bootstrap mode
1103   // in order to avoid boottime increase
1104   if (!gBootstrap) {
1105     for (const auto& apex : getFactoryPackages()) {
1106       const auto& same_path = [&apex](const auto& o) {
1107         return o.GetPath() == apex.GetPath();
1108       };
1109       if (std::find_if(active.begin(), active.end(), same_path) ==
1110           active.end()) {
1111         convertToAutogen(apex, false /* isActive */);
1112       }
1113     }
1114   }
1115 
1116   std::stringstream xml;
1117   com::android::apex::ApexInfoList apexInfoList(apexInfos);
1118   com::android::apex::write(xml, apexInfoList);
1119 
1120   if (!android::base::WriteStringToFd(xml.str(), fd)) {
1121     return ErrnoErrorf("Can't write to {}", fileName);
1122   }
1123 
1124   fd.reset();
1125 
1126   const std::string mountPoint = fmt::format("{}/{}", kApexRoot, kApexInfoList);
1127   if (access(mountPoint.c_str(), F_OK) != 0) {
1128     close(open(mountPoint.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
1129                0644));
1130   }
1131   if (mount(fileName.c_str(), mountPoint.c_str(), nullptr, MS_BIND, nullptr) ==
1132       -1) {
1133     return ErrnoErrorf("Can't bind mount {} to {}", fileName, mountPoint);
1134   }
1135   return RestoreconPath(fileName);
1136 }
1137 
1138 namespace {
GetActivePackagesMap()1139 std::unordered_map<std::string, uint64_t> GetActivePackagesMap() {
1140   std::vector<ApexFile> active_packages = getActivePackages();
1141   std::unordered_map<std::string, uint64_t> ret;
1142   for (const auto& package : active_packages) {
1143     const ApexManifest& manifest = package.GetManifest();
1144     ret.insert({manifest.name(), manifest.version()});
1145   }
1146   return ret;
1147 }
1148 
1149 }  // namespace
1150 
getFactoryPackages()1151 std::vector<ApexFile> getFactoryPackages() {
1152   std::vector<ApexFile> ret;
1153   for (const auto& dir : kApexPackageBuiltinDirs) {
1154     auto apex_files = FindApexFilesByName(dir);
1155     if (!apex_files.ok()) {
1156       LOG(ERROR) << apex_files.error();
1157       continue;
1158     }
1159     for (const std::string& path : *apex_files) {
1160       Result<ApexFile> apex_file = ApexFile::Open(path);
1161       if (!apex_file.ok()) {
1162         LOG(ERROR) << apex_file.error();
1163       } else {
1164         ret.emplace_back(std::move(*apex_file));
1165       }
1166     }
1167   }
1168   return ret;
1169 }
1170 
getActivePackage(const std::string & packageName)1171 Result<ApexFile> getActivePackage(const std::string& packageName) {
1172   std::vector<ApexFile> packages = getActivePackages();
1173   for (ApexFile& apex : packages) {
1174     if (apex.GetManifest().name() == packageName) {
1175       return std::move(apex);
1176     }
1177   }
1178 
1179   return ErrnoError() << "Cannot find matching package for: " << packageName;
1180 }
1181 
1182 /**
1183  * Abort individual staged session.
1184  *
1185  * Returns without error only if session was successfully aborted.
1186  **/
abortStagedSession(int session_id)1187 Result<void> abortStagedSession(int session_id) {
1188   auto session = ApexSession::GetSession(session_id);
1189   if (!session) {
1190     return Error() << "No session found with id " << session_id;
1191   }
1192   switch (session->GetState()) {
1193     case SessionState::VERIFIED:
1194       [[clang::fallthrough]];
1195     case SessionState::STAGED:
1196       return session->DeleteSession();
1197     default:
1198       return Error() << "Session " << *session << " can't be aborted";
1199   }
1200 }
1201 
1202 // TODO(b/139041058): cleanup activation logic to avoid unnecessary scanning.
1203 namespace {
1204 
ScanApexFiles(const char * apex_package_dir)1205 Result<std::vector<ApexFile>> ScanApexFiles(const char* apex_package_dir) {
1206   LOG(INFO) << "Scanning " << apex_package_dir << " looking for APEX packages.";
1207   if (access(apex_package_dir, F_OK) != 0 && errno == ENOENT) {
1208     LOG(INFO) << "... does not exist. Skipping";
1209     return {};
1210   }
1211   Result<std::vector<std::string>> scan = FindApexFilesByName(apex_package_dir);
1212   if (!scan.ok()) {
1213     return Error() << "Failed to scan " << apex_package_dir << " : "
1214                    << scan.error();
1215   }
1216   std::vector<ApexFile> ret;
1217   for (const auto& name : *scan) {
1218     LOG(INFO) << "Found " << name;
1219     Result<ApexFile> apex_file = ApexFile::Open(name);
1220     if (!apex_file.ok()) {
1221       LOG(ERROR) << "Failed to scan " << name << " : " << apex_file.error();
1222     } else {
1223       ret.emplace_back(std::move(*apex_file));
1224     }
1225   }
1226   return ret;
1227 }
1228 
ActivateApexPackages(const std::vector<ApexFile> & apexes)1229 Result<void> ActivateApexPackages(const std::vector<ApexFile>& apexes) {
1230   const auto& packages_with_code = GetActivePackagesMap();
1231   size_t failed_cnt = 0;
1232   size_t skipped_cnt = 0;
1233   size_t activated_cnt = 0;
1234   for (const auto& apex : apexes) {
1235     uint64_t new_version = static_cast<uint64_t>(apex.GetManifest().version());
1236     const auto& it = packages_with_code.find(apex.GetManifest().name());
1237     if (it != packages_with_code.end() && it->second >= new_version) {
1238       LOG(INFO) << "Skipping activation of " << apex.GetPath()
1239                 << " same package with higher version " << it->second
1240                 << " is already active";
1241       skipped_cnt++;
1242       continue;
1243     }
1244 
1245     if (auto res = activatePackageImpl(apex); !res.ok()) {
1246       LOG(ERROR) << "Failed to activate " << apex.GetPath() << " : "
1247                  << res.error();
1248       failed_cnt++;
1249     } else {
1250       activated_cnt++;
1251     }
1252   }
1253   if (failed_cnt > 0) {
1254     return Error() << "Failed to activate " << failed_cnt << " APEX packages";
1255   }
1256   LOG(INFO) << "Activated " << activated_cnt
1257             << " packages. Skipped: " << skipped_cnt;
1258   return {};
1259 }
1260 
ShouldActivateApexOnData(const ApexFile & apex)1261 bool ShouldActivateApexOnData(const ApexFile& apex) {
1262   return HasPreInstalledVersion(apex.GetManifest().name());
1263 }
1264 
1265 }  // namespace
1266 
scanPackagesDirAndActivate(const char * apex_package_dir)1267 Result<void> scanPackagesDirAndActivate(const char* apex_package_dir) {
1268   auto apexes = ScanApexFiles(apex_package_dir);
1269   if (!apexes.ok()) {
1270     return apexes.error();
1271   }
1272   return ActivateApexPackages(*apexes);
1273 }
1274 
1275 /**
1276  * Snapshots data from base_dir/apexdata/<apex name> to
1277  * base_dir/apexrollback/<rollback id>/<apex name>.
1278  */
snapshotDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1279 Result<void> snapshotDataDirectory(const std::string& base_dir,
1280                                    const int rollback_id,
1281                                    const std::string& apex_name,
1282                                    bool pre_restore = false) {
1283   auto rollback_path =
1284       StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1285                    rollback_id, pre_restore ? kPreRestoreSuffix : "");
1286   const Result<void> result = createDirIfNeeded(rollback_path, 0700);
1287   if (!result.ok()) {
1288     return Error() << "Failed to create snapshot directory for rollback "
1289                    << rollback_id << " : " << result.error();
1290   }
1291   auto from_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1292                                 apex_name.c_str());
1293   auto to_path =
1294       StringPrintf("%s/%s", rollback_path.c_str(), apex_name.c_str());
1295 
1296   return ReplaceFiles(from_path, to_path);
1297 }
1298 
1299 /**
1300  * Restores snapshot from base_dir/apexrollback/<rollback id>/<apex name>
1301  * to base_dir/apexdata/<apex name>.
1302  * Note the snapshot will be deleted after restoration succeeded.
1303  */
restoreDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1304 Result<void> restoreDataDirectory(const std::string& base_dir,
1305                                   const int rollback_id,
1306                                   const std::string& apex_name,
1307                                   bool pre_restore = false) {
1308   auto from_path = StringPrintf(
1309       "%s/%s/%d%s/%s", base_dir.c_str(), kApexSnapshotSubDir, rollback_id,
1310       pre_restore ? kPreRestoreSuffix : "", apex_name.c_str());
1311   auto to_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1312                               apex_name.c_str());
1313   Result<void> result = ReplaceFiles(from_path, to_path);
1314   if (!result.ok()) {
1315     return result;
1316   }
1317   result = RestoreconPath(to_path);
1318   if (!result.ok()) {
1319     return result;
1320   }
1321   result = DeleteDir(from_path);
1322   if (!result.ok()) {
1323     LOG(ERROR) << "Failed to delete the snapshot: " << result.error();
1324   }
1325   return {};
1326 }
1327 
snapshotOrRestoreDeIfNeeded(const std::string & base_dir,const ApexSession & session)1328 void snapshotOrRestoreDeIfNeeded(const std::string& base_dir,
1329                                  const ApexSession& session) {
1330   if (session.HasRollbackEnabled()) {
1331     for (const auto& apex_name : session.GetApexNames()) {
1332       Result<void> result =
1333           snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1334       if (!result.ok()) {
1335         LOG(ERROR) << "Snapshot failed for " << apex_name << ": "
1336                    << result.error();
1337       }
1338     }
1339   } else if (session.IsRollback()) {
1340     for (const auto& apex_name : session.GetApexNames()) {
1341       if (!gInFsCheckpointMode) {
1342         // Snapshot before restore so this rollback can be reverted.
1343         snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name,
1344                               true /* pre_restore */);
1345       }
1346       Result<void> result =
1347           restoreDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1348       if (!result.ok()) {
1349         LOG(ERROR) << "Restore of data failed for " << apex_name << ": "
1350                    << result.error();
1351       }
1352     }
1353   }
1354 }
1355 
snapshotOrRestoreDeSysData()1356 void snapshotOrRestoreDeSysData() {
1357   auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1358 
1359   for (const ApexSession& session : sessions) {
1360     snapshotOrRestoreDeIfNeeded(kDeSysDataDir, session);
1361   }
1362 }
1363 
snapshotOrRestoreDeUserData()1364 int snapshotOrRestoreDeUserData() {
1365   auto user_dirs = GetDeUserDirs();
1366 
1367   if (!user_dirs.ok()) {
1368     LOG(ERROR) << "Error reading dirs " << user_dirs.error();
1369     return 1;
1370   }
1371 
1372   auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1373 
1374   for (const ApexSession& session : sessions) {
1375     for (const auto& user_dir : *user_dirs) {
1376       snapshotOrRestoreDeIfNeeded(user_dir, session);
1377     }
1378   }
1379 
1380   return 0;
1381 }
1382 
snapshotCeData(const int user_id,const int rollback_id,const std::string & apex_name)1383 Result<ino_t> snapshotCeData(const int user_id, const int rollback_id,
1384                              const std::string& apex_name) {
1385   auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1386   Result<void> result = snapshotDataDirectory(base_dir, rollback_id, apex_name);
1387   if (!result.ok()) {
1388     return result.error();
1389   }
1390   auto ce_snapshot_path =
1391       StringPrintf("%s/%s/%d/%s", base_dir.c_str(), kApexSnapshotSubDir,
1392                    rollback_id, apex_name.c_str());
1393   return get_path_inode(ce_snapshot_path);
1394 }
1395 
restoreCeData(const int user_id,const int rollback_id,const std::string & apex_name)1396 Result<void> restoreCeData(const int user_id, const int rollback_id,
1397                            const std::string& apex_name) {
1398   auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1399   return restoreDataDirectory(base_dir, rollback_id, apex_name);
1400 }
1401 
1402 //  Migrates sessions directory from /data/apex/sessions to
1403 //  /metadata/apex/sessions, if necessary.
migrateSessionsDirIfNeeded()1404 Result<void> migrateSessionsDirIfNeeded() {
1405   namespace fs = std::filesystem;
1406   auto from_path = std::string(kApexDataDir) + "/sessions";
1407   auto exists = PathExists(from_path);
1408   if (!exists.ok()) {
1409     return Error() << "Failed to access " << from_path << ": "
1410                    << exists.error();
1411   }
1412   if (!*exists) {
1413     LOG(DEBUG) << from_path << " does not exist. Nothing to migrate.";
1414     return {};
1415   }
1416   auto to_path = kApexSessionsDir;
1417   std::error_code error_code;
1418   fs::copy(from_path, to_path, fs::copy_options::recursive, error_code);
1419   if (error_code) {
1420     return Error() << "Failed to copy old sessions directory"
1421                    << error_code.message();
1422   }
1423   fs::remove_all(from_path, error_code);
1424   if (error_code) {
1425     return Error() << "Failed to delete old sessions directory "
1426                    << error_code.message();
1427   }
1428   return {};
1429 }
1430 
destroySnapshots(const std::string & base_dir,const int rollback_id)1431 Result<void> destroySnapshots(const std::string& base_dir,
1432                               const int rollback_id) {
1433   auto path = StringPrintf("%s/%s/%d", base_dir.c_str(), kApexSnapshotSubDir,
1434                            rollback_id);
1435   return DeleteDir(path);
1436 }
1437 
destroyDeSnapshots(const int rollback_id)1438 Result<void> destroyDeSnapshots(const int rollback_id) {
1439   destroySnapshots(kDeSysDataDir, rollback_id);
1440 
1441   auto user_dirs = GetDeUserDirs();
1442   if (!user_dirs.ok()) {
1443     return Error() << "Error reading user dirs " << user_dirs.error();
1444   }
1445 
1446   for (const auto& user_dir : *user_dirs) {
1447     destroySnapshots(user_dir, rollback_id);
1448   }
1449 
1450   return {};
1451 }
1452 
restorePreRestoreSnapshotsIfPresent(const std::string & base_dir,const ApexSession & session)1453 void restorePreRestoreSnapshotsIfPresent(const std::string& base_dir,
1454                                          const ApexSession& session) {
1455   auto pre_restore_snapshot_path =
1456       StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1457                    session.GetRollbackId(), kPreRestoreSuffix);
1458   if (PathExists(pre_restore_snapshot_path)) {
1459     for (const auto& apex_name : session.GetApexNames()) {
1460       Result<void> result = restoreDataDirectory(
1461           base_dir, session.GetRollbackId(), apex_name, true /* pre_restore */);
1462       if (!result) {
1463         LOG(ERROR) << "Restore of pre-restore snapshot failed for " << apex_name
1464                    << ": " << result.error();
1465       }
1466     }
1467 
1468     Result<void> result = DeleteDir(pre_restore_snapshot_path);
1469     if (!result) {
1470       LOG(ERROR) << "Deletion of pre-restore snapshot failed: "
1471                  << result.error();
1472     }
1473   }
1474 }
1475 
restoreDePreRestoreSnapshotsIfPresent(const ApexSession & session)1476 void restoreDePreRestoreSnapshotsIfPresent(const ApexSession& session) {
1477   restorePreRestoreSnapshotsIfPresent(kDeSysDataDir, session);
1478 
1479   auto user_dirs = GetDeUserDirs();
1480   if (!user_dirs) {
1481     LOG(ERROR) << "Error reading user dirs to restore pre-restore snapshots"
1482                << user_dirs.error();
1483   }
1484 
1485   for (const auto& user_dir : *user_dirs) {
1486     restorePreRestoreSnapshotsIfPresent(user_dir, session);
1487   }
1488 }
1489 
deleteDePreRestoreSnapshots(const std::string & base_dir,const ApexSession & session)1490 void deleteDePreRestoreSnapshots(const std::string& base_dir,
1491                                  const ApexSession& session) {
1492   auto pre_restore_snapshot_path =
1493       StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1494                    session.GetRollbackId(), kPreRestoreSuffix);
1495   Result<void> result = DeleteDir(pre_restore_snapshot_path);
1496   if (!result) {
1497     LOG(ERROR) << "Deletion of pre-restore snapshot failed: " << result.error();
1498   }
1499 }
1500 
deleteDePreRestoreSnapshots(const ApexSession & session)1501 void deleteDePreRestoreSnapshots(const ApexSession& session) {
1502   deleteDePreRestoreSnapshots(kDeSysDataDir, session);
1503 
1504   auto user_dirs = GetDeUserDirs();
1505   if (!user_dirs) {
1506     LOG(ERROR) << "Error reading user dirs to delete pre-restore snapshots"
1507                << user_dirs.error();
1508   }
1509 
1510   for (const auto& user_dir : *user_dirs) {
1511     deleteDePreRestoreSnapshots(user_dir, session);
1512   }
1513 }
1514 
1515 /**
1516  * Deletes all credential-encrypted snapshots for the given user, except for
1517  * those listed in retain_rollback_ids.
1518  */
destroyCeSnapshotsNotSpecified(int user_id,const std::vector<int> & retain_rollback_ids)1519 Result<void> destroyCeSnapshotsNotSpecified(
1520     int user_id, const std::vector<int>& retain_rollback_ids) {
1521   auto snapshot_root =
1522       StringPrintf("%s/%d/%s", kCeDataDir, user_id, kApexSnapshotSubDir);
1523   auto snapshot_dirs = GetSubdirs(snapshot_root);
1524   if (!snapshot_dirs) {
1525     return Error() << "Error reading snapshot dirs " << snapshot_dirs.error();
1526   }
1527 
1528   for (const auto& snapshot_dir : *snapshot_dirs) {
1529     uint snapshot_id;
1530     bool parse_ok = ParseUint(
1531         std::filesystem::path(snapshot_dir).filename().c_str(), &snapshot_id);
1532     if (parse_ok &&
1533         std::find(retain_rollback_ids.begin(), retain_rollback_ids.end(),
1534                   snapshot_id) == retain_rollback_ids.end()) {
1535       Result<void> result = DeleteDir(snapshot_dir);
1536       if (!result) {
1537         return Error() << "Destroy CE snapshot failed for " << snapshot_dir
1538                        << " : " << result.error();
1539       }
1540     }
1541   }
1542   return {};
1543 }
1544 
scanStagedSessionsDirAndStage()1545 void scanStagedSessionsDirAndStage() {
1546   LOG(INFO) << "Scanning " << kApexSessionsDir
1547             << " looking for sessions to be activated.";
1548 
1549   auto sessionsToActivate =
1550       ApexSession::GetSessionsInState(SessionState::STAGED);
1551   if (gSupportsFsCheckpoints) {
1552     // A session that is in the ACTIVATED state should still be re-activated if
1553     // fs checkpointing is supported. In this case, a session may be in the
1554     // ACTIVATED state yet the data/apex/active directory may have been
1555     // reverted. The session should be reverted in this scenario.
1556     auto activatedSessions =
1557         ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1558     sessionsToActivate.insert(sessionsToActivate.end(),
1559                               activatedSessions.begin(),
1560                               activatedSessions.end());
1561   }
1562 
1563   for (auto& session : sessionsToActivate) {
1564     auto sessionId = session.GetId();
1565 
1566     auto session_failed_fn = [&]() {
1567       LOG(WARNING) << "Marking session " << sessionId << " as failed.";
1568       auto st = session.UpdateStateAndCommit(SessionState::ACTIVATION_FAILED);
1569       if (!st.ok()) {
1570         LOG(WARNING) << "Failed to mark session " << sessionId
1571                      << " as failed : " << st.error();
1572       }
1573     };
1574     auto scope_guard = android::base::make_scope_guard(session_failed_fn);
1575 
1576     std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
1577     if (session.GetBuildFingerprint().compare(build_fingerprint) != 0) {
1578       LOG(ERROR) << "APEX build fingerprint has changed";
1579       continue;
1580     }
1581 
1582     std::vector<std::string> dirsToScan;
1583     if (session.GetChildSessionIds().empty()) {
1584       dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1585                            std::to_string(sessionId));
1586     } else {
1587       for (auto childSessionId : session.GetChildSessionIds()) {
1588         dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1589                              std::to_string(childSessionId));
1590       }
1591     }
1592 
1593     std::vector<std::string> apexes;
1594     bool scanSuccessful = true;
1595     for (const auto& dirToScan : dirsToScan) {
1596       Result<std::vector<std::string>> scan = FindApexFilesByName(dirToScan);
1597       if (!scan.ok()) {
1598         LOG(WARNING) << scan.error();
1599         scanSuccessful = false;
1600         break;
1601       }
1602 
1603       if (scan->size() > 1) {
1604         LOG(WARNING) << "More than one APEX package found in the same session "
1605                      << "directory " << dirToScan << ", skipping activation.";
1606         scanSuccessful = false;
1607         break;
1608       }
1609 
1610       if (scan->empty()) {
1611         LOG(WARNING) << "No APEX packages found while scanning " << dirToScan
1612                      << " session id: " << sessionId << ".";
1613         scanSuccessful = false;
1614         break;
1615       }
1616       apexes.push_back(std::move((*scan)[0]));
1617     }
1618 
1619     if (!scanSuccessful) {
1620       continue;
1621     }
1622 
1623     // Run postinstall, if necessary.
1624     Result<void> postinstall_status = postinstallPackages(apexes);
1625     if (!postinstall_status.ok()) {
1626       LOG(ERROR) << "Postinstall failed for session "
1627                  << std::to_string(sessionId) << ": "
1628                  << postinstall_status.error();
1629       continue;
1630     }
1631 
1632     for (const auto& apex : apexes) {
1633       // TODO(b/158470836): Avoid opening ApexFile repeatedly.
1634       Result<ApexFile> apex_file = ApexFile::Open(apex);
1635       if (!apex_file.ok()) {
1636         LOG(ERROR) << "Cannot open apex file during staging: " << apex;
1637         continue;
1638       }
1639       session.AddApexName(apex_file->GetManifest().name());
1640     }
1641 
1642     const Result<void> result = stagePackages(apexes);
1643     if (!result.ok()) {
1644       LOG(ERROR) << "Activation failed for packages " << Join(apexes, ',')
1645                  << ": " << result.error();
1646       continue;
1647     }
1648 
1649     // Session was OK, release scopeguard.
1650     scope_guard.Disable();
1651 
1652     auto st = session.UpdateStateAndCommit(SessionState::ACTIVATED);
1653     if (!st.ok()) {
1654       LOG(ERROR) << "Failed to mark " << session
1655                  << " as activated : " << st.error();
1656     }
1657   }
1658 }
1659 
preinstallPackages(const std::vector<std::string> & paths)1660 Result<void> preinstallPackages(const std::vector<std::string>& paths) {
1661   Result<std::vector<ApexFile>> apex_files = OpenApexFiles(paths);
1662   if (!apex_files.ok()) {
1663     return apex_files.error();
1664   }
1665   LOG(DEBUG) << "preinstallPackages() for " << Join(paths, ',');
1666   return PreinstallPackages(*apex_files);
1667 }
1668 
postinstallPackages(const std::vector<std::string> & paths)1669 Result<void> postinstallPackages(const std::vector<std::string>& paths) {
1670   Result<std::vector<ApexFile>> apex_files = OpenApexFiles(paths);
1671   if (!apex_files.ok()) {
1672     return apex_files.error();
1673   }
1674   LOG(DEBUG) << "postinstallPackages() for " << Join(paths, ',');
1675   return PostinstallPackages(*apex_files);
1676 }
1677 
1678 namespace {
StageDestPath(const ApexFile & apex_file)1679 std::string StageDestPath(const ApexFile& apex_file) {
1680   return StringPrintf("%s/%s%s", kActiveApexPackagesDataDir,
1681                       GetPackageId(apex_file.GetManifest()).c_str(),
1682                       kApexPackageSuffix);
1683 }
1684 
1685 }  // namespace
1686 
stagePackages(const std::vector<std::string> & tmpPaths)1687 Result<void> stagePackages(const std::vector<std::string>& tmpPaths) {
1688   if (tmpPaths.empty()) {
1689     return Errorf("Empty set of inputs");
1690   }
1691   LOG(DEBUG) << "stagePackages() for " << Join(tmpPaths, ',');
1692 
1693   // Note: this function is temporary. As such the code is not optimized, e.g.,
1694   //       it will open ApexFiles multiple times.
1695 
1696   // 1) Verify all packages.
1697   auto verify_status = verifyPackages(tmpPaths, VerifyPackageBoot);
1698   if (!verify_status.ok()) {
1699     return verify_status.error();
1700   }
1701 
1702   // Make sure that kActiveApexPackagesDataDir exists.
1703   auto create_dir_status =
1704       createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755);
1705   if (!create_dir_status.ok()) {
1706     return create_dir_status.error();
1707   }
1708 
1709   // 2) Now stage all of them.
1710 
1711   // Ensure the APEX gets removed on failure.
1712   std::unordered_set<std::string> staged_files;
1713   std::vector<std::string> changed_hashtree_files;
1714   auto deleter = [&staged_files, &changed_hashtree_files]() {
1715     for (const std::string& staged_path : staged_files) {
1716       if (TEMP_FAILURE_RETRY(unlink(staged_path.c_str())) != 0) {
1717         PLOG(ERROR) << "Unable to unlink " << staged_path;
1718       }
1719     }
1720     for (const std::string& hashtree_file : changed_hashtree_files) {
1721       if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
1722         PLOG(ERROR) << "Unable to unlink " << hashtree_file;
1723       }
1724     }
1725   };
1726   auto scope_guard = android::base::make_scope_guard(deleter);
1727 
1728   std::unordered_set<std::string> staged_packages;
1729   for (const std::string& path : tmpPaths) {
1730     Result<ApexFile> apex_file = ApexFile::Open(path);
1731     if (!apex_file.ok()) {
1732       return apex_file.error();
1733     }
1734     // First promote new hashtree file to the one that will be used when
1735     // mounting apex.
1736     std::string new_hashtree_file = GetHashTreeFileName(*apex_file,
1737                                                         /* is_new = */ true);
1738     std::string old_hashtree_file = GetHashTreeFileName(*apex_file,
1739                                                         /* is_new = */ false);
1740     if (access(new_hashtree_file.c_str(), F_OK) == 0) {
1741       if (TEMP_FAILURE_RETRY(rename(new_hashtree_file.c_str(),
1742                                     old_hashtree_file.c_str())) != 0) {
1743         return ErrnoError() << "Failed to move " << new_hashtree_file << " to "
1744                             << old_hashtree_file;
1745       }
1746       changed_hashtree_files.emplace_back(std::move(old_hashtree_file));
1747     }
1748     // And only then move apex to /data/apex/active.
1749     std::string dest_path = StageDestPath(*apex_file);
1750     if (access(dest_path.c_str(), F_OK) == 0) {
1751       LOG(DEBUG) << dest_path << " already exists. Deleting";
1752       if (TEMP_FAILURE_RETRY(unlink(dest_path.c_str())) != 0) {
1753         return ErrnoError() << "Failed to unlink " << dest_path;
1754       }
1755     }
1756 
1757     if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
1758       return ErrnoError() << "Unable to link " << apex_file->GetPath() << " to "
1759                           << dest_path;
1760     }
1761     staged_files.insert(dest_path);
1762     staged_packages.insert(apex_file->GetManifest().name());
1763 
1764     LOG(DEBUG) << "Success linking " << apex_file->GetPath() << " to "
1765                << dest_path;
1766   }
1767 
1768   scope_guard.Disable();  // Accept the state.
1769 
1770   return RemovePreviouslyActiveApexFiles(staged_packages, staged_files);
1771 }
1772 
unstagePackages(const std::vector<std::string> & paths)1773 Result<void> unstagePackages(const std::vector<std::string>& paths) {
1774   if (paths.empty()) {
1775     return Errorf("Empty set of inputs");
1776   }
1777   LOG(DEBUG) << "unstagePackages() for " << Join(paths, ',');
1778 
1779   for (const std::string& path : paths) {
1780     if (isPathForBuiltinApexes(path)) {
1781       return Error() << "Can't uninstall pre-installed apex " << path;
1782     }
1783     if (access(path.c_str(), F_OK) != 0) {
1784       return ErrnoError() << "Can't access " << path;
1785     }
1786   }
1787 
1788   for (const std::string& path : paths) {
1789     if (unlink(path.c_str()) != 0) {
1790       return ErrnoError() << "Can't unlink " << path;
1791     }
1792   }
1793 
1794   return {};
1795 }
1796 
1797 /**
1798  * During apex installation, staged sessions located in /data/apex/sessions
1799  * mutate the active sessions in /data/apex/active. If some error occurs during
1800  * installation of apex, we need to revert /data/apex/active to its original
1801  * state and reboot.
1802  *
1803  * Also, we need to put staged sessions in /data/apex/sessions in REVERTED state
1804  * so that they do not get activated on next reboot.
1805  */
revertActiveSessions(const std::string & crashing_native_process)1806 Result<void> revertActiveSessions(const std::string& crashing_native_process) {
1807   // First check whenever there is anything to revert. If there is none, then
1808   // fail. This prevents apexd from boot looping a device in case a native
1809   // process is crashing and there are no apex updates.
1810   auto activeSessions = ApexSession::GetActiveSessions();
1811   if (activeSessions.empty()) {
1812     return Error() << "Revert requested, when there are no active sessions.";
1813   }
1814 
1815   for (auto& session : activeSessions) {
1816     if (!crashing_native_process.empty()) {
1817       session.SetCrashingNativeProcess(crashing_native_process);
1818     }
1819     auto status =
1820         session.UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS);
1821     if (!status) {
1822       return Error() << "Revert of session " << session
1823                      << " failed : " << status.error();
1824     }
1825   }
1826 
1827   if (!gInFsCheckpointMode) {
1828     auto restoreStatus = RestoreActivePackages();
1829     if (!restoreStatus.ok()) {
1830       for (auto& session : activeSessions) {
1831         auto st = session.UpdateStateAndCommit(SessionState::REVERT_FAILED);
1832         LOG(DEBUG) << "Marking " << session << " as failed to revert";
1833         if (!st) {
1834           LOG(WARNING) << "Failed to mark session " << session
1835                        << " as failed to revert : " << st.error();
1836         }
1837       }
1838       return restoreStatus;
1839     }
1840   } else {
1841     LOG(INFO) << "Not restoring active packages in checkpoint mode.";
1842   }
1843 
1844   for (auto& session : activeSessions) {
1845     if (!gInFsCheckpointMode && session.IsRollback()) {
1846       // If snapshots have already been restored, undo that by restoring the
1847       // pre-restore snapshot.
1848       restoreDePreRestoreSnapshotsIfPresent(session);
1849     }
1850 
1851     auto status = session.UpdateStateAndCommit(SessionState::REVERTED);
1852     if (!status) {
1853       LOG(WARNING) << "Failed to mark session " << session
1854                    << " as reverted : " << status.error();
1855     }
1856   }
1857 
1858   return {};
1859 }
1860 
revertActiveSessionsAndReboot(const std::string & crashing_native_process)1861 Result<void> revertActiveSessionsAndReboot(
1862     const std::string& crashing_native_process) {
1863   auto status = revertActiveSessions(crashing_native_process);
1864   if (!status) {
1865     return status;
1866   }
1867   LOG(ERROR) << "Successfully reverted. Time to reboot device.";
1868   if (gInFsCheckpointMode) {
1869     Result<void> res = gVoldService->AbortChanges(
1870         "apexd_initiated" /* message */, false /* retry */);
1871     if (!res.ok()) {
1872       LOG(ERROR) << res.error();
1873     }
1874   }
1875   Reboot();
1876   return {};
1877 }
1878 
onBootstrap()1879 int onBootstrap() {
1880   gBootstrap = true;
1881 
1882   Result<void> preAllocate = preAllocateLoopDevices();
1883   if (!preAllocate.ok()) {
1884     LOG(ERROR) << "Failed to pre-allocate loop devices : "
1885                << preAllocate.error();
1886   }
1887 
1888   std::vector<std::string> bootstrap_apex_dirs{
1889       kApexPackageSystemDir, kApexPackageSystemExtDir, kApexPackageVendorDir};
1890   Result<void> status = collectPreinstalledData(bootstrap_apex_dirs);
1891   if (!status.ok()) {
1892     LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1893     return 1;
1894   }
1895 
1896   // Activate built-in APEXes for processes launched before /data is mounted.
1897   for (const auto& dir : bootstrap_apex_dirs) {
1898     auto scan_status = ScanApexFiles(dir.c_str());
1899     if (!scan_status.ok()) {
1900       LOG(ERROR) << "Failed to scan APEX files in " << dir << " : "
1901                  << scan_status.error();
1902       return 1;
1903     }
1904     if (auto ret = ActivateApexPackages(*scan_status); !ret.ok()) {
1905       LOG(ERROR) << "Failed to activate APEX files in " << dir << " : "
1906                  << ret.error();
1907       return 1;
1908     }
1909   }
1910 
1911   onAllPackagesActivated();
1912   LOG(INFO) << "Bootstrapping done";
1913   return 0;
1914 }
1915 
remountApexFile(const std::string & path)1916 Result<void> remountApexFile(const std::string& path) {
1917   if (auto ret = deactivatePackage(path); !ret.ok()) {
1918     return ret;
1919   }
1920   return activatePackage(path);
1921 }
1922 
initializeVold(CheckpointInterface * checkpoint_service)1923 void initializeVold(CheckpointInterface* checkpoint_service) {
1924   if (checkpoint_service != nullptr) {
1925     gVoldService = checkpoint_service;
1926     Result<bool> supports_fs_checkpoints =
1927         gVoldService->SupportsFsCheckpoints();
1928     if (supports_fs_checkpoints.ok()) {
1929       gSupportsFsCheckpoints = *supports_fs_checkpoints;
1930     } else {
1931       LOG(ERROR) << "Failed to check if filesystem checkpoints are supported: "
1932                  << supports_fs_checkpoints.error();
1933     }
1934     if (gSupportsFsCheckpoints) {
1935       Result<bool> needs_checkpoint = gVoldService->NeedsCheckpoint();
1936       if (needs_checkpoint.ok()) {
1937         gInFsCheckpointMode = *needs_checkpoint;
1938       } else {
1939         LOG(ERROR) << "Failed to check if we're in filesystem checkpoint mode: "
1940                    << needs_checkpoint.error();
1941       }
1942     }
1943   }
1944 }
1945 
initialize(CheckpointInterface * checkpoint_service)1946 void initialize(CheckpointInterface* checkpoint_service) {
1947   initializeVold(checkpoint_service);
1948   Result<void> status = collectPreinstalledData(kApexPackageBuiltinDirs);
1949   if (!status.ok()) {
1950     LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1951     return;
1952   }
1953 
1954   gMountedApexes.PopulateFromMounts();
1955 }
1956 
onStart()1957 void onStart() {
1958   LOG(INFO) << "Marking APEXd as starting";
1959   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusStarting)) {
1960     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1961                 << kApexStatusStarting;
1962   }
1963 
1964   // Ask whether we should revert any active sessions; this can happen if
1965   // we've exceeded the retry count on a device that supports filesystem
1966   // checkpointing.
1967   if (gSupportsFsCheckpoints) {
1968     Result<bool> needs_revert = gVoldService->NeedsRollback();
1969     if (!needs_revert) {
1970       LOG(ERROR) << "Failed to check if we need a revert: "
1971                  << needs_revert.error();
1972     } else if (*needs_revert) {
1973       LOG(INFO) << "Exceeded number of session retries ("
1974                 << kNumRetriesWhenCheckpointingEnabled
1975                 << "). Starting a revert";
1976       Result<void> status = revertActiveSessions("");
1977       if (!status) {
1978         LOG(ERROR) << "Failed to revert (as requested by fs checkpointing) : "
1979                    << status.error();
1980       }
1981     }
1982   }
1983 
1984   // Activate APEXes from /data/apex. If one in the directory is newer than the
1985   // system one, the new one will eclipse the old one.
1986   scanStagedSessionsDirAndStage();
1987   auto status = resumeRevertIfNeeded();
1988   if (!status.ok()) {
1989     LOG(ERROR) << "Failed to resume revert : " << status.error();
1990   }
1991 
1992   std::vector<ApexFile> data_apex;
1993   if (auto scan = ScanApexFiles(kActiveApexPackagesDataDir); !scan.ok()) {
1994     LOG(ERROR) << "Failed to scan packages from " << kActiveApexPackagesDataDir
1995                << " : " << scan.error();
1996     if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
1997       LOG(ERROR) << "Failed to revert : " << revert.error();
1998     }
1999   } else {
2000     auto filter_fn = [](const ApexFile& apex) {
2001       if (!ShouldActivateApexOnData(apex)) {
2002         LOG(WARNING) << "Skipping " << apex.GetPath();
2003         return false;
2004       }
2005       return true;
2006     };
2007     std::copy_if(std::make_move_iterator(scan->begin()),
2008                  std::make_move_iterator(scan->end()),
2009                  std::back_inserter(data_apex), filter_fn);
2010   }
2011 
2012   if (auto ret = ActivateApexPackages(data_apex); !ret.ok()) {
2013     LOG(ERROR) << "Failed to activate packages from "
2014                << kActiveApexPackagesDataDir << " : " << ret.error();
2015     if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
2016       LOG(ERROR) << "Failed to revert : " << revert.error();
2017     }
2018   }
2019 
2020   // Now also scan and activate APEXes from pre-installed directories.
2021   for (const auto& dir : kApexPackageBuiltinDirs) {
2022     // TODO(b/123622800): if activation failed, revert and reboot.
2023     status = scanPackagesDirAndActivate(dir.c_str());
2024     if (!status) {
2025       // This should never happen. Like **really** never.
2026       LOG(ERROR) << "Failed to activate packages from " << dir << " : "
2027                  << status.error();
2028     }
2029   }
2030 
2031   // Now that APEXes are mounted, snapshot or restore DE_sys data.
2032   snapshotOrRestoreDeSysData();
2033 }
2034 
onAllPackagesActivated()2035 void onAllPackagesActivated() {
2036   auto result = emitApexInfoList();
2037   if (!result.ok()) {
2038     LOG(ERROR) << "cannot emit apex info list: " << result.error();
2039   }
2040 
2041   // Because apexd in bootstrap mode runs in blocking mode
2042   // we don't have to set as activated.
2043   if (gBootstrap) {
2044     return;
2045   }
2046 
2047   // Set a system property to let other components know that APEXs are
2048   // activated, but are not yet ready to be used. init is expected to wait
2049   // for this status before performing configuration based on activated
2050   // apexes. Other components that need to use APEXs should wait for the
2051   // ready state instead.
2052   LOG(INFO) << "Marking APEXd as activated";
2053   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusActivated)) {
2054     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
2055                 << kApexStatusActivated;
2056   }
2057 }
2058 
onAllPackagesReady()2059 void onAllPackagesReady() {
2060   // Set a system property to let other components know that APEXs are
2061   // correctly mounted and ready to be used. Before using any file from APEXs,
2062   // they can query this system property to ensure that they are okay to
2063   // access. Or they may have a on-property trigger to delay a task until
2064   // APEXs become ready.
2065   LOG(INFO) << "Marking APEXd as ready";
2066   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusReady)) {
2067     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
2068                 << kApexStatusReady;
2069   }
2070 }
2071 
submitStagedSession(const int session_id,const std::vector<int> & child_session_ids,const bool has_rollback_enabled,const bool is_rollback,const int rollback_id)2072 Result<std::vector<ApexFile>> submitStagedSession(
2073     const int session_id, const std::vector<int>& child_session_ids,
2074     const bool has_rollback_enabled, const bool is_rollback,
2075     const int rollback_id) {
2076   if (session_id == 0) {
2077     return Error() << "Session id was not provided.";
2078   }
2079 
2080   if (!gSupportsFsCheckpoints) {
2081     Result<void> backup_status = BackupActivePackages();
2082     if (!backup_status) {
2083       // Do not proceed with staged install without backup
2084       return backup_status.error();
2085     }
2086   }
2087 
2088   std::vector<int> ids_to_scan;
2089   if (!child_session_ids.empty()) {
2090     ids_to_scan = child_session_ids;
2091   } else {
2092     ids_to_scan = {session_id};
2093   }
2094 
2095   std::vector<ApexFile> ret;
2096   for (int id_to_scan : ids_to_scan) {
2097     auto verified = verifySessionDir(id_to_scan);
2098     if (!verified.ok()) {
2099       return verified.error();
2100     }
2101     ret.push_back(std::move(*verified));
2102   }
2103 
2104   // Run preinstall, if necessary.
2105   Result<void> preinstall_status = PreinstallPackages(ret);
2106   if (!preinstall_status.ok()) {
2107     return preinstall_status.error();
2108   }
2109 
2110   if (has_rollback_enabled && is_rollback) {
2111     return Error() << "Cannot set session " << session_id << " as both a"
2112                    << " rollback and enabled for rollback.";
2113   }
2114 
2115   auto session = ApexSession::CreateSession(session_id);
2116   if (!session.ok()) {
2117     return session.error();
2118   }
2119   (*session).SetChildSessionIds(child_session_ids);
2120   std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
2121   (*session).SetBuildFingerprint(build_fingerprint);
2122   session->SetHasRollbackEnabled(has_rollback_enabled);
2123   session->SetIsRollback(is_rollback);
2124   session->SetRollbackId(rollback_id);
2125   Result<void> commit_status =
2126       (*session).UpdateStateAndCommit(SessionState::VERIFIED);
2127   if (!commit_status.ok()) {
2128     return commit_status.error();
2129   }
2130 
2131   return ret;
2132 }
2133 
markStagedSessionReady(const int session_id)2134 Result<void> markStagedSessionReady(const int session_id) {
2135   auto session = ApexSession::GetSession(session_id);
2136   if (!session.ok()) {
2137     return session.error();
2138   }
2139   // We should only accept sessions in SessionState::VERIFIED or
2140   // SessionState::STAGED state. In the SessionState::STAGED case, this
2141   // function is effectively a no-op.
2142   auto session_state = (*session).GetState();
2143   if (session_state == SessionState::STAGED) {
2144     return {};
2145   }
2146   if (session_state == SessionState::VERIFIED) {
2147     return (*session).UpdateStateAndCommit(SessionState::STAGED);
2148   }
2149   return Error() << "Invalid state for session " << session_id
2150                  << ". Cannot mark it as ready.";
2151 }
2152 
markStagedSessionSuccessful(const int session_id)2153 Result<void> markStagedSessionSuccessful(const int session_id) {
2154   auto session = ApexSession::GetSession(session_id);
2155   if (!session.ok()) {
2156     return session.error();
2157   }
2158   // Only SessionState::ACTIVATED or SessionState::SUCCESS states are accepted.
2159   // In the SessionState::SUCCESS state, this function is a no-op.
2160   if (session->GetState() == SessionState::SUCCESS) {
2161     return {};
2162   } else if (session->GetState() == SessionState::ACTIVATED) {
2163     auto cleanup_status = DeleteBackup();
2164     if (!cleanup_status.ok()) {
2165       return Error() << "Failed to mark session " << *session
2166                      << " as successful : " << cleanup_status.error();
2167     }
2168     if (session->IsRollback() && !gInFsCheckpointMode) {
2169       deleteDePreRestoreSnapshots(*session);
2170     }
2171     return session->UpdateStateAndCommit(SessionState::SUCCESS);
2172   } else {
2173     return Error() << "Session " << *session << " can not be marked successful";
2174   }
2175 }
2176 
2177 namespace {
2178 
2179 // Find dangling mounts and unmount them.
2180 // If one is on /data/apex/active, remove it.
UnmountDanglingMounts()2181 void UnmountDanglingMounts() {
2182   std::multimap<std::string, MountedApexData> danglings;
2183   gMountedApexes.ForallMountedApexes([&](const std::string& package,
2184                                          const MountedApexData& data,
2185                                          bool latest) {
2186     if (!latest) {
2187       danglings.insert({package, data});
2188     }
2189   });
2190 
2191   for (const auto& [package, data] : danglings) {
2192     const std::string& path = data.full_path;
2193     LOG(VERBOSE) << "Unmounting " << data.mount_point;
2194     gMountedApexes.RemoveMountedApex(package, path);
2195     if (auto st = Unmount(data); !st.ok()) {
2196       LOG(ERROR) << st.error();
2197     }
2198     if (StartsWith(path, kActiveApexPackagesDataDir)) {
2199       LOG(VERBOSE) << "Deleting old APEX " << path;
2200       if (unlink(path.c_str()) != 0) {
2201         PLOG(ERROR) << "Failed to delete " << path;
2202       }
2203     }
2204   }
2205 
2206   RemoveObsoleteHashTrees();
2207 }
2208 
2209 // Removes APEXes on /data that don't have corresponding pre-installed version
2210 // or that are corrupt
RemoveOrphanedApexes()2211 void RemoveOrphanedApexes() {
2212   auto data_apexes = FindApexFilesByName(kActiveApexPackagesDataDir);
2213   if (!data_apexes.ok()) {
2214     LOG(ERROR) << "Failed to scan " << kActiveApexPackagesDataDir << " : "
2215                << data_apexes.error();
2216     return;
2217   }
2218   for (const auto& path : *data_apexes) {
2219     auto apex = ApexFile::Open(path);
2220     if (!apex.ok()) {
2221       LOG(DEBUG) << "Failed to open APEX " << path << " : " << apex.error();
2222       // before removing, double-check if the path is active or not
2223       // just in case ApexFile::Open() fails with valid APEX
2224       if (!apexd_private::IsMounted(path)) {
2225         LOG(DEBUG) << "Removing corrupt APEX " << path;
2226         if (unlink(path.c_str()) != 0) {
2227           PLOG(ERROR) << "Failed to unlink " << path;
2228         }
2229       }
2230       continue;
2231     }
2232     if (!ShouldActivateApexOnData(*apex)) {
2233       LOG(DEBUG) << "Removing orphaned APEX " << path;
2234       if (unlink(path.c_str()) != 0) {
2235         PLOG(ERROR) << "Failed to unlink " << path;
2236       }
2237     }
2238   }
2239 }
2240 
2241 }  // namespace
2242 
bootCompletedCleanup()2243 void bootCompletedCleanup() {
2244   UnmountDanglingMounts();
2245   RemoveOrphanedApexes();
2246   ApexSession::DeleteFinalizedSessions();
2247 }
2248 
unmountAll()2249 int unmountAll() {
2250   gMountedApexes.PopulateFromMounts();
2251   int ret = 0;
2252   gMountedApexes.ForallMountedApexes([&](const std::string& /*package*/,
2253                                          const MountedApexData& data,
2254                                          bool latest) {
2255     LOG(INFO) << "Unmounting " << data.full_path << " mounted on "
2256               << data.mount_point;
2257     if (latest) {
2258       auto pos = data.mount_point.find('@');
2259       CHECK(pos != std::string::npos);
2260       std::string bind_mount = data.mount_point.substr(0, pos);
2261       if (umount2(bind_mount.c_str(), UMOUNT_NOFOLLOW) != 0) {
2262         PLOG(ERROR) << "Failed to unmount bind-mount " << bind_mount;
2263         ret = 1;
2264       }
2265     }
2266     if (auto status = Unmount(data); !status.ok()) {
2267       LOG(ERROR) << "Failed to unmount " << data.mount_point << " : "
2268                  << status.error();
2269       ret = 1;
2270     }
2271   });
2272   return ret;
2273 }
2274 
isBooting()2275 bool isBooting() {
2276   auto status = GetProperty(kApexStatusSysprop, "");
2277   return status != kApexStatusReady && status != kApexStatusActivated;
2278 }
2279 
remountPackages()2280 Result<void> remountPackages() {
2281   std::vector<std::string> apexes;
2282   gMountedApexes.ForallMountedApexes([&apexes](const std::string& /*package*/,
2283                                                const MountedApexData& data,
2284                                                bool latest) {
2285     if (latest) {
2286       LOG(DEBUG) << "Found active APEX " << data.full_path;
2287       apexes.push_back(data.full_path);
2288     }
2289   });
2290   std::vector<std::string> failed;
2291   for (const std::string& apex : apexes) {
2292     // Since this is only used during development workflow, we are trying to
2293     // remount as many apexes as possible instead of failing fast.
2294     if (auto ret = remountApexFile(apex); !ret) {
2295       LOG(WARNING) << "Failed to remount " << apex << " : " << ret.error();
2296       failed.emplace_back(apex);
2297     }
2298   }
2299   static constexpr const char* kErrorMessage =
2300       "Failed to remount following APEX packages, hence previous versions of "
2301       "them are still active. If APEX you are developing is in this list, it "
2302       "means that there still are alive processes holding a reference to the "
2303       "previous version of your APEX.\n";
2304   if (!failed.empty()) {
2305     return Error() << kErrorMessage << "Failed (" << failed.size() << ") "
2306                    << "APEX packages: [" << Join(failed, ',') << "]";
2307   }
2308   return {};
2309 }
2310 
2311 }  // namespace apex
2312 }  // namespace android
2313