diff --git a/Android.bp b/Android.bp index d8a9f3a..1aaa7e6 100644 --- a/Android.bp +++ b/Android.bp @@ -1,51 +1,11 @@ -cc_binary { - name: "sgdisk", - host_supported: true, - - srcs: [ - "sgdisk.cc", - ], - cflags: [ - "-Wno-unused-parameter", - "-Wno-pragma-pack", - "-Werror", - ], - - shared_libs: ["libext2_uuid"], - static_libs: ["libgptf"], - -} - -cc_library_static { - name: "libgptf", - host_supported: true, - - export_include_dirs:["."], - - srcs: [ - "gptcl.cc", - "crc32.cc", - "support.cc", - "guid.cc", - "gptpart.cc", - "mbrpart.cc", - "basicmbr.cc", - "mbr.cc", - "gpt.cc", - "bsd.cc", - "parttypes.cc", - "attributes.cc", - "diskio.cc", - "diskio-unix.cc", - "android_popt.cc", - ], +cc_defaults { + name: "gptfdisk_default_flags", cflags: [ "-Wno-unused-parameter", "-Wno-pragma-pack", "-Werror", "-fPIC", ], - target: { darwin: { cflags: [ @@ -54,6 +14,57 @@ cc_library_static { ], }, }, +} + +cc_binary { + name: "sgdisk", + defaults: ["gptfdisk_default_flags"], + host_supported: true, + + srcs: [ + "sgdisk.cc", + ], + + shared_libs: ["libext2_uuid"], + static_libs: ["libgptf"], +} + +lib_common_srcs = [ + "gptcl.cc", + "crc32.cc", + "support.cc", + "guid.cc", + "gptpart.cc", + "mbrpart.cc", + "basicmbr.cc", + "mbr.cc", + "gpt.cc", + "bsd.cc", + "parttypes.cc", + "attributes.cc", + "diskio.cc", + "android_popt.cc", +] + +cc_library_static { + name: "libgptf", + defaults: ["gptfdisk_default_flags"], + host_supported: true, + + export_include_dirs: ["."], + srcs: lib_common_srcs + ["diskio-unix.cc"], + + shared_libs: ["libext2_uuid"], +} + +cc_library_static { + name: "libgptf_fuzzer_lib", + defaults: ["gptfdisk_default_flags"], + host_supported: true, + + export_include_dirs: ["."], + srcs: lib_common_srcs + ["diskio-heap.cc"], + cflags: ["-DENABLE_HEAP_DISKIO"], shared_libs: ["libext2_uuid"], } diff --git a/diskio-heap.cc b/diskio-heap.cc new file mode 100644 index 0000000..3129113 --- /dev/null +++ b/diskio-heap.cc @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "diskio.h" + +using namespace std; + +int DiskIO::OpenForRead(const unsigned char* data, size_t size) { + this->data = data; + this->size = size; + this->off = 0; + this->isOpen = 1; + this->openForWrite = 0; + return 1; +} + +void DiskIO::MakeRealName(void) { + realFilename = userFilename; +} + +int DiskIO::OpenForRead(void) { + return 1; +} + +int DiskIO::OpenForWrite(void) { + return 1; +} + +void DiskIO::Close(void) { +} + +int DiskIO::GetBlockSize(void) { + return 512; +} + +int DiskIO::GetPhysBlockSize(void) { + return 512; +} + +uint32_t DiskIO::GetNumHeads(void) { + return 255; +} + +uint32_t DiskIO::GetNumSecsPerTrack(void) { + return 63; +} + +int DiskIO::DiskSync(void) { + return 1; +} + +int DiskIO::Seek(uint64_t sector) { + off_t off = sector * GetBlockSize(); + if (off >= this->size) { + return 0; + } else { + this->off = off; + return 1; + } +} + +int DiskIO::Read(void* buffer, int numBytes) { + int actualBytes = std::min(static_cast(this->size - this->off), numBytes); + memcpy(buffer, this->data + this->off, actualBytes); + return actualBytes; +} + +int DiskIO::Write(void*, int) { + return 0; +} + +uint64_t DiskIO::DiskSize(int *) { + return this->size / GetBlockSize(); +} diff --git a/diskio.h b/diskio.h index 0bdaba4..8521b8e 100644 --- a/diskio.h +++ b/diskio.h @@ -56,12 +56,20 @@ class DiskIO { HANDLE fd; #else int fd; +#endif +#ifdef ENABLE_HEAP_DISKIO + const unsigned char* data; + size_t size; + off_t off; #endif public: DiskIO(void); ~DiskIO(void); void MakeRealName(void); +#ifdef ENABLE_HEAP_DISKIO + int OpenForRead(const unsigned char* data, size_t size); +#endif int OpenForRead(const string & filename); int OpenForRead(void); int OpenForWrite(const string & filename); diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp new file mode 100644 index 0000000..ea92f96 --- /dev/null +++ b/fuzzer/Android.bp @@ -0,0 +1,22 @@ +cc_fuzz { + name: "libgptf_fuzzer", + srcs: ["libgptf_fuzzer.cc"], + cflags: ["-DENABLE_HEAP_DISKIO"], + host_supported: true, + corpus: ["corpus/*"], + static_libs: ["libgmock"], + target: { + android: { + static_libs: [ + "libgptf_fuzzer_lib", + "libext2_uuid", + ], + }, + host: { + static_libs: [ + "libgptf_fuzzer_lib", + "libext2_uuid", + ], + }, + }, +} diff --git a/fuzzer/corpus/typical.bin b/fuzzer/corpus/typical.bin new file mode 100644 index 0000000..666506e Binary files /dev/null and b/fuzzer/corpus/typical.bin differ diff --git a/fuzzer/libgptf_fuzzer.cc b/fuzzer/libgptf_fuzzer.cc new file mode 100644 index 0000000..688167a --- /dev/null +++ b/fuzzer/libgptf_fuzzer.cc @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "diskio.h" +#include "mbr.h" +#include "gpt.h" + +#include + +std::ofstream silence("/dev/null"); + +extern "C" int LLVMFuzzerInitialize(int *, char ***) { + std::cout.rdbuf(silence.rdbuf()); + std::cerr.rdbuf(silence.rdbuf()); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + DiskIO disk; + disk.OpenForRead(static_cast(data), size); + + BasicMBRData mbrData; + mbrData.ReadMBRData(&disk); + + GPTData gptData; + gptData.SetDisk(disk); + gptData.LoadPartitions("/dev/does_not_exist"); + + return 0; +} diff --git a/gpt.cc b/gpt.cc index 2d2e72c..8ab6975 100644 --- a/gpt.cc +++ b/gpt.cc @@ -780,6 +780,11 @@ int GPTData::SetDisk(const string & deviceFilename) { return allOK; } // GPTData::SetDisk() +int GPTData::SetDisk(const DiskIO & disk) { + myDisk = disk; + return 1; +} // GPTData::SetDisk() + // Scan for partition data. This function loads the MBR data (regular MBR or // protective MBR) and loads BSD disklabel data (which is probably invalid). // It also looks for APM data, forces a load of GPT data, and summarizes diff --git a/gpt.h b/gpt.h index a5be961..0712a1f 100644 --- a/gpt.h +++ b/gpt.h @@ -112,6 +112,7 @@ public: // Load or save data from/to disk int SetDisk(const string & deviceFilename); + int SetDisk(const DiskIO & disk); DiskIO* GetDisk(void) {return &myDisk;} int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);} int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}