Merge "Added fuzzer for Unwinder" am: e28cc8cf48
Original change: https://android-review.googlesource.com/c/platform/system/core/+/1318953 Change-Id: If64ec3c8d305487782c8651173c47d8b7c26616c
This commit is contained in:
commit
e7ab54aba3
4 changed files with 570 additions and 0 deletions
|
|
@ -340,6 +340,37 @@ cc_test {
|
|||
isolated: true,
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// 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
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
@ -458,3 +489,4 @@ cc_binary_host {
|
|||
"tests/GenGnuDebugdata.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
|||
356
libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
Normal file
356
libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
Normal file
|
|
@ -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);
|
||||
}
|
||||
83
libunwindstack/tests/fuzz/UnwinderComponentCreator.h
Normal file
83
libunwindstack/tests/fuzz/UnwinderComponentCreator.h
Normal file
|
|
@ -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
|
||||
99
libunwindstack/tests/fuzz/UnwinderFuzz.cpp
Normal file
99
libunwindstack/tests/fuzz/UnwinderFuzz.cpp
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue