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