Merge "Add function to compare the partitions' extents in metadata"
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 250cb82..8788b5a 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -280,5 +280,12 @@
return android::base::Join(argv, " ");
}
+std::string DmTargetUser::GetParameterString() const {
+ std::vector<std::string> argv;
+ argv.push_back(std::to_string(start()));
+ argv.push_back(std::to_string(size()));
+ return android::base::Join(argv, " ");
+}
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index f986cfe..57e3884 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -309,6 +309,14 @@
bool is_hw_wrapped_ = false;
};
+class DmTargetUser final : public DmTarget {
+ public:
+ DmTargetUser(uint64_t start, uint64_t length) : DmTarget(start, length) {}
+
+ std::string name() const override { return "user"; }
+ std::string GetParameterString() const override;
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index dff31b0..623293e 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -236,11 +236,18 @@
}
}
- if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false) &&
- !always_keep_source_slot) {
- if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
- target_slot_number)) {
- return nullptr;
+ if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) {
+ if (always_keep_source_slot) {
+ // always_keep_source_slot implies the target build does not support snapshots.
+ // Clear unsupported attributes.
+ SetMetadataHeaderV0(metadata.get());
+ } else {
+ // !always_keep_source_slot implies the target build supports snapshots. Do snapshot
+ // updates.
+ if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
+ target_slot_number)) {
+ return nullptr;
+ }
}
}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 293e444..54f31bc 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -225,8 +225,10 @@
// metadata may not have the target slot's devices listed yet, in which
// case, it is automatically upgraded to include all available block
// devices.
- // If |always_keep_source_slot| is set, on a Virtual A/B device, source slot
- // partitions are kept. This is useful when applying a downgrade package.
+ // If |always_keep_source_slot| is set, on a Virtual A/B device
+ // - source slot partitions are kept.
+ // - UPDATED flag is cleared.
+ // This is useful when applying a downgrade package.
static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
const std::string& source_partition,
uint32_t source_slot_number,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 48c5c83..d8e171b 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -15,6 +15,7 @@
*/
#include <fcntl.h>
+#include <inttypes.h>
#include <stdint.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -29,6 +30,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <ext4_utils/ext4_utils.h>
#include <openssl/sha.h>
@@ -285,5 +287,42 @@
return true;
}
+inline std::string ToHexString(uint64_t value) {
+ return android::base::StringPrintf("0x%" PRIx64, value);
+}
+
+void SetMetadataHeaderV0(LpMetadata* metadata) {
+ if (metadata->header.minor_version <= LP_METADATA_MINOR_VERSION_MIN) {
+ return;
+ }
+ LINFO << "Forcefully setting metadata header version " << LP_METADATA_MAJOR_VERSION << "."
+ << metadata->header.minor_version << " to " << LP_METADATA_MAJOR_VERSION << "."
+ << LP_METADATA_MINOR_VERSION_MIN;
+ metadata->header.minor_version = LP_METADATA_MINOR_VERSION_MIN;
+ metadata->header.header_size = sizeof(LpMetadataHeaderV1_0);
+
+ // Retrofit Virtual A/B devices should have version 10.1, so flags shouldn't be set.
+ // Warn if this is the case, but zero it out anyways.
+ if (metadata->header.flags) {
+ LWARN << "Zeroing unexpected flags: " << ToHexString(metadata->header.flags);
+ }
+
+ // Zero out all fields beyond LpMetadataHeaderV0.
+ static_assert(sizeof(metadata->header) > sizeof(LpMetadataHeaderV1_0));
+ memset(reinterpret_cast<uint8_t*>(&metadata->header) + sizeof(LpMetadataHeaderV1_0), 0,
+ sizeof(metadata->header) - sizeof(LpMetadataHeaderV1_0));
+
+ // Clear partition attributes unknown to V0.
+ // On retrofit Virtual A/B devices, UPDATED flag may be set, so only log info here.
+ for (auto& partition : metadata->partitions) {
+ if (partition.attributes & ~LP_PARTITION_ATTRIBUTE_MASK_V0) {
+ LINFO << "Clearing " << GetPartitionName(partition)
+ << " partition attribute: " << ToHexString(partition.attributes);
+ }
+
+ partition.attributes &= LP_PARTITION_ATTRIBUTE_MASK_V0;
+ }
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index c4fe3ed..aa3a6a0 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -103,6 +103,10 @@
bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,
uint32_t target_slot_number);
+// Forcefully set metadata header version to 1.0, clearing any incompatible flags and attributes
+// so that when downgrading to a build with liblp V0, the device still boots.
+void SetMetadataHeaderV0(LpMetadata* metadata);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 55214f5..7488bda 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1846,7 +1846,7 @@
PLOG(ERROR) << "Open failed: " << file;
return nullptr;
}
- if (lock_flags != 0 && flock(fd, lock_flags) < 0) {
+ if (lock_flags != 0 && TEMP_FAILURE_RETRY(flock(fd, lock_flags)) < 0) {
PLOG(ERROR) << "Acquire flock failed: " << file;
return nullptr;
}
@@ -1857,7 +1857,7 @@
}
SnapshotManager::LockedFile::~LockedFile() {
- if (flock(fd_, LOCK_UN) < 0) {
+ if (TEMP_FAILURE_RETRY(flock(fd_, LOCK_UN)) < 0) {
PLOG(ERROR) << "Failed to unlock file: " << path_;
}
}
@@ -2520,7 +2520,19 @@
LOG(INFO) << "EnsureMetadataMounted does nothing in Android mode.";
return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice());
}
- return AutoUnmountDevice::New(device_->GetMetadataDir());
+ auto ret = AutoUnmountDevice::New(device_->GetMetadataDir());
+ if (ret == nullptr) return nullptr;
+
+ // In rescue mode, it is possible to erase and format metadata, but /metadata/ota is not
+ // created to execute snapshot updates. Hence, subsequent calls is likely to fail because
+ // Lock*() fails. By failing early and returning nullptr here, update_engine_sideload can
+ // treat this case as if /metadata is not mounted.
+ if (!LockShared()) {
+ LOG(WARNING) << "/metadata is mounted, but errors occur when acquiring a shared lock. "
+ "Subsequent calls to SnapshotManager will fail. Unmounting /metadata now.";
+ return nullptr;
+ }
+ return ret;
}
bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 2738457..7a3d9a9 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -174,6 +174,8 @@
}
return std::make_unique<DmTargetSnapshot>(start_sector, num_sectors, base_device,
cow_device, mode, chunk_size);
+ } else if (target_type == "user") {
+ return std::make_unique<DmTargetUser>(start_sector, num_sectors);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
diff --git a/init/devices.cpp b/init/devices.cpp
index 9fbec64..53ca875 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -193,7 +193,8 @@
while (directory != "/" && directory != ".") {
std::string subsystem_link_path;
if (Realpath(directory + "/subsystem", &subsystem_link_path) &&
- subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
+ (subsystem_link_path == sysfs_mount_point_ + "/bus/platform" ||
+ subsystem_link_path == sysfs_mount_point_ + "/bus/amba")) {
// We need to remove the mount point that we added above before returning.
directory.erase(0, sysfs_mount_point_.size());
*platform_device_path = directory;
diff --git a/init/init.cpp b/init/init.cpp
index 631db8e..ba880ea 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -868,6 +868,8 @@
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
+ // Restore prio before main loop
+ setpriority(PRIO_PROCESS, 0, 0);
while (true) {
// By default, sleep until something happens.
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
diff --git a/init/main.cpp b/init/main.cpp
index 38bc74b..23f5530 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -52,7 +52,8 @@
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
-
+ // Boost prio which will be restored later
+ setpriority(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 612854d..b593b62 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -51,6 +51,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -74,6 +75,7 @@
using namespace std::literals;
using android::base::GetProperty;
+using android::base::ParseInt;
using android::base::ReadFileToString;
using android::base::Split;
using android::base::StartsWith;
@@ -886,24 +888,60 @@
load_properties_from_file("/prop.default", nullptr, &properties);
}
+ // /<part>/etc/build.prop is the canonical location of the build-time properties since S.
+ // Falling back to /<part>/defalt.prop and /<part>/build.prop only when legacy path has to
+ // be supported, which is controlled by the support_legacy_path_until argument.
+ const auto load_properties_from_partition = [&properties](const std::string& partition,
+ int support_legacy_path_until) {
+ auto path = "/" + partition + "/etc/build.prop";
+ if (load_properties_from_file(path.c_str(), nullptr, &properties)) {
+ return;
+ }
+ // To read ro.<partition>.build.version.sdk, temporarily load the legacy paths into a
+ // separate map. Then by comparing its value with legacy_version, we know that if the
+ // partition is old enough so that we need to respect the legacy paths.
+ std::map<std::string, std::string> temp;
+ auto legacy_path1 = "/" + partition + "/default.prop";
+ auto legacy_path2 = "/" + partition + "/build.prop";
+ load_properties_from_file(legacy_path1.c_str(), nullptr, &temp);
+ load_properties_from_file(legacy_path2.c_str(), nullptr, &temp);
+ bool support_legacy_path = false;
+ auto version_prop_name = "ro." + partition + ".build.version.sdk";
+ auto it = temp.find(version_prop_name);
+ if (it == temp.end()) {
+ // This is embarassing. Without the prop, we can't determine how old the partition is.
+ // Let's be conservative by assuming it is very very old.
+ support_legacy_path = true;
+ } else if (int value;
+ ParseInt(it->second.c_str(), &value) && value <= support_legacy_path_until) {
+ support_legacy_path = true;
+ }
+ if (support_legacy_path) {
+ // We don't update temp into properties directly as it might skip any (future) logic
+ // for resolving duplicates implemented in load_properties_from_file. Instead, read
+ // the files again into the properties map.
+ load_properties_from_file(legacy_path1.c_str(), nullptr, &properties);
+ load_properties_from_file(legacy_path2.c_str(), nullptr, &properties);
+ } else {
+ LOG(FATAL) << legacy_path1 << " and " << legacy_path2 << " were not loaded "
+ << "because " << version_prop_name << "(" << it->second << ") is newer "
+ << "than " << support_legacy_path_until;
+ }
+ };
+
+ // Order matters here. The more the partition is specific to a product, the higher its
+ // precedence is.
load_properties_from_file("/system/build.prop", nullptr, &properties);
- load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
-
- // TODO(b/117892318): uncomment the following condition when vendor.imgs for
- // aosp_* targets are all updated.
-// if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
- load_properties_from_file("/vendor/default.prop", nullptr, &properties);
-// }
+ load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
+ // TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
+ // all updated.
+ // if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
+ load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+ // }
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
+ load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
+ load_properties_from_partition("product", /* support_legacy_path_until */ 30);
- if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
- load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
- } else {
- load_properties_from_file("/odm/default.prop", nullptr, &properties);
- load_properties_from_file("/odm/build.prop", nullptr, &properties);
- }
-
- load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
if (access(kDebugRamdiskProp, R_OK) == 0) {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index f3dd538..9d4ea8c 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -18,6 +18,8 @@
#include <fcntl.h>
#include <poll.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <unistd.h>
#include <android-base/file.h>
@@ -181,6 +183,8 @@
trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
+ // Restore prio before main loop
+ setpriority(PRIO_PROCESS, 0, 0);
subcontext_process.MainLoop();
return 0;
}
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 7514b61..54659c5 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -321,6 +321,8 @@
while (waitpid(-1, nullptr, WNOHANG) > 0) {
}
+ // Restore prio before main loop
+ setpriority(PRIO_PROCESS, 0, 0);
uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
for (auto& uevent_handler : uevent_handlers) {
uevent_handler->HandleUevent(uevent);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 19c22c8..8cc780a 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -341,6 +341,37 @@
}
//-------------------------------------------------------------------------
+// Fuzzers
+//-------------------------------------------------------------------------
+cc_defaults {
+ name: "libunwindstack_fuzz_defaults",
+ host_supported: true,
+ defaults: ["libunwindstack_flags"],
+ cflags: [
+ "-Wno-exit-time-destructors",
+ "-g",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "liblzma",
+ "libunwindstack",
+ "libdexfile_support",
+ ],
+}
+
+cc_fuzz {
+ name: "libunwindstack_fuzz_unwinder",
+ defaults: ["libunwindstack_fuzz_defaults"],
+ srcs: [
+ "tests/MemoryFake.cpp",
+ "tests/ElfFake.cpp",
+ "tests/fuzz/UnwinderComponentCreator.cpp",
+ "tests/fuzz/UnwinderFuzz.cpp",
+ ],
+}
+
+//-------------------------------------------------------------------------
// Tools
//-------------------------------------------------------------------------
cc_defaults {
@@ -458,3 +489,4 @@
"tests/GenGnuDebugdata.cpp",
],
}
+
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
new file mode 100644
index 0000000..94f5a73
--- /dev/null
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UnwinderComponentCreator.h"
+
+std::unique_ptr<Regs> GetRegisters(ArchEnum arch) {
+ switch (arch) {
+ case unwindstack::ARCH_ARM: {
+ std::unique_ptr<unwindstack::RegsArm> regs = std::make_unique<unwindstack::RegsArm>();
+ return regs;
+ }
+ case unwindstack::ARCH_ARM64: {
+ std::unique_ptr<unwindstack::RegsArm64> regs = std::make_unique<unwindstack::RegsArm64>();
+ return regs;
+ }
+ case unwindstack::ARCH_X86: {
+ std::unique_ptr<unwindstack::RegsX86> regs = std::make_unique<unwindstack::RegsX86>();
+ return regs;
+ }
+ case unwindstack::ARCH_X86_64: {
+ std::unique_ptr<unwindstack::RegsX86_64> regs = std::make_unique<unwindstack::RegsX86_64>();
+ return regs;
+ }
+ case unwindstack::ARCH_MIPS: {
+ std::unique_ptr<unwindstack::RegsMips> regs = std::make_unique<unwindstack::RegsMips>();
+ return regs;
+ }
+ case unwindstack::ARCH_MIPS64: {
+ std::unique_ptr<unwindstack::RegsMips64> regs = std::make_unique<unwindstack::RegsMips64>();
+ return regs;
+ }
+ case unwindstack::ARCH_UNKNOWN:
+ default: {
+ std::unique_ptr<unwindstack::RegsX86_64> regs = std::make_unique<unwindstack::RegsX86_64>();
+ return regs;
+ }
+ }
+}
+
+ArchEnum GetArch(FuzzedDataProvider* data_provider) {
+ uint8_t arch = data_provider->ConsumeIntegralInRange<uint8_t>(1, kArchCount);
+ return static_cast<ArchEnum>(arch);
+}
+
+void ElfAddMapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+ const char* name, Elf* elf = nullptr) {
+ std::string str_name(name);
+ maps->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
+ if (elf != nullptr) {
+ const auto& map_info = *--maps->end();
+ map_info->elf.reset(elf);
+ }
+}
+
+void ElfPushFakeFunctionData(FuzzedDataProvider* data_provider, ElfInterfaceFake* elf) {
+ uint8_t func_count = data_provider->ConsumeIntegralInRange<uint>(0, kMaxFuncCount);
+ for (uint8_t i = 0; i < func_count; i++) {
+ std::string func_name = data_provider->ConsumeRandomLengthString(kMaxFuncNameLen);
+ bool global = data_provider->ConsumeBool();
+ if (global) {
+ elf->FakeSetGlobalVariable(func_name, data_provider->ConsumeIntegral<uint64_t>());
+ } else {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData(func_name, i));
+ }
+ }
+}
+void ElfPushFakeStepData(FuzzedDataProvider* data_provider) {
+ uint8_t step_count = data_provider->ConsumeIntegralInRange<uint>(0, kMaxStepCount);
+ for (uint8_t i = 0; i < step_count; i++) {
+ uint64_t pc = data_provider->ConsumeIntegral<uint64_t>();
+ uint64_t sp = data_provider->ConsumeIntegral<uint64_t>();
+ bool finished = i + 1 == step_count;
+ ElfInterfaceFake::FakePushStepData(StepData(pc, sp, finished));
+ }
+}
+
+ElfFake* PopulateElfFake(FuzzedDataProvider* data_provider) {
+ // This will be passed to a smart pointer in ElfAddMapInfo.
+ ElfFake* elf = new ElfFake(new MemoryFake);
+
+ // This will be handled by a smart pointer within Elf.
+ ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
+ std::string build_id = data_provider->ConsumeRandomLengthString(kMaxBuildIdLen);
+ interface_fake->FakeSetBuildID(build_id);
+ std::string so_name = data_provider->ConsumeRandomLengthString(kMaxSoNameLen);
+ interface_fake->FakeSetSoname(so_name.c_str());
+
+ elf->FakeSetArch(GetArch(data_provider));
+ elf->FakeSetLoadBias(data_provider->ConsumeIntegral<uint64_t>());
+
+ ElfPushFakeFunctionData(data_provider, interface_fake);
+ ElfPushFakeStepData(data_provider);
+
+ elf->FakeSetInterface(interface_fake);
+ ElfInterfaceFake::FakeClear();
+ return elf;
+}
+
+std::unique_ptr<Maps> GetMaps(FuzzedDataProvider* data_provider) {
+ std::unique_ptr<Maps> maps = std::make_unique<Maps>();
+ uint8_t entry_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxMapEntryCount);
+ for (uint8_t i = 0; i < entry_count; i++) {
+ uint64_t start = data_provider->ConsumeIntegral<uint64_t>();
+ uint64_t end = data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX);
+ uint64_t offset = data_provider->ConsumeIntegral<uint64_t>();
+ std::string map_info_name = data_provider->ConsumeRandomLengthString(kMaxMapInfoNameLen);
+ uint8_t flags = PROT_READ | PROT_WRITE;
+
+ bool exec = data_provider->ConsumeBool();
+ if (exec) {
+ flags |= PROT_EXEC;
+ }
+
+ bool shouldAddElf = data_provider->ConsumeBool();
+ if (shouldAddElf) {
+ ElfAddMapInfo(maps.get(), start, end, offset, flags, map_info_name.c_str(),
+ PopulateElfFake(data_provider));
+ } else {
+ ElfAddMapInfo(maps.get(), start, end, offset, flags, map_info_name.c_str());
+ }
+ }
+ maps->Sort();
+ return maps;
+}
+
+// This code (until PutElfFilesInMemory) is pretty much directly copied from JitDebugTest.cpp
+// There's a few minor modifications, most notably, all methods accept a MemoryFake pointer, and
+// PutElfInMemory inserts JIT data when called.
+void WriteDescriptor32(MemoryFake* memory, uint64_t addr, uint32_t entry) {
+ // Format of the 32 bit JITDescriptor structure:
+ // uint32_t version
+ memory->SetData32(addr, 1);
+ // uint32_t action_flag
+ memory->SetData32(addr + 4, 0);
+ // uint32_t relevant_entry
+ memory->SetData32(addr + 8, 0);
+ // uint32_t first_entry
+ memory->SetData32(addr + 12, entry);
+}
+
+void WriteDescriptor64(MemoryFake* memory, uint64_t addr, uint64_t entry) {
+ // Format of the 64 bit JITDescriptor structure:
+ // uint32_t version
+ memory->SetData32(addr, 1);
+ // uint32_t action_flag
+ memory->SetData32(addr + 4, 0);
+ // uint64_t relevant_entry
+ memory->SetData64(addr + 8, 0);
+ // uint64_t first_entry
+ memory->SetData64(addr + 16, entry);
+}
+
+void WriteEntry32Pack(MemoryFake* memory, uint64_t addr, uint32_t prev, uint32_t next,
+ uint32_t elf_addr, uint64_t elf_size) {
+ // Format of the 32 bit JITCodeEntry structure:
+ // uint32_t next
+ memory->SetData32(addr, next);
+ // uint32_t prev
+ memory->SetData32(addr + 4, prev);
+ // uint32_t symfile_addr
+ memory->SetData32(addr + 8, elf_addr);
+ // uint64_t symfile_size
+ memory->SetData64(addr + 12, elf_size);
+}
+
+void WriteEntry32Pad(MemoryFake* memory, uint64_t addr, uint32_t prev, uint32_t next,
+ uint32_t elf_addr, uint64_t elf_size) {
+ // Format of the 32 bit JITCodeEntry structure:
+ // uint32_t next
+ memory->SetData32(addr, next);
+ // uint32_t prev
+ memory->SetData32(addr + 4, prev);
+ // uint32_t symfile_addr
+ memory->SetData32(addr + 8, elf_addr);
+ // uint32_t pad
+ memory->SetData32(addr + 12, 0);
+ // uint64_t symfile_size
+ memory->SetData64(addr + 16, elf_size);
+}
+
+void WriteEntry64(MemoryFake* memory, uint64_t addr, uint64_t prev, uint64_t next,
+ uint64_t elf_addr, uint64_t elf_size) {
+ // Format of the 64 bit JITCodeEntry structure:
+ // uint64_t next
+ memory->SetData64(addr, next);
+ // uint64_t prev
+ memory->SetData64(addr + 8, prev);
+ // uint64_t symfile_addr
+ memory->SetData64(addr + 16, elf_addr);
+ // uint64_t symfile_size
+ memory->SetData64(addr + 24, elf_size);
+}
+
+template <typename EhdrType, typename ShdrType>
+void PutElfInMemory(MemoryFake* memory, uint64_t offset, uint8_t class_type, uint8_t machine_type,
+ uint32_t pc, uint32_t size) {
+ EhdrType ehdr;
+ memset(&ehdr, 0, sizeof(ehdr));
+ uint64_t sh_offset = sizeof(ehdr);
+ memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
+ ehdr.e_ident[EI_CLASS] = class_type;
+ ehdr.e_machine = machine_type;
+ ehdr.e_shstrndx = 1;
+ ehdr.e_shoff = sh_offset;
+ ehdr.e_shentsize = sizeof(ShdrType);
+ ehdr.e_shnum = 3;
+ memory->SetMemory(offset, &ehdr, sizeof(ehdr));
+
+ ShdrType shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_NULL;
+ memory->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
+
+ sh_offset += sizeof(shdr);
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 1;
+ shdr.sh_offset = 0x500;
+ shdr.sh_size = 0x100;
+ memory->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
+ memory->SetMemory(offset + 0x500, ".debug_frame");
+
+ sh_offset += sizeof(shdr);
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_name = 0;
+ shdr.sh_addr = 0x600;
+ shdr.sh_offset = 0x600;
+ shdr.sh_size = 0x200;
+ memory->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
+
+ // Now add a single cie/fde.
+ uint64_t dwarf_offset = offset + 0x600;
+ if (class_type == ELFCLASS32) {
+ // CIE 32 information.
+ memory->SetData32(dwarf_offset, 0xfc);
+ memory->SetData32(dwarf_offset + 0x4, 0xffffffff);
+ memory->SetData8(dwarf_offset + 0x8, 1);
+ memory->SetData8(dwarf_offset + 0x9, '\0');
+ memory->SetData8(dwarf_offset + 0xa, 0x4);
+ memory->SetData8(dwarf_offset + 0xb, 0x4);
+ memory->SetData8(dwarf_offset + 0xc, 0x1);
+
+ // FDE 32 information.
+ memory->SetData32(dwarf_offset + 0x100, 0xfc);
+ memory->SetData32(dwarf_offset + 0x104, 0);
+ memory->SetData32(dwarf_offset + 0x108, pc);
+ memory->SetData32(dwarf_offset + 0x10c, size);
+ } else {
+ // CIE 64 information.
+ memory->SetData32(dwarf_offset, 0xffffffff);
+ memory->SetData64(dwarf_offset + 4, 0xf4);
+ memory->SetData64(dwarf_offset + 0xc, 0xffffffffffffffffULL);
+ memory->SetData8(dwarf_offset + 0x14, 1);
+ memory->SetData8(dwarf_offset + 0x15, '\0');
+ memory->SetData8(dwarf_offset + 0x16, 0x4);
+ memory->SetData8(dwarf_offset + 0x17, 0x4);
+ memory->SetData8(dwarf_offset + 0x18, 0x1);
+
+ // FDE 64 information.
+ memory->SetData32(dwarf_offset + 0x100, 0xffffffff);
+ memory->SetData64(dwarf_offset + 0x104, 0xf4);
+ memory->SetData64(dwarf_offset + 0x10c, 0);
+ memory->SetData64(dwarf_offset + 0x114, pc);
+ memory->SetData64(dwarf_offset + 0x11c, size);
+ }
+}
+
+void PutElfFilesInMemory(MemoryFake* memory, FuzzedDataProvider* data_provider) {
+ uint8_t elf_file_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxJitElfFiles);
+ int entry_offset = 0;
+ int prev_jit_addr = 0;
+ for (uint8_t i = 0; i < elf_file_count; i++) {
+ uint64_t offset = data_provider->ConsumeIntegral<uint64_t>();
+ // Technically the max valid value is ELFCLASSNUM - 1 (2), but
+ // we want to test values outside of that range.
+ uint8_t class_type = data_provider->ConsumeIntegral<uint8_t>();
+ // Same here, EM_NUM is 253, max valid machine type is 252
+ uint8_t machine_type = data_provider->ConsumeIntegral<uint8_t>();
+ uint32_t pc = data_provider->ConsumeIntegral<uint32_t>();
+ uint32_t size = data_provider->ConsumeIntegral<uint32_t>();
+ bool sixty_four_bit = data_provider->ConsumeBool();
+ bool write_jit = data_provider->ConsumeBool();
+ if (sixty_four_bit) {
+ PutElfInMemory<Elf64_Ehdr, Elf64_Shdr>(memory, offset, class_type, machine_type, pc, size);
+ } else {
+ PutElfInMemory<Elf32_Ehdr, Elf32_Shdr>(memory, offset, class_type, machine_type, pc, size);
+ }
+ if (write_jit) {
+ bool use_pad = data_provider->ConsumeBool();
+ // It is possible this will overwrite part of the ELF.
+ // This provides an interesting test of how malformed ELF
+ // data is handled.
+ uint64_t cur_descriptor_addr = 0x11800 + entry_offset;
+ uint64_t cur_jit_addr = 0x200000 + entry_offset;
+ uint64_t next_jit_addr = cur_jit_addr + size;
+ if (sixty_four_bit) {
+ WriteDescriptor64(memory, 0x11800, cur_jit_addr);
+ WriteEntry64(memory, cur_jit_addr, prev_jit_addr, next_jit_addr, pc, size);
+ } else {
+ // Loop back. Again, this may corrupt data,
+ // but that will allow for testing edge cases with
+ // malformed JIT data.
+ if (cur_jit_addr > UINT32_MAX) {
+ entry_offset = 0;
+ cur_jit_addr = 0x200000;
+ cur_descriptor_addr = 0x11800;
+ next_jit_addr = cur_jit_addr + size;
+ }
+ WriteDescriptor32(memory, cur_descriptor_addr, cur_jit_addr);
+ if (use_pad) {
+ WriteEntry32Pad(memory, cur_jit_addr, prev_jit_addr, next_jit_addr, pc, size);
+ } else {
+ WriteEntry32Pack(memory, cur_jit_addr, prev_jit_addr, next_jit_addr, pc, size);
+ }
+ }
+ entry_offset += size;
+ prev_jit_addr = cur_jit_addr;
+ }
+ }
+}
+
+std::vector<std::string> GetStringList(FuzzedDataProvider* data_provider, uint max_str_len,
+ uint max_strings) {
+ uint str_count = data_provider->ConsumeIntegralInRange<uint>(0, max_strings);
+ std::vector<std::string> strings;
+ for (uint i = 0; i < str_count; i++) {
+ strings.push_back(data_provider->ConsumeRandomLengthString(max_str_len));
+ }
+ return strings;
+}
+
+std::unique_ptr<DexFiles> GetDexFiles(FuzzedDataProvider* data_provider,
+ std::shared_ptr<Memory> memory, uint max_library_length,
+ uint max_libraries) {
+ std::vector<std::string> search_libs =
+ GetStringList(data_provider, max_library_length, max_libraries);
+ if (search_libs.size() <= 0) {
+ return std::make_unique<DexFiles>(memory);
+ }
+
+ return std::make_unique<DexFiles>(memory, search_libs);
+}
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
new file mode 100644
index 0000000..09b3379
--- /dev/null
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
+#define _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
+
+#include <elf.h>
+#include <sys/mman.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
+
+#include "../ElfFake.h"
+#include "../MemoryFake.h"
+
+#include "fuzzer/FuzzedDataProvider.h"
+
+using unwindstack::ArchEnum;
+using unwindstack::DexFiles;
+using unwindstack::Elf;
+using unwindstack::ElfFake;
+using unwindstack::ElfInterfaceFake;
+using unwindstack::FunctionData;
+using unwindstack::Maps;
+using unwindstack::Memory;
+using unwindstack::MemoryFake;
+using unwindstack::Regs;
+using unwindstack::StepData;
+
+static constexpr uint8_t kArchCount = 6;
+
+static constexpr uint8_t kMaxSoNameLen = 150;
+
+static constexpr uint8_t kMaxFuncNameLen = 50;
+static constexpr uint8_t kMaxFuncCount = 100;
+
+static constexpr uint8_t kMaxJitElfFiles = 20;
+static constexpr uint8_t kJitElfPadding = 32;
+
+static constexpr uint8_t kMaxStepCount = 100;
+static constexpr uint8_t kMaxMapEntryCount = 50;
+static constexpr uint8_t kMaxBuildIdLen = 100;
+static constexpr uint8_t kMaxMapInfoNameLen = 150;
+
+std::unique_ptr<unwindstack::Regs> GetRegisters(unwindstack::ArchEnum arch);
+std::unique_ptr<unwindstack::Maps> GetMaps(FuzzedDataProvider* data_provider);
+std::vector<std::string> GetStringList(FuzzedDataProvider* data_provider, uint max_str_len,
+ uint max_strings);
+unwindstack::ArchEnum GetArch(FuzzedDataProvider* data_provider);
+
+void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name,
+ Elf* elf = nullptr);
+void PutElfFilesInMemory(MemoryFake* memory, FuzzedDataProvider* data_provider);
+
+std::unique_ptr<unwindstack::DexFiles> GetDexFiles(FuzzedDataProvider* data_provider,
+ std::shared_ptr<unwindstack::Memory> memory,
+ uint max_libraries, uint max_library_length);
+#endif // _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
diff --git a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
new file mode 100644
index 0000000..2f4986a
--- /dev/null
+++ b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <functional>
+#include <iostream>
+#include <vector>
+
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Unwinder.h>
+
+#include "../MemoryFake.h"
+#include "UnwinderComponentCreator.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+namespace unwindstack {
+
+static constexpr int kMaxUnwindStringLen = 50;
+static constexpr int kMaxUnwindStrings = 50;
+
+void PerformUnwind(FuzzedDataProvider* data_provider, Unwinder* unwinder) {
+ // 0 = don't set any values
+ // 1 = set initial_map_names_to_skip
+ // 2 = set map_suffixes_to_ignore
+ // 3 = set both
+ uint8_t set_values = data_provider->ConsumeIntegral<uint8_t>() % 4;
+ if (set_values == 0) {
+ unwinder->Unwind();
+ } else if (set_values == 1) {
+ // Only setting initial_map_names_to_skip
+ std::vector<std::string> skip_names =
+ GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
+
+ unwinder->Unwind(&skip_names, nullptr);
+ } else if (set_values == 2) {
+ // Only setting map_suffixes_to_ignore
+ std::vector<std::string> ignore_suffixes =
+ GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
+
+ unwinder->Unwind(nullptr, &ignore_suffixes);
+ } else if (set_values == 3) {
+ // Setting both values
+ std::vector<std::string> skip_names =
+ GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
+ std::vector<std::string> ignore_suffixes =
+ GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
+
+ unwinder->Unwind(&skip_names, &ignore_suffixes);
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider data_provider(data, size);
+
+ // We need to construct an unwinder.
+ // Generate the Maps:
+ std::unique_ptr<Maps> maps = GetMaps(&data_provider);
+
+ // Generate the Regs:
+ uint8_t arch_val = data_provider.ConsumeIntegralInRange<uint8_t>(1, kArchCount);
+ ArchEnum arch = static_cast<ArchEnum>(arch_val);
+ std::unique_ptr<Regs> regs = GetRegisters(arch);
+
+ // Generate memory:
+ std::shared_ptr<Memory> memory = std::make_shared<MemoryFake>();
+ PutElfFilesInMemory(reinterpret_cast<MemoryFake*>(memory.get()), &data_provider);
+
+ size_t max_frames = data_provider.ConsumeIntegralInRange<size_t>(0, 5000);
+
+ std::unique_ptr<JitDebug> jit_debug_ptr = std::make_unique<JitDebug>(memory);
+
+ // Create instance
+ Unwinder unwinder(max_frames, maps.get(), regs.get(), memory);
+ unwinder.SetJitDebug(jit_debug_ptr.get(), arch);
+ unwinder.SetResolveNames(data_provider.ConsumeBool());
+ // Call unwind
+ PerformUnwind(&data_provider, &unwinder);
+
+ // Run some additional logic that changes after unwind
+ uint64_t pc = data_provider.ConsumeIntegral<uint64_t>();
+ unwinder.BuildFrameFromPcOnly(pc);
+ unwinder.ConsumeFrames();
+ return 0;
+}
+} // namespace unwindstack
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 7392806..9bd15c6 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -78,6 +78,9 @@
"libcutils",
"liblog",
],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
target: {
android: {