• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2019 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 <sysexits.h>
18 #include <unistd.h>
19 #include <chrono>
20 #include <filesystem>
21 #include <fstream>
22 #include <future>
23 #include <iostream>
24 #include <map>
25 #include <sstream>
26 #include <thread>
27 
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 #include <android-base/unique_fd.h>
31 
32 #include <android-base/chrono_utils.h>
33 #include <android-base/hex.h>
34 #include <android-base/parseint.h>
35 #include <android-base/properties.h>
36 #include <android-base/scopeguard.h>
37 #include <android-base/stringprintf.h>
38 #include <android-base/strings.h>
39 #include <android/snapshot/snapshot.pb.h>
40 
41 #include <fs_avb/fs_avb_util.h>
42 #include <fs_mgr.h>
43 #include <fs_mgr_dm_linear.h>
44 #include <fstab/fstab.h>
45 #include <liblp/builder.h>
46 #include <libsnapshot/cow_format.h>
47 #include <libsnapshot/snapshot.h>
48 #include <storage_literals/storage_literals.h>
49 
50 #include <openssl/sha.h>
51 
52 #include "partition_cow_creator.h"
53 #include "scratch_super.h"
54 
55 #include "utility.h"
56 
57 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
58 #include <BootControlClient.h>
59 #endif
60 
61 using namespace std::chrono_literals;
62 using namespace std::string_literals;
63 using namespace android::storage_literals;
64 using android::base::LogdLogger;
65 using android::base::StderrLogger;
66 using android::base::TeeLogger;
67 using namespace android::dm;
68 using namespace android::fs_mgr;
69 using android::fs_mgr::CreateLogicalPartitionParams;
70 using android::fs_mgr::FindPartition;
71 using android::fs_mgr::GetPartitionSize;
72 using android::fs_mgr::PartitionOpener;
73 using android::fs_mgr::ReadMetadata;
74 using android::fs_mgr::SlotNumberForSlotSuffix;
75 
Usage()76 int Usage() {
77     std::cerr << "snapshotctl: Control snapshots.\n"
78                  "Usage: snapshotctl [action] [flags]\n"
79                  "Actions:\n"
80                  "  dump\n"
81                  "    Print snapshot states.\n"
82                  "  merge\n"
83                  "    Deprecated.\n"
84                  "  map\n"
85                  "    Map all partitions at /dev/block/mapper\n"
86                  "  pause-merge\n"
87                  "    Pause snapshot merge\n"
88                  "  resume-merge\n"
89                  "    Resume snapshot merge\n"
90                  "  map-snapshots <directory where snapshot patches are present>\n"
91                  "    Map all snapshots based on patches present in the directory\n"
92                  "  unmap-snapshots\n"
93                  "    Unmap all pre-created snapshots\n"
94                  "  delete-snapshots\n"
95                  "    Delete all pre-created snapshots\n"
96                  "  revert-snapshots\n"
97                  "    Prepares devices to boot without snapshots on next boot.\n"
98                  "    This does not delete the snapshot. It only removes the indicators\n"
99                  "    so that first stage init will not mount from snapshots.\n"
100                  "  apply-update\n"
101                  "    Apply the incremental OTA update wherein the snapshots are\n"
102                  "    directly written to COW block device. This will bypass update-engine\n"
103                  "    and the device will be ready to boot from the target build.\n"
104                  "  dump-verity-hash <directory where verity merkel tree hashes are stored> "
105                  "[-verify]\n"
106                  "    Dump the verity merkel tree hashes at the specified path\n"
107                  "    -verify: Verify the dynamic partition blocks by comparing it with verity "
108                  "merkel tree\n";
109     return EX_USAGE;
110 }
111 
112 namespace android {
113 namespace snapshot {
114 
115 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
116 class MapSnapshots {
117   public:
118     MapSnapshots(std::string path = "", bool metadata_super = false);
119     bool CreateSnapshotDevice(std::string& partition_name, std::string& patch);
120     bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch);
121     bool FinishSnapshotWrites();
122     bool UnmapCowImagePath(std::string& name);
123     bool DeleteSnapshots();
124     bool CleanupSnapshot();
125     bool BeginUpdate();
126     bool ApplyUpdate();
127 
128   private:
129     std::optional<std::string> GetCowImagePath(std::string& name);
130     bool PrepareUpdate();
131     bool GetCowDevicePath(std::string partition_name, std::string* cow_path);
132     bool WriteSnapshotPatch(std::string cow_device, std::string patch);
133     std::string GetGroupName(const android::fs_mgr::LpMetadata& pt,
134                              const std::string& partiton_name);
135     std::unique_ptr<SnapshotManager::LockedFile> lock_;
136     std::unique_ptr<SnapshotManager> sm_;
137     std::vector<std::future<bool>> threads_;
138     std::string snapshot_dir_path_;
139     std::unordered_map<std::string, chromeos_update_engine::DynamicPartitionGroup*> group_map_;
140 
141     std::vector<std::string> patchfiles_;
142     chromeos_update_engine::DeltaArchiveManifest manifest_;
143     bool metadata_super_ = false;
144 };
145 
MapSnapshots(std::string path,bool metadata_super)146 MapSnapshots::MapSnapshots(std::string path, bool metadata_super) {
147     snapshot_dir_path_ = path + "/";
148     metadata_super_ = metadata_super;
149 }
150 
GetGroupName(const android::fs_mgr::LpMetadata & pt,const std::string & partition_name)151 std::string MapSnapshots::GetGroupName(const android::fs_mgr::LpMetadata& pt,
152                                        const std::string& partition_name) {
153     std::string group_name;
154     for (const auto& partition : pt.partitions) {
155         std::string name = android::fs_mgr::GetPartitionName(partition);
156         auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name);
157         std::string pname = name.substr(0, name.size() - suffix.size());
158         if (pname == partition_name) {
159             std::string group_name =
160                     android::fs_mgr::GetPartitionGroupName(pt.groups[partition.group_index]);
161             return group_name.substr(0, group_name.size() - suffix.size());
162         }
163     }
164     return "";
165 }
166 
PrepareUpdate()167 bool MapSnapshots::PrepareUpdate() {
168     if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
169         LOG(ERROR) << "Failed to create OTA metadata on super";
170         return false;
171     }
172     sm_ = SnapshotManager::New();
173 
174     auto source_slot = fs_mgr_get_slot_suffix();
175     auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
176     auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
177 
178     // Get current partition information.
179     PartitionOpener opener;
180     auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
181     if (!source_metadata) {
182         LOG(ERROR) << "Could not read source partition metadata.\n";
183         return false;
184     }
185 
186     auto dap = manifest_.mutable_dynamic_partition_metadata();
187     dap->set_snapshot_enabled(true);
188     dap->set_vabc_enabled(true);
189     dap->set_vabc_compression_param("lz4");
190     dap->set_cow_version(3);
191 
192     for (const auto& entry : std::filesystem::directory_iterator(snapshot_dir_path_)) {
193         if (android::base::EndsWith(entry.path().generic_string(), ".patch")) {
194             patchfiles_.push_back(android::base::Basename(entry.path().generic_string()));
195         }
196     }
197 
198     for (auto& patchfile : patchfiles_) {
199         std::string parsing_file = snapshot_dir_path_ + patchfile;
200         android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file.c_str(), O_RDONLY)));
201         if (fd < 0) {
202             LOG(ERROR) << "Failed to open file: " << parsing_file;
203             return false;
204         }
205         uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
206         if (!dev_sz) {
207             LOG(ERROR) << "Could not determine block device size: " << parsing_file;
208             return false;
209         }
210 
211         const int block_sz = 4_KiB;
212         dev_sz += block_sz - 1;
213         dev_sz &= ~(block_sz - 1);
214 
215         auto npos = patchfile.rfind(".patch");
216         auto partition_name = patchfile.substr(0, npos);
217 
218         chromeos_update_engine::DynamicPartitionGroup* group = nullptr;
219         std::string group_name = GetGroupName(*source_metadata.get(), partition_name);
220         if (group_map_.find(group_name) != group_map_.end()) {
221             group = group_map_[group_name];
222         } else {
223             group = dap->add_groups();
224             group->set_name(group_name);
225             group_map_[group_name] = group;
226         }
227         group->add_partition_names(partition_name);
228 
229         auto pu = manifest_.mutable_partitions()->Add();
230         pu->set_partition_name(partition_name);
231         pu->set_estimate_cow_size(dev_sz);
232 
233         CowReader reader;
234         if (!reader.Parse(fd)) {
235             LOG(ERROR) << "COW reader parse failed";
236             return false;
237         }
238 
239         uint64_t new_device_size = 0;
240         const auto& header = reader.GetHeader();
241         if (header.prefix.major_version == 2) {
242             size_t num_ops = reader.get_num_total_data_ops();
243             new_device_size = (num_ops * header.block_size);
244         } else {
245             const auto& v3_header = reader.header_v3();
246             new_device_size = v3_header.op_count_max * v3_header.block_size;
247         }
248 
249         LOG(INFO) << "Partition: " << partition_name << " Group_name: " << group_name
250                   << " size: " << new_device_size << " COW-size: " << dev_sz;
251         pu->mutable_new_partition_info()->set_size(new_device_size);
252     }
253     return true;
254 }
255 
GetCowDevicePath(std::string partition_name,std::string * cow_path)256 bool MapSnapshots::GetCowDevicePath(std::string partition_name, std::string* cow_path) {
257     auto& dm = android::dm::DeviceMapper::Instance();
258 
259     std::string cow_device = partition_name + "-cow-img";
260     if (metadata_super_) {
261         // If COW device exists on /data, then data wipe cannot be done.
262         if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
263             LOG(ERROR) << "COW device exists on /data: " << *cow_path;
264             return false;
265         }
266     }
267 
268     cow_device = partition_name + "-cow";
269     if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
270         return true;
271     }
272 
273     LOG(INFO) << "Failed to find cow path: " << cow_device << " Checking the device for -img path";
274     // If the COW device exists only on /data
275     cow_device = partition_name + "-cow-img";
276     if (!dm.GetDmDevicePathByName(cow_device, cow_path)) {
277         LOG(ERROR) << "Failed to cow path: " << cow_device;
278         return false;
279     }
280     return true;
281 }
282 
ApplyUpdate()283 bool MapSnapshots::ApplyUpdate() {
284     if (!PrepareUpdate()) {
285         LOG(ERROR) << "PrepareUpdate failed";
286         return false;
287     }
288     if (!sm_->BeginUpdate()) {
289         LOG(ERROR) << "BeginUpdate failed";
290         return false;
291     }
292     if (!sm_->CreateUpdateSnapshots(manifest_)) {
293         LOG(ERROR) << "Could not apply snapshots";
294         return false;
295     }
296 
297     LOG(INFO) << "CreateUpdateSnapshots success";
298     if (!sm_->MapAllSnapshots(10s)) {
299         LOG(ERROR) << "MapAllSnapshots failed";
300         return false;
301     }
302 
303     LOG(INFO) << "MapAllSnapshots success";
304 
305     auto target_slot = fs_mgr_get_other_slot_suffix();
306     for (auto& patchfile : patchfiles_) {
307         auto npos = patchfile.rfind(".patch");
308         auto partition_name = patchfile.substr(0, npos) + target_slot;
309         std::string cow_path;
310         if (!GetCowDevicePath(partition_name, &cow_path)) {
311             LOG(ERROR) << "Failed to find cow path";
312             return false;
313         }
314         threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch,
315                                          this, cow_path, patchfile));
316     }
317 
318     bool ret = true;
319     for (auto& t : threads_) {
320         ret = t.get() && ret;
321     }
322     if (!ret) {
323         LOG(ERROR) << "Snapshot writes failed";
324         return false;
325     }
326     if (!sm_->UnmapAllSnapshots()) {
327         LOG(ERROR) << "UnmapAllSnapshots failed";
328         return false;
329     }
330 
331     LOG(INFO) << "Pre-created snapshots successfully copied";
332     // All snapshots have been written.
333     if (!sm_->FinishedSnapshotWrites(false /* wipe */)) {
334         LOG(ERROR) << "Could not finalize snapshot writes.\n";
335         return false;
336     }
337 
338     auto hal = hal::BootControlClient::WaitForService();
339     if (!hal) {
340         LOG(ERROR) << "Could not find IBootControl HAL.\n";
341         return false;
342     }
343     auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
344     auto cr = hal->SetActiveBootSlot(target_slot_number);
345     if (!cr.IsOk()) {
346         LOG(ERROR) << "Could not set active boot slot: " << cr.errMsg;
347         return false;
348     }
349 
350     LOG(INFO) << "ApplyUpdate success";
351     return true;
352 }
353 
BeginUpdate()354 bool MapSnapshots::BeginUpdate() {
355     if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
356         LOG(ERROR) << "Failed to create OTA metadata on super";
357         return false;
358     }
359     sm_ = SnapshotManager::New();
360 
361     lock_ = sm_->LockExclusive();
362     std::vector<std::string> snapshots;
363     sm_->ListSnapshots(lock_.get(), &snapshots);
364     if (!snapshots.empty()) {
365         // Snapshots are already present.
366         return true;
367     }
368 
369     lock_ = nullptr;
370     if (!sm_->BeginUpdate()) {
371         LOG(ERROR) << "BeginUpdate failed";
372         return false;
373     }
374     lock_ = sm_->LockExclusive();
375     return true;
376 }
377 
CreateSnapshotDevice(std::string & partition_name,std::string & patchfile)378 bool MapSnapshots::CreateSnapshotDevice(std::string& partition_name, std::string& patchfile) {
379     std::string parsing_file = snapshot_dir_path_ + patchfile;
380 
381     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file.c_str(), O_RDONLY)));
382     if (fd < 0) {
383         LOG(ERROR) << "Failed to open file: " << parsing_file;
384         return false;
385     }
386 
387     uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
388     if (!dev_sz) {
389         LOG(ERROR) << "Could not determine block device size: " << parsing_file;
390         return false;
391     }
392 
393     const int block_sz = 4_KiB;
394     dev_sz += block_sz - 1;
395     dev_sz &= ~(block_sz - 1);
396 
397     SnapshotStatus status;
398     status.set_state(SnapshotState::CREATED);
399     status.set_using_snapuserd(true);
400     status.set_old_partition_size(0);
401     status.set_name(partition_name);
402     status.set_cow_file_size(dev_sz);
403     status.set_cow_partition_size(0);
404 
405     PartitionCowCreator cow_creator;
406     cow_creator.using_snapuserd = true;
407 
408     if (!sm_->CreateSnapshot(lock_.get(), &cow_creator, &status)) {
409         LOG(ERROR) << "CreateSnapshot failed";
410         return false;
411     }
412 
413     if (!sm_->CreateCowImage(lock_.get(), partition_name)) {
414         LOG(ERROR) << "CreateCowImage failed";
415         return false;
416     }
417 
418     return true;
419 }
420 
GetCowImagePath(std::string & name)421 std::optional<std::string> MapSnapshots::GetCowImagePath(std::string& name) {
422     auto cow_dev = sm_->MapCowImage(name, 5s);
423     if (!cow_dev.has_value()) {
424         LOG(ERROR) << "Failed to get COW device path";
425         return std::nullopt;
426     }
427 
428     LOG(INFO) << "COW Device path: " << cow_dev.value();
429     return cow_dev;
430 }
431 
WriteSnapshotPatch(std::string cow_device,std::string patch)432 bool MapSnapshots::WriteSnapshotPatch(std::string cow_device, std::string patch) {
433     std::string patch_file = snapshot_dir_path_ + patch;
434 
435     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(patch_file.c_str(), O_RDONLY)));
436     if (fd < 0) {
437         LOG(ERROR) << "Failed to open file: " << patch_file;
438         return false;
439     }
440 
441     uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
442     if (!dev_sz) {
443         std::cout << "Could not determine block device size: " << patch_file;
444         return false;
445     }
446 
447     android::base::unique_fd cfd(TEMP_FAILURE_RETRY(open(cow_device.c_str(), O_RDWR)));
448     if (cfd < 0) {
449         LOG(ERROR) << "Failed to open file: " << cow_device;
450         return false;
451     }
452 
453     const uint64_t read_sz = 1_MiB;
454     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(read_sz);
455     off_t file_offset = 0;
456 
457     while (true) {
458         size_t to_read = std::min((dev_sz - file_offset), read_sz);
459         if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) {
460             PLOG(ERROR) << "ReadFullyAtOffset failed";
461             return false;
462         }
463 
464         if (!android::base::WriteFullyAtOffset(cfd, buffer.get(), to_read, file_offset)) {
465             PLOG(ERROR) << "WriteFullyAtOffset failed";
466             return false;
467         }
468         file_offset += to_read;
469         if (file_offset >= dev_sz) {
470             break;
471         }
472     }
473     if (fsync(cfd.get()) < 0) {
474         PLOG(ERROR) << "Fsync failed";
475         return false;
476     }
477     return true;
478 }
479 
InitiateThreadedSnapshotWrite(std::string & pname,std::string & snapshot_patch)480 bool MapSnapshots::InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch) {
481     auto path = GetCowImagePath(pname);
482     if (!path.has_value()) {
483         return false;
484     }
485     threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch, this,
486                                      path.value(), snapshot_patch));
487     return true;
488 }
489 
FinishSnapshotWrites()490 bool MapSnapshots::FinishSnapshotWrites() {
491     bool ret = true;
492     for (auto& t : threads_) {
493         ret = t.get() && ret;
494     }
495 
496     lock_ = nullptr;
497     if (ret) {
498         LOG(INFO) << "Pre-created snapshots successfully copied";
499         if (!sm_->FinishedSnapshotWrites(false)) {
500             return false;
501         }
502         return sm_->BootFromSnapshotsWithoutSlotSwitch();
503     }
504 
505     LOG(ERROR) << "Snapshot copy failed";
506     return false;
507 }
508 
UnmapCowImagePath(std::string & name)509 bool MapSnapshots::UnmapCowImagePath(std::string& name) {
510     sm_ = SnapshotManager::New();
511     return sm_->UnmapCowImage(name);
512 }
513 
CleanupSnapshot()514 bool MapSnapshots::CleanupSnapshot() {
515     sm_ = SnapshotManager::New();
516     return sm_->PrepareDeviceToBootWithoutSnapshot();
517 }
518 
DeleteSnapshots()519 bool MapSnapshots::DeleteSnapshots() {
520     sm_ = SnapshotManager::New();
521     lock_ = sm_->LockExclusive();
522     if (!sm_->RemoveAllUpdateState(lock_.get())) {
523         LOG(ERROR) << "Remove All Update State failed";
524         return false;
525     }
526     return true;
527 }
528 #endif
529 
DumpCmdHandler(int,char ** argv)530 bool DumpCmdHandler(int /*argc*/, char** argv) {
531     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
532     return SnapshotManager::New()->Dump(std::cout);
533 }
534 
MapCmdHandler(int,char ** argv)535 bool MapCmdHandler(int, char** argv) {
536     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
537     using namespace std::chrono_literals;
538     return SnapshotManager::New()->MapAllSnapshots(5000ms);
539 }
540 
UnmapCmdHandler(int,char ** argv)541 bool UnmapCmdHandler(int, char** argv) {
542     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
543     return SnapshotManager::New()->UnmapAllSnapshots();
544 }
545 
PauseSnapshotMerge(int,char ** argv)546 bool PauseSnapshotMerge(int, char** argv) {
547     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
548     return SnapshotManager::New()->PauseSnapshotMerge();
549 }
550 
ResumeSnapshotMerge(int,char ** argv)551 bool ResumeSnapshotMerge(int, char** argv) {
552     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
553     return SnapshotManager::New()->ResumeSnapshotMerge();
554 }
555 
MergeCmdHandler(int,char ** argv)556 bool MergeCmdHandler(int /*argc*/, char** argv) {
557     android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
558     LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
559     return false;
560 }
561 
562 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
GetVerityPartitions(std::vector<std::string> & partitions)563 bool GetVerityPartitions(std::vector<std::string>& partitions) {
564     auto& dm = android::dm::DeviceMapper::Instance();
565     auto dm_block_devices = dm.FindDmPartitions();
566     if (dm_block_devices.empty()) {
567         LOG(ERROR) << "No dm-enabled block device is found.";
568         return false;
569     }
570 
571     for (auto& block_device : dm_block_devices) {
572         std::string dm_block_name = block_device.first;
573         std::string slot_suffix = fs_mgr_get_slot_suffix();
574         std::string partition = dm_block_name + slot_suffix;
575         partitions.push_back(partition);
576     }
577     return true;
578 }
579 
UnMapPrecreatedSnapshots(int,char ** argv)580 bool UnMapPrecreatedSnapshots(int, char** argv) {
581     android::base::InitLogging(argv, &android::base::KernelLogger);
582     // Make sure we are root.
583     if (::getuid() != 0) {
584         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
585         return EXIT_FAILURE;
586     }
587 
588     std::vector<std::string> partitions;
589     if (!GetVerityPartitions(partitions)) {
590         return false;
591     }
592 
593     MapSnapshots snapshot;
594     for (auto partition : partitions) {
595         if (!snapshot.UnmapCowImagePath(partition)) {
596             LOG(ERROR) << "UnmapCowImagePath failed: " << partition;
597         }
598     }
599     return true;
600 }
601 
RemovePrecreatedSnapshots(int,char ** argv)602 bool RemovePrecreatedSnapshots(int, char** argv) {
603     android::base::InitLogging(argv, &android::base::KernelLogger);
604     // Make sure we are root.
605     if (::getuid() != 0) {
606         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
607         return false;
608     }
609 
610     MapSnapshots snapshot;
611     if (!snapshot.CleanupSnapshot()) {
612         LOG(ERROR) << "CleanupSnapshot failed";
613         return false;
614     }
615     return true;
616 }
617 
DeletePrecreatedSnapshots(int,char ** argv)618 bool DeletePrecreatedSnapshots(int, char** argv) {
619     android::base::InitLogging(argv, &android::base::KernelLogger);
620     // Make sure we are root.
621     if (::getuid() != 0) {
622         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
623         return EXIT_FAILURE;
624     }
625 
626     MapSnapshots snapshot;
627     return snapshot.DeleteSnapshots();
628 }
629 
ApplyUpdate(int argc,char ** argv)630 bool ApplyUpdate(int argc, char** argv) {
631     android::base::InitLogging(argv, &android::base::KernelLogger);
632 
633     // Make sure we are root.
634     if (::getuid() != 0) {
635         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
636         return EXIT_FAILURE;
637     }
638 
639     if (argc < 3) {
640         std::cerr << " apply-update <directory location where snapshot patches are present> {-w}"
641                      "    Apply the snapshots to the COW block device\n";
642         return false;
643     }
644 
645     std::string path = std::string(argv[2]);
646     bool metadata_on_super = false;
647     if (argc == 4) {
648         if (std::string(argv[3]) == "-w") {
649             metadata_on_super = true;
650         }
651     }
652     MapSnapshots cow(path, metadata_on_super);
653     if (!cow.ApplyUpdate()) {
654         return false;
655     }
656     LOG(INFO) << "Apply update success. Please reboot the device";
657     return true;
658 }
659 
GetBlockHashFromMerkelTree(android::base::borrowed_fd image_fd,uint64_t image_size,uint32_t data_block_size,uint32_t hash_block_size,uint64_t tree_offset,std::vector<std::string> & out_block_hash)660 static bool GetBlockHashFromMerkelTree(android::base::borrowed_fd image_fd, uint64_t image_size,
661                                        uint32_t data_block_size, uint32_t hash_block_size,
662                                        uint64_t tree_offset,
663                                        std::vector<std::string>& out_block_hash) {
664     uint32_t padded_digest_size = 32;
665     if (image_size % data_block_size != 0) {
666         LOG(ERROR) << "Image_size: " << image_size
667                    << " not a multiple of data block size: " << data_block_size;
668         return false;
669     }
670 
671     // vector of level-size and offset
672     std::vector<std::pair<uint64_t, uint64_t>> levels;
673     uint64_t data_block_count = image_size / data_block_size;
674     uint32_t digests_per_block = hash_block_size / padded_digest_size;
675     uint32_t level_block_count = data_block_count;
676     while (level_block_count > 1) {
677         uint32_t next_level_block_count =
678                 (level_block_count + digests_per_block - 1) / digests_per_block;
679         levels.emplace_back(std::make_pair(next_level_block_count * hash_block_size, 0));
680         level_block_count = next_level_block_count;
681     }
682     // root digest
683     levels.emplace_back(std::make_pair(0, 0));
684     // initialize offset
685     for (auto level = std::prev(levels.end()); level != levels.begin(); level--) {
686         std::prev(level)->second = level->second + level->first;
687     }
688 
689     // We just want level 0
690     auto level = levels.begin();
691     std::string hash_block(hash_block_size, '\0');
692     uint64_t block_offset = tree_offset + level->second;
693     uint64_t t_read_blocks = 0;
694     uint64_t blockidx = 0;
695     uint64_t num_hash_blocks = level->first / hash_block_size;
696     while ((t_read_blocks < num_hash_blocks) && (blockidx < data_block_count)) {
697         if (!android::base::ReadFullyAtOffset(image_fd, hash_block.data(), hash_block.size(),
698                                               block_offset)) {
699             LOG(ERROR) << "Failed to read tree block at offset: " << block_offset;
700             return false;
701         }
702 
703         for (uint32_t offset = 0; offset < hash_block.size(); offset += padded_digest_size) {
704             std::string single_hash = hash_block.substr(offset, padded_digest_size);
705             out_block_hash.emplace_back(single_hash);
706 
707             blockidx += 1;
708             if (blockidx >= data_block_count) {
709                 break;
710             }
711         }
712 
713         block_offset += hash_block_size;
714         t_read_blocks += 1;
715     }
716     return true;
717 }
718 
CalculateDigest(const void * buffer,size_t size,const void * salt,uint32_t salt_length,uint8_t * digest)719 static bool CalculateDigest(const void* buffer, size_t size, const void* salt, uint32_t salt_length,
720                             uint8_t* digest) {
721     SHA256_CTX ctx;
722     if (SHA256_Init(&ctx) != 1) {
723         return false;
724     }
725     if (SHA256_Update(&ctx, salt, salt_length) != 1) {
726         return false;
727     }
728     if (SHA256_Update(&ctx, buffer, size) != 1) {
729         return false;
730     }
731     if (SHA256_Final(digest, &ctx) != 1) {
732         return false;
733     }
734     return true;
735 }
736 
verify_data_blocks(android::base::borrowed_fd fd,const std::vector<std::string> & block_hash,std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> & descriptor,const std::vector<uint8_t> & salt)737 bool verify_data_blocks(android::base::borrowed_fd fd, const std::vector<std::string>& block_hash,
738                         std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor>& descriptor,
739                         const std::vector<uint8_t>& salt) {
740     uint64_t data_block_count = descriptor->image_size / descriptor->data_block_size;
741     uint64_t foffset = 0;
742     uint64_t blk = 0;
743 
744     std::string hash_block(descriptor->hash_block_size, '\0');
745     while (blk < data_block_count) {
746         if (!android::base::ReadFullyAtOffset(fd, hash_block.data(), descriptor->hash_block_size,
747                                               foffset)) {
748             LOG(ERROR) << "Failed to read from offset: " << foffset;
749             return false;
750         }
751 
752         std::string digest(32, '\0');
753         CalculateDigest(hash_block.data(), descriptor->hash_block_size, salt.data(), salt.size(),
754                         reinterpret_cast<uint8_t*>(digest.data()));
755         if (digest != block_hash[blk]) {
756             LOG(ERROR) << "Hash mismatch for block: " << blk << " Expected: " << block_hash[blk]
757                        << " Received: " << digest;
758             return false;
759         }
760 
761         foffset += descriptor->hash_block_size;
762         blk += 1;
763     }
764 
765     return true;
766 }
767 
DumpVerityHash(int argc,char ** argv)768 bool DumpVerityHash(int argc, char** argv) {
769     android::base::InitLogging(argv, &android::base::KernelLogger);
770 
771     if (::getuid() != 0) {
772         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
773         return EXIT_FAILURE;
774     }
775 
776     if (argc < 3) {
777         std::cerr
778                 << " dump-verity-hash <directory location where verity hash is saved> {-verify}\n";
779         return false;
780     }
781 
782     bool verification_required = false;
783     std::string hash_file_path = argv[2];
784     bool metadata_on_super = false;
785     if (argc == 4) {
786         if (argv[3] == "-verify"s) {
787             verification_required = true;
788         }
789     }
790 
791     auto& dm = android::dm::DeviceMapper::Instance();
792     auto dm_block_devices = dm.FindDmPartitions();
793     if (dm_block_devices.empty()) {
794         LOG(ERROR) << "No dm-enabled block device is found.";
795         return false;
796     }
797 
798     android::fs_mgr::Fstab fstab;
799     if (!ReadDefaultFstab(&fstab)) {
800         LOG(ERROR) << "Failed to read fstab";
801         return false;
802     }
803 
804     for (const auto& pair : dm_block_devices) {
805         std::string partition_name = pair.first;
806         android::fs_mgr::FstabEntry* fstab_entry =
807                 GetEntryForMountPoint(&fstab, "/" + partition_name);
808         auto vbmeta = LoadAndVerifyVbmeta(*fstab_entry, "", nullptr, nullptr, nullptr);
809         if (vbmeta == nullptr) {
810             LOG(ERROR) << "LoadAndVerifyVbmetaByPath failed for partition: " << partition_name;
811             return false;
812         }
813 
814         auto descriptor =
815                 android::fs_mgr::GetHashtreeDescriptor(partition_name, std::move(*vbmeta));
816         if (descriptor == nullptr) {
817             LOG(ERROR) << "GetHashtreeDescriptor failed for partition: " << partition_name;
818             return false;
819         }
820 
821         std::string device_path = fstab_entry->blk_device;
822         if (!dm.GetDmDevicePathByName(fstab_entry->blk_device, &device_path)) {
823             LOG(ERROR) << "Failed to resolve logical device path for: " << fstab_entry->blk_device;
824             return false;
825         }
826 
827         android::base::unique_fd fd(open(device_path.c_str(), O_RDONLY));
828         if (fd < 0) {
829             LOG(ERROR) << "Failed to open file: " << device_path;
830             return false;
831         }
832         std::vector<std::string> block_hash;
833         if (!GetBlockHashFromMerkelTree(fd, descriptor->image_size, descriptor->data_block_size,
834                                         descriptor->hash_block_size, descriptor->tree_offset,
835                                         block_hash)) {
836             LOG(ERROR) << "GetBlockHashFromMerkelTree failed";
837             return false;
838         }
839 
840         uint64_t dev_sz = lseek(fd, 0, SEEK_END);
841         uint64_t fec_size = dev_sz - descriptor->image_size;
842         if (fec_size % descriptor->data_block_size != 0) {
843             LOG(ERROR) << "fec_size: " << fec_size
844                        << " isn't multiple of: " << descriptor->data_block_size;
845             return false;
846         }
847 
848         std::vector<uint8_t> salt;
849         const std::string& salt_str = descriptor->salt;
850         bool ok = android::base::HexToBytes(salt_str, &salt);
851         if (!ok) {
852             LOG(ERROR) << "HexToBytes conversion failed";
853             return false;
854         }
855         uint64_t file_offset = descriptor->image_size;
856         std::vector<uint8_t> hash_block(descriptor->hash_block_size, 0);
857         while (file_offset < dev_sz) {
858             if (!android::base::ReadFullyAtOffset(fd, hash_block.data(),
859                                                   descriptor->hash_block_size, file_offset)) {
860                 LOG(ERROR) << "Failed to read tree block at offset: " << file_offset;
861                 return false;
862             }
863             std::string digest(32, '\0');
864             CalculateDigest(hash_block.data(), descriptor->hash_block_size, salt.data(),
865                             salt.size(), reinterpret_cast<uint8_t*>(digest.data()));
866             block_hash.push_back(digest);
867             file_offset += descriptor->hash_block_size;
868             fec_size -= descriptor->hash_block_size;
869         }
870 
871         if (fec_size != 0) {
872             LOG(ERROR) << "Checksum calculation pending: " << fec_size;
873             return false;
874         }
875 
876         if (verification_required) {
877             if (!verify_data_blocks(fd, block_hash, descriptor, salt)) {
878                 LOG(ERROR) << "verify_data_blocks failed";
879                 return false;
880             }
881         }
882 
883         VerityHash verity_hash;
884         verity_hash.set_partition_name(partition_name);
885         verity_hash.set_salt(salt_str);
886         for (auto hash : block_hash) {
887             verity_hash.add_block_hash(hash.data(), hash.size());
888         }
889         std::string hash_file = hash_file_path + "/" + partition_name + ".pb";
890         std::string content;
891         if (!verity_hash.SerializeToString(&content)) {
892             LOG(ERROR) << "Unable to serialize verity_hash";
893             return false;
894         }
895         if (!WriteStringToFileAtomic(content, hash_file)) {
896             PLOG(ERROR) << "Unable to write VerityHash to " << hash_file;
897             return false;
898         }
899 
900         LOG(INFO) << partition_name
901                   << ": GetBlockHashFromMerkelTree success. Num Blocks: " << block_hash.size();
902     }
903     return true;
904 }
905 
MapPrecreatedSnapshots(int argc,char ** argv)906 bool MapPrecreatedSnapshots(int argc, char** argv) {
907     android::base::InitLogging(argv, &android::base::KernelLogger);
908 
909     // Make sure we are root.
910     if (::getuid() != 0) {
911         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
912         return EXIT_FAILURE;
913     }
914 
915     if (argc < 3) {
916         std::cerr << " map-snapshots <directory location where snapshot patches are present> {-w}"
917                      "    Map all snapshots based on patches present in the directory\n";
918         return false;
919     }
920 
921     std::string path = std::string(argv[2]);
922     std::vector<std::string> patchfiles;
923 
924     for (const auto& entry : std::filesystem::directory_iterator(path)) {
925         if (android::base::EndsWith(entry.path().generic_string(), ".patch")) {
926             patchfiles.push_back(android::base::Basename(entry.path().generic_string()));
927         }
928     }
929     auto& dm = android::dm::DeviceMapper::Instance();
930     auto dm_block_devices = dm.FindDmPartitions();
931     if (dm_block_devices.empty()) {
932         LOG(ERROR) << "No dm-enabled block device is found.";
933         return false;
934     }
935 
936     std::vector<std::pair<std::string, std::string>> partitions;
937     for (auto& patchfile : patchfiles) {
938         auto npos = patchfile.rfind(".patch");
939         auto dm_block_name = patchfile.substr(0, npos);
940         if (dm_block_devices.find(dm_block_name) != dm_block_devices.end()) {
941             std::string slot_suffix = fs_mgr_get_slot_suffix();
942             std::string partition = dm_block_name + slot_suffix;
943             partitions.push_back(std::make_pair(partition, patchfile));
944         }
945     }
946 
947     bool metadata_on_super = false;
948     if (argc == 4) {
949         if (std::string(argv[3]) == "-w") {
950             metadata_on_super = true;
951         }
952     }
953 
954     MapSnapshots cow(path, metadata_on_super);
955     if (!cow.BeginUpdate()) {
956         LOG(ERROR) << "BeginUpdate failed";
957         return false;
958     }
959 
960     for (auto& pair : partitions) {
961         if (!cow.CreateSnapshotDevice(pair.first, pair.second)) {
962             LOG(ERROR) << "CreateSnapshotDevice failed for: " << pair.first;
963             return false;
964         }
965         if (!cow.InitiateThreadedSnapshotWrite(pair.first, pair.second)) {
966             LOG(ERROR) << "InitiateThreadedSnapshotWrite failed for: " << pair.first;
967             return false;
968         }
969     }
970 
971     return cow.FinishSnapshotWrites();
972 }
973 
CreateTestUpdate(SnapshotManager * sm)974 bool CreateTestUpdate(SnapshotManager* sm) {
975     chromeos_update_engine::DeltaArchiveManifest manifest;
976 
977     // We only copy system, to simplify things.
978     manifest.set_partial_update(true);
979 
980     auto dap = manifest.mutable_dynamic_partition_metadata();
981     dap->set_snapshot_enabled(true);
982     dap->set_vabc_enabled(true);
983     dap->set_vabc_compression_param("none");
984     dap->set_cow_version(kCowVersionMajor);
985 
986     auto source_slot = fs_mgr_get_slot_suffix();
987     auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
988     auto target_slot = fs_mgr_get_other_slot_suffix();
989     auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
990     auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
991 
992     // Get current partition information.
993     PartitionOpener opener;
994     auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
995     if (!source_metadata) {
996         std::cerr << "Could not read source partition metadata.\n";
997         return false;
998     }
999 
1000     auto system_source_name = "system" + source_slot;
1001     auto system_source = FindPartition(*source_metadata.get(), system_source_name);
1002     if (!system_source) {
1003         std::cerr << "Could not find system partition: " << system_source_name << ".\n";
1004         return false;
1005     }
1006     auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source);
1007 
1008     // Since we only add copy operations, 64MB should be enough.
1009     auto system_update = manifest.mutable_partitions()->Add();
1010     system_update->set_partition_name("system");
1011     system_update->set_estimate_cow_size(64_MiB);
1012     system_update->mutable_new_partition_info()->set_size(system_source_size);
1013 
1014     if (!sm->CreateUpdateSnapshots(manifest)) {
1015         std::cerr << "Could not create update snapshots.\n";
1016         return false;
1017     }
1018 
1019     // Write the "new" system partition.
1020     auto system_target_name = "system" + target_slot;
1021     CreateLogicalPartitionParams clpp = {
1022             .block_device = fs_mgr_get_super_partition_name(target_slot_number),
1023             .metadata_slot = {target_slot_number},
1024             .partition_name = system_target_name,
1025             .timeout_ms = 10s,
1026             .partition_opener = &opener,
1027     };
1028     auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt);
1029     if (!writer) {
1030         std::cerr << "Could not open snapshot writer.\n";
1031         return false;
1032     }
1033 
1034     for (uint64_t block = 0; block < system_source_size / 4096; block++) {
1035         if (!writer->AddCopy(block, block)) {
1036             std::cerr << "Unable to add copy operation for block " << block << ".\n";
1037             return false;
1038         }
1039     }
1040     if (!writer->Finalize()) {
1041         std::cerr << "Could not finalize COW for " << system_target_name << ".\n";
1042         return false;
1043     }
1044     writer = nullptr;
1045 
1046     // Finished writing this partition, unmap.
1047     if (!sm->UnmapUpdateSnapshot(system_target_name)) {
1048         std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n";
1049         return false;
1050     }
1051 
1052     // All snapshots have been written.
1053     if (!sm->FinishedSnapshotWrites(false /* wipe */)) {
1054         std::cerr << "Could not finalize snapshot writes.\n";
1055         return false;
1056     }
1057 
1058     auto hal = hal::BootControlClient::WaitForService();
1059     if (!hal) {
1060         std::cerr << "Could not find IBootControl HAL.\n";
1061         return false;
1062     }
1063     auto cr = hal->SetActiveBootSlot(target_slot_number);
1064     if (!cr.IsOk()) {
1065         std::cerr << "Could not set active boot slot: " << cr.errMsg;
1066         return false;
1067     }
1068 
1069     std::cerr << "It is now safe to reboot your device. If using a physical device, make\n"
1070               << "sure that all physical partitions are flashed to both A and B slots.\n";
1071     return true;
1072 }
1073 
TestOtaHandler(int,char **)1074 bool TestOtaHandler(int /* argc */, char** /* argv */) {
1075     auto sm = SnapshotManager::New();
1076 
1077     if (!sm->BeginUpdate()) {
1078         std::cerr << "Error starting update.\n";
1079         return false;
1080     }
1081 
1082     if (!CreateTestUpdate(sm.get())) {
1083         sm->CancelUpdate();
1084         return false;
1085     }
1086     return true;
1087 }
1088 #endif
1089 
1090 static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
1091         // clang-format off
1092         {"dump", DumpCmdHandler},
1093         {"merge", MergeCmdHandler},
1094         {"map", MapCmdHandler},
1095 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
1096         {"test-blank-ota", TestOtaHandler},
1097         {"apply-update", ApplyUpdate},
1098         {"map-snapshots", MapPrecreatedSnapshots},
1099         {"unmap-snapshots", UnMapPrecreatedSnapshots},
1100         {"delete-snapshots", DeletePrecreatedSnapshots},
1101         {"revert-snapshots", RemovePrecreatedSnapshots},
1102         {"dump-verity-hash", DumpVerityHash},
1103 #endif
1104         {"unmap", UnmapCmdHandler},
1105         {"pause-merge", PauseSnapshotMerge},
1106         {"resume-merge", ResumeSnapshotMerge},
1107         // clang-format on
1108 };
1109 
1110 }  // namespace snapshot
1111 }  // namespace android
1112 
main(int argc,char ** argv)1113 int main(int argc, char** argv) {
1114     using namespace android::snapshot;
1115     if (argc < 2) {
1116         return Usage();
1117     }
1118 
1119     for (const auto& cmd : kCmdMap) {
1120         if (cmd.first == argv[1]) {
1121             return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE;
1122         }
1123     }
1124 
1125     return Usage();
1126 }
1127