libsnapshot_fuzzer: map super image
... instead of operating on the image file directly.
Test: run it
Bug: 154633114
Change-Id: Id04c0d15d0d52483647716f8bfb0b8ee1a2876d9
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
index 12a0531..3671bb0 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
@@ -125,14 +125,14 @@
static FuzzSnapshotManager fuzz_snapshot_manager;
[[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
- CHECK(env.InitOk());
+ env.CheckSoftReset();
FuzzData fuzz_data(data, size);
auto snapshot_manager_data = fuzz_data.Consume<SnapshotManagerFuzzData>();
if (!snapshot_manager_data.has_value()) {
return 0;
}
- auto snapshot_manager = env.CreateSnapshotManager(snapshot_manager_data.value());
+ auto snapshot_manager = env.CheckCreateSnapshotManager(snapshot_manager_data.value());
CHECK(snapshot_manager);
fuzz_snapshot_manager.DepleteData(snapshot_manager.get(), &fuzz_data);
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
index d5e3e96..7829193 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
@@ -19,6 +19,7 @@
#include <sys/stat.h>
#include <sysexits.h>
+#include <chrono>
#include <string>
#include <android-base/file.h>
@@ -29,17 +30,27 @@
#include <storage_literals/storage_literals.h>
#include "snapshot_fuzz_utils.h"
+#include "utility.h"
+
+// Prepends the errno string, but it is good enough.
+#ifndef PCHECK
+#define PCHECK(x) CHECK(x) << strerror(errno) << ": "
+#endif
using namespace android::storage_literals;
+using namespace std::chrono_literals;
using namespace std::string_literals;
using android::base::StringPrintf;
using android::base::unique_fd;
using android::base::WriteStringToFile;
+using android::dm::LoopControl;
using android::fiemap::IImageManager;
using android::fiemap::ImageManager;
-static const char MNT_DIR[] = "/mnt";
+// This directory is exempted from pinning in ImageManager.
+static const char MNT_DIR[] = "/data/gsi/ota/test/";
+
static const char FAKE_ROOT_NAME[] = "snapshot_fuzz";
static const auto SUPER_IMAGE_SIZE = 16_MiB;
static const auto FAKE_ROOT_SIZE = 64_MiB;
@@ -128,6 +139,9 @@
class AutoMemBasedDir : public AutoDevice {
public:
static std::unique_ptr<AutoMemBasedDir> New(const std::string& name, uint64_t size) {
+ if (!Mkdir(MNT_DIR)) {
+ return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
+ }
auto ret = std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(name));
ret->auto_delete_mount_dir_ = AutoDeleteDir::New(ret->mount_path());
if (!ret->auto_delete_mount_dir_->HasDevice()) {
@@ -137,20 +151,31 @@
if (!ret->auto_umount_mount_point_->HasDevice()) {
return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
}
- // path() does not need to be deleted upon destruction, hence it is not wrapped with
- // AutoDeleteDir.
- if (!Mkdir(ret->path())) {
+ // tmp_path() and persist_path does not need to be deleted upon destruction, hence it is
+ // not wrapped with AutoDeleteDir.
+ if (!Mkdir(ret->tmp_path())) {
+ return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
+ }
+ if (!Mkdir(ret->persist_path())) {
return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
}
return ret;
}
- // Return the scratch directory.
- std::string path() const {
+ // Return the temporary scratch directory.
+ std::string tmp_path() const {
CHECK(HasDevice());
- return mount_path() + "/root";
+ return mount_path() + "/tmp";
}
- // Delete all contents in path() and start over. path() itself is re-created.
- bool SoftReset() { return RmdirRecursive(path()) && Mkdir(path()); }
+ // Return the temporary scratch directory.
+ std::string persist_path() const {
+ CHECK(HasDevice());
+ return mount_path() + "/persist";
+ }
+ // Delete all contents in tmp_path() and start over. tmp_path() itself is re-created.
+ void CheckSoftReset() {
+ PCHECK(RmdirRecursive(tmp_path()));
+ PCHECK(Mkdir(tmp_path()));
+ }
private:
AutoMemBasedDir(const std::string& name) : AutoDevice(name) {}
@@ -164,64 +189,83 @@
SnapshotFuzzEnv::SnapshotFuzzEnv() {
fake_root_ = AutoMemBasedDir::New(FAKE_ROOT_NAME, FAKE_ROOT_SIZE);
+ CHECK(fake_root_ != nullptr);
+ CHECK(fake_root_->HasDevice());
+ loop_control_ = std::make_unique<LoopControl>();
+ mapped_super_ = CheckMapSuper(fake_root_->persist_path(), loop_control_.get(), &fake_super_);
}
SnapshotFuzzEnv::~SnapshotFuzzEnv() = default;
-bool SnapshotFuzzEnv::InitOk() const {
- if (fake_root_ == nullptr || !fake_root_->HasDevice()) return false;
- return true;
+void CheckZeroFill(const std::string& file, size_t size) {
+ std::string zeros(size, '\0');
+ PCHECK(WriteStringToFile(zeros, file)) << "Cannot write zeros to " << file;
}
-bool SnapshotFuzzEnv::SoftReset() {
- return fake_root_->SoftReset();
+void SnapshotFuzzEnv::CheckSoftReset() {
+ fake_root_->CheckSoftReset();
+ CheckZeroFill(super(), SUPER_IMAGE_SIZE);
}
-std::unique_ptr<IImageManager> SnapshotFuzzEnv::CreateFakeImageManager(
- const std::string& fake_root) {
- auto images_dir = fake_root + "/images";
+std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager(
+ const std::string& path) {
+ auto images_dir = path + "/images";
auto metadata_dir = images_dir + "/metadata";
auto data_dir = images_dir + "/data";
- if (!Mkdir(images_dir) || !Mkdir(metadata_dir) || !Mkdir(data_dir)) {
- return nullptr;
- }
+ PCHECK(Mkdir(images_dir));
+ PCHECK(Mkdir(metadata_dir));
+ PCHECK(Mkdir(data_dir));
return ImageManager::Open(metadata_dir, data_dir);
}
-std::unique_ptr<TestPartitionOpener> SnapshotFuzzEnv::CreatePartitionOpener(
- const std::string& fake_root) {
- auto fake_super = fake_root + "/super.img";
- std::string zeros(SUPER_IMAGE_SIZE, '\0');
-
- if (!WriteStringToFile(zeros, fake_super)) {
- PLOG(ERROR) << "Cannot write zeros to " << fake_super;
- return nullptr;
- }
-
- return std::make_unique<TestPartitionOpener>(fake_super);
+// Helper to create a loop device for a file.
+static void CheckCreateLoopDevice(LoopControl* control, const std::string& file,
+ const std::chrono::milliseconds& timeout_ms, std::string* path) {
+ static constexpr int kOpenFlags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
+ android::base::unique_fd file_fd(open(file.c_str(), kOpenFlags));
+ PCHECK(file_fd >= 0) << "Could not open file: " << file;
+ CHECK(control->Attach(file_fd, timeout_ms, path))
+ << "Could not create loop device for: " << file;
}
-std::string SnapshotFuzzEnv::root() const {
- CHECK(InitOk());
- return fake_root_->path();
+class AutoDetachLoopDevice : public AutoDevice {
+ public:
+ AutoDetachLoopDevice(LoopControl* control, const std::string& device)
+ : AutoDevice(device), control_(control) {}
+ ~AutoDetachLoopDevice() { control_->Detach(name_); }
+
+ private:
+ LoopControl* control_;
+};
+
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMapSuper(const std::string& fake_persist_path,
+ LoopControl* control,
+ std::string* fake_super) {
+ auto super_img = fake_persist_path + "/super.img";
+ CheckZeroFill(super_img, SUPER_IMAGE_SIZE);
+ CheckCreateLoopDevice(control, super_img, 1s, fake_super);
+
+ return std::make_unique<AutoDetachLoopDevice>(control, *fake_super);
}
-std::unique_ptr<ISnapshotManager> SnapshotFuzzEnv::CreateSnapshotManager(
+std::unique_ptr<ISnapshotManager> SnapshotFuzzEnv::CheckCreateSnapshotManager(
const SnapshotManagerFuzzData& data) {
- // TODO(b/154633114): create valid super partition according to fuzz data
- auto partition_opener = CreatePartitionOpener(root());
- if (partition_opener == nullptr) return nullptr;
- auto metadata_dir = root() + "/snapshot_metadata";
- if (!Mkdir(metadata_dir)) return nullptr;
+ auto partition_opener = std::make_unique<TestPartitionOpener>(super());
+ auto metadata_dir = fake_root_->tmp_path() + "/snapshot_metadata";
+ PCHECK(Mkdir(metadata_dir));
auto device_info = new SnapshotFuzzDeviceInfo(data.device_info_data,
std::move(partition_opener), metadata_dir);
auto snapshot = SnapshotManager::New(device_info /* takes ownership */);
- snapshot->images_ = CreateFakeImageManager(root());
+ snapshot->images_ = CheckCreateFakeImageManager(fake_root_->tmp_path());
snapshot->has_local_image_manager_ = data.is_local_image_manager;
return snapshot;
}
+const std::string& SnapshotFuzzEnv::super() const {
+ return fake_super_;
+}
+
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index 32910a9..8c0d5dd 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -16,6 +16,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <libdm/loop_control.h>
#include <libfiemap/image_manager.h>
#include <libsnapshot/auto_device.h>
#include <libsnapshot/test_helpers.h>
@@ -52,27 +53,30 @@
SnapshotFuzzEnv();
~SnapshotFuzzEnv();
- // Check if environment is initialized properly.
- bool InitOk() const;
-
- // A scratch directory for the test to play around with. The scratch directory
- // is backed by tmpfs. SoftReset() clears the directory.
- std::string root() const;
-
// Soft reset part of the environment before running the next test.
- bool SoftReset();
+ // Abort if fails.
+ void CheckSoftReset();
// Create a snapshot manager for this test run.
// Client is responsible for maintaining the lifetime of |data| over the life time of
// ISnapshotManager.
- std::unique_ptr<ISnapshotManager> CreateSnapshotManager(const SnapshotManagerFuzzData& data);
+ std::unique_ptr<ISnapshotManager> CheckCreateSnapshotManager(
+ const SnapshotManagerFuzzData& data);
+
+ // Return path to super partition.
+ const std::string& super() const;
private:
std::unique_ptr<AutoMemBasedDir> fake_root_;
+ std::unique_ptr<android::dm::LoopControl> loop_control_;
+ std::unique_ptr<AutoDevice> mapped_super_;
+ std::string fake_super_;
- static std::unique_ptr<android::fiemap::IImageManager> CreateFakeImageManager(
- const std::string& fake_root);
- static std::unique_ptr<TestPartitionOpener> CreatePartitionOpener(const std::string& fake_root);
+ static std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager(
+ const std::string& fake_tmp_path);
+ static std::unique_ptr<AutoDevice> CheckMapSuper(const std::string& fake_persist_path,
+ android::dm::LoopControl* control,
+ std::string* fake_super);
};
class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo {