1 // Copyright (C) 2020 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <memory> 16 #include <set> 17 #include <string> 18 19 #include <android-base/file.h> 20 #include <android-base/stringprintf.h> 21 #include <android/snapshot/snapshot_fuzz.pb.h> 22 #include <libdm/loop_control.h> 23 #include <libfiemap/image_manager.h> 24 #include <liblp/liblp.h> 25 #include <libsnapshot/auto_device.h> 26 #include <libsnapshot/test_helpers.h> 27 28 // libsnapshot-specific code for fuzzing. Defines fake classes that are depended 29 // by SnapshotManager. 30 31 #include "android/snapshot/snapshot_fuzz.pb.h" 32 33 namespace android::snapshot { 34 35 class AutoMemBasedDir; 36 class SnapshotFuzzDeviceInfo; 37 38 class NoOpAutoDevice : public AutoDevice { 39 public: NoOpAutoDevice(bool mounted)40 NoOpAutoDevice(bool mounted) : AutoDevice(mounted ? "no_op" : "") {} 41 }; 42 43 struct SnapshotTestModule { 44 std::unique_ptr<ISnapshotManager> snapshot; 45 SnapshotFuzzDeviceInfo* device_info = nullptr; 46 TestPartitionOpener* opener = nullptr; 47 }; 48 49 // Prepare test environment. This has a heavy overhead and should be done once. 50 class SnapshotFuzzEnv { 51 public: 52 // Check if test should run at all. 53 static bool ShouldSkipTest(); 54 55 // Initialize the environment. 56 SnapshotFuzzEnv(); 57 ~SnapshotFuzzEnv(); 58 59 // Soft reset part of the environment before running the next test. 60 // Abort if fails. 61 void CheckSoftReset(); 62 63 // Create a snapshot manager for this test run. 64 // Client is responsible for maintaining the lifetime of |data| over the life time of 65 // ISnapshotManager. 66 SnapshotTestModule CheckCreateSnapshotManager(const SnapshotFuzzData& data); 67 68 std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager(); 69 70 // Return path to super partition. 71 const std::string& super() const; 72 73 private: 74 std::unique_ptr<AutoMemBasedDir> fake_root_; 75 std::unique_ptr<android::dm::LoopControl> loop_control_; 76 std::string fake_data_mount_point_; 77 std::unique_ptr<AutoDevice> auto_delete_data_mount_point_; 78 std::unique_ptr<AutoDevice> mapped_super_; 79 std::string fake_super_; 80 std::unique_ptr<AutoDevice> mapped_data_; 81 std::string fake_data_block_device_; 82 std::unique_ptr<AutoDevice> mounted_data_; 83 84 static std::unique_ptr<AutoDevice> CheckMapImage(const std::string& fake_persist_path, 85 uint64_t size, 86 android::dm::LoopControl* control, 87 std::string* mapped_path); 88 static std::unique_ptr<AutoDevice> CheckMountFormatData(const std::string& blk_device, 89 const std::string& mount_point); 90 91 void CheckWriteSuperMetadata(const SnapshotFuzzData& proto, 92 const android::fs_mgr::IPartitionOpener& opener); 93 }; 94 95 class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo { 96 public: 97 // Client is responsible for maintaining the lifetime of |data|. SnapshotFuzzDeviceInfo(SnapshotFuzzEnv * env,const FuzzDeviceInfoData & data,std::unique_ptr<TestPartitionOpener> && partition_opener,const std::string & metadata_dir)98 SnapshotFuzzDeviceInfo(SnapshotFuzzEnv* env, const FuzzDeviceInfoData& data, 99 std::unique_ptr<TestPartitionOpener>&& partition_opener, 100 const std::string& metadata_dir) 101 : env_(env), 102 data_(&data), 103 partition_opener_(std::move(partition_opener)), 104 metadata_dir_(metadata_dir) {} 105 106 // Following APIs are mocked. GetMetadataDir()107 std::string GetMetadataDir() const override { return metadata_dir_; } GetSuperDevice(uint32_t)108 std::string GetSuperDevice(uint32_t) const override { 109 // TestPartitionOpener can recognize this. 110 return "super"; 111 } GetPartitionOpener()112 const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override { 113 return *partition_opener_; 114 } 115 116 // Following APIs are fuzzed. GetSlotSuffix()117 std::string GetSlotSuffix() const override { return CurrentSlotIsA() ? "_a" : "_b"; } GetOtherSlotSuffix()118 std::string GetOtherSlotSuffix() const override { return CurrentSlotIsA() ? "_b" : "_a"; } IsOverlayfsSetup()119 bool IsOverlayfsSetup() const override { return data_->is_overlayfs_setup(); } SetBootControlMergeStatus(android::hardware::boot::V1_1::MergeStatus)120 bool SetBootControlMergeStatus(android::hardware::boot::V1_1::MergeStatus) override { 121 return data_->allow_set_boot_control_merge_status(); 122 } SetSlotAsUnbootable(unsigned int)123 bool SetSlotAsUnbootable(unsigned int) override { 124 return data_->allow_set_slot_as_unbootable(); 125 } IsRecovery()126 bool IsRecovery() const override { return data_->is_recovery(); } IsFirstStageInit()127 bool IsFirstStageInit() const override { return false; } OpenImageManager()128 std::unique_ptr<IImageManager> OpenImageManager() const { 129 return env_->CheckCreateFakeImageManager(); 130 } 131 SwitchSlot()132 void SwitchSlot() { switched_slot_ = !switched_slot_; } 133 134 private: 135 SnapshotFuzzEnv* env_; 136 const FuzzDeviceInfoData* data_; 137 std::unique_ptr<TestPartitionOpener> partition_opener_; 138 std::string metadata_dir_; 139 bool switched_slot_ = false; 140 CurrentSlotIsA()141 bool CurrentSlotIsA() const { return data_->slot_suffix_is_a() != switched_slot_; } 142 }; 143 144 // A spy class on ImageManager implementation. Upon destruction, unmaps all images 145 // map through this object. 146 class SnapshotFuzzImageManager : public android::fiemap::IImageManager { 147 public: Open(const std::string & metadata_dir,const std::string & data_dir)148 static std::unique_ptr<SnapshotFuzzImageManager> Open(const std::string& metadata_dir, 149 const std::string& data_dir) { 150 auto impl = android::fiemap::ImageManager::Open(metadata_dir, data_dir); 151 if (impl == nullptr) return nullptr; 152 return std::unique_ptr<SnapshotFuzzImageManager>( 153 new SnapshotFuzzImageManager(std::move(impl))); 154 } 155 156 ~SnapshotFuzzImageManager(); 157 158 // Spied APIs. 159 bool MapImageDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms, 160 std::string* path) override; 161 162 // Other functions call through. CreateBackingImage(const std::string & name,uint64_t size,int flags,std::function<bool (uint64_t,uint64_t)> && on_progress)163 android::fiemap::FiemapStatus CreateBackingImage( 164 const std::string& name, uint64_t size, int flags, 165 std::function<bool(uint64_t, uint64_t)>&& on_progress) override { 166 return impl_->CreateBackingImage(name, size, flags, std::move(on_progress)); 167 } DeleteBackingImage(const std::string & name)168 bool DeleteBackingImage(const std::string& name) override { 169 return impl_->DeleteBackingImage(name); 170 } UnmapImageDevice(const std::string & name)171 bool UnmapImageDevice(const std::string& name) override { 172 return impl_->UnmapImageDevice(name); 173 } BackingImageExists(const std::string & name)174 bool BackingImageExists(const std::string& name) override { 175 return impl_->BackingImageExists(name); 176 } IsImageMapped(const std::string & name)177 bool IsImageMapped(const std::string& name) override { return impl_->IsImageMapped(name); } MapImageWithDeviceMapper(const IPartitionOpener & opener,const std::string & name,std::string * dev)178 bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name, 179 std::string* dev) override { 180 return impl_->MapImageWithDeviceMapper(opener, name, dev); 181 } GetMappedImageDevice(const std::string & name,std::string * device)182 bool GetMappedImageDevice(const std::string& name, std::string* device) override { 183 return impl_->GetMappedImageDevice(name, device); 184 } MapAllImages(const std::function<bool (std::set<std::string>)> & init)185 bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override { 186 return impl_->MapAllImages(init); 187 } DisableImage(const std::string & name)188 bool DisableImage(const std::string& name) override { return impl_->DisableImage(name); } RemoveDisabledImages()189 bool RemoveDisabledImages() override { return impl_->RemoveDisabledImages(); } GetAllBackingImages()190 std::vector<std::string> GetAllBackingImages() override { return impl_->GetAllBackingImages(); } ZeroFillNewImage(const std::string & name,uint64_t bytes)191 android::fiemap::FiemapStatus ZeroFillNewImage(const std::string& name, 192 uint64_t bytes) override { 193 return impl_->ZeroFillNewImage(name, bytes); 194 } RemoveAllImages()195 bool RemoveAllImages() override { return impl_->RemoveAllImages(); } UnmapImageIfExists(const std::string & name)196 bool UnmapImageIfExists(const std::string& name) override { 197 return impl_->UnmapImageIfExists(name); 198 } 199 200 private: 201 std::unique_ptr<android::fiemap::IImageManager> impl_; 202 std::set<std::string> mapped_; 203 SnapshotFuzzImageManager(std::unique_ptr<android::fiemap::IImageManager> && impl)204 SnapshotFuzzImageManager(std::unique_ptr<android::fiemap::IImageManager>&& impl) 205 : impl_(std::move(impl)) {} 206 }; 207 208 } // namespace android::snapshot 209