Add a fuzzer for gptfdisk.
Since gptfdisk is used to parse MBR and GPT partition tables from
untrusted USB and SD card storage devices, we should get a fuzzer
wired up to hunt for security issues.
To enable the fuzzer, we create a new "diskio-heap" implementation
for backing I/O operations, which allows us to treat the fuzzer
input as a fake block device. These changes are as minimal as
possible to avoid future merge conflicts.
The single corpus input is a sample block device with a single
empty GPT partition created using these commands:
$ losetup /dev/loop0 typical.bin
$ gdisk /dev/loop0
And the final table is:
Number Start (sector) End (sector) Size Code Name
1 34 38 2.5 KiB 8300 Linux filesystem
Bug: 170783842
Test: SANITIZE_HOST=address make ${FUZZER_NAME} && ${ANDROID_HOST_OUT}/fuzz/$(get_build_var HOST_ARCH)/${FUZZER_NAME}/${FUZZER_NAME}
Change-Id: I21a2a5f7f1019365accf8fd74c958aaafe7f7ff7
This commit is contained in:
69
Android.bp
69
Android.bp
@@ -1,28 +1,35 @@
|
|||||||
|
cc_defaults {
|
||||||
|
name: "gptfdisk_default_flags",
|
||||||
|
cflags: [
|
||||||
|
"-Wno-unused-parameter",
|
||||||
|
"-Wno-pragma-pack",
|
||||||
|
"-Werror",
|
||||||
|
"-fPIC",
|
||||||
|
],
|
||||||
|
target: {
|
||||||
|
darwin: {
|
||||||
|
cflags: [
|
||||||
|
"-D_FILE_OFFSET_BITS=64",
|
||||||
|
"-Doff64_t=off_t",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
cc_binary {
|
cc_binary {
|
||||||
name: "sgdisk",
|
name: "sgdisk",
|
||||||
|
defaults: ["gptfdisk_default_flags"],
|
||||||
host_supported: true,
|
host_supported: true,
|
||||||
|
|
||||||
srcs: [
|
srcs: [
|
||||||
"sgdisk.cc",
|
"sgdisk.cc",
|
||||||
],
|
],
|
||||||
cflags: [
|
|
||||||
"-Wno-unused-parameter",
|
|
||||||
"-Wno-pragma-pack",
|
|
||||||
"-Werror",
|
|
||||||
],
|
|
||||||
|
|
||||||
shared_libs: ["libext2_uuid"],
|
shared_libs: ["libext2_uuid"],
|
||||||
static_libs: ["libgptf"],
|
static_libs: ["libgptf"],
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_library_static {
|
lib_common_srcs = [
|
||||||
name: "libgptf",
|
|
||||||
host_supported: true,
|
|
||||||
|
|
||||||
export_include_dirs:["."],
|
|
||||||
|
|
||||||
srcs: [
|
|
||||||
"gptcl.cc",
|
"gptcl.cc",
|
||||||
"crc32.cc",
|
"crc32.cc",
|
||||||
"support.cc",
|
"support.cc",
|
||||||
@@ -36,24 +43,28 @@ cc_library_static {
|
|||||||
"parttypes.cc",
|
"parttypes.cc",
|
||||||
"attributes.cc",
|
"attributes.cc",
|
||||||
"diskio.cc",
|
"diskio.cc",
|
||||||
"diskio-unix.cc",
|
|
||||||
"android_popt.cc",
|
"android_popt.cc",
|
||||||
],
|
]
|
||||||
cflags: [
|
|
||||||
"-Wno-unused-parameter",
|
|
||||||
"-Wno-pragma-pack",
|
|
||||||
"-Werror",
|
|
||||||
"-fPIC",
|
|
||||||
],
|
|
||||||
|
|
||||||
target: {
|
cc_library_static {
|
||||||
darwin: {
|
name: "libgptf",
|
||||||
cflags: [
|
defaults: ["gptfdisk_default_flags"],
|
||||||
"-D_FILE_OFFSET_BITS=64",
|
host_supported: true,
|
||||||
"-Doff64_t=off_t",
|
|
||||||
],
|
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"],
|
shared_libs: ["libext2_uuid"],
|
||||||
}
|
}
|
||||||
|
|||||||
86
diskio-heap.cc
Normal file
86
diskio-heap.cc
Normal file
@@ -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 <algorithm>
|
||||||
|
|
||||||
|
#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<int>(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();
|
||||||
|
}
|
||||||
8
diskio.h
8
diskio.h
@@ -56,12 +56,20 @@ class DiskIO {
|
|||||||
HANDLE fd;
|
HANDLE fd;
|
||||||
#else
|
#else
|
||||||
int fd;
|
int fd;
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_HEAP_DISKIO
|
||||||
|
const unsigned char* data;
|
||||||
|
size_t size;
|
||||||
|
off_t off;
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
DiskIO(void);
|
DiskIO(void);
|
||||||
~DiskIO(void);
|
~DiskIO(void);
|
||||||
|
|
||||||
void MakeRealName(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(const string & filename);
|
||||||
int OpenForRead(void);
|
int OpenForRead(void);
|
||||||
int OpenForWrite(const string & filename);
|
int OpenForWrite(const string & filename);
|
||||||
|
|||||||
22
fuzzer/Android.bp
Normal file
22
fuzzer/Android.bp
Normal file
@@ -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",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
BIN
fuzzer/corpus/typical.bin
Normal file
BIN
fuzzer/corpus/typical.bin
Normal file
Binary file not shown.
43
fuzzer/libgptf_fuzzer.cc
Normal file
43
fuzzer/libgptf_fuzzer.cc
Normal file
@@ -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 <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "diskio.h"
|
||||||
|
#include "mbr.h"
|
||||||
|
#include "gpt.h"
|
||||||
|
|
||||||
|
#include <fuzzer/FuzzedDataProvider.h>
|
||||||
|
|
||||||
|
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<const unsigned char*>(data), size);
|
||||||
|
|
||||||
|
BasicMBRData mbrData;
|
||||||
|
mbrData.ReadMBRData(&disk);
|
||||||
|
|
||||||
|
GPTData gptData;
|
||||||
|
gptData.SetDisk(disk);
|
||||||
|
gptData.LoadPartitions("/dev/does_not_exist");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
5
gpt.cc
5
gpt.cc
@@ -780,6 +780,11 @@ int GPTData::SetDisk(const string & deviceFilename) {
|
|||||||
return allOK;
|
return allOK;
|
||||||
} // GPTData::SetDisk()
|
} // 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
|
// Scan for partition data. This function loads the MBR data (regular MBR or
|
||||||
// protective MBR) and loads BSD disklabel data (which is probably invalid).
|
// 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
|
// It also looks for APM data, forces a load of GPT data, and summarizes
|
||||||
|
|||||||
1
gpt.h
1
gpt.h
@@ -112,6 +112,7 @@ public:
|
|||||||
|
|
||||||
// Load or save data from/to disk
|
// Load or save data from/to disk
|
||||||
int SetDisk(const string & deviceFilename);
|
int SetDisk(const string & deviceFilename);
|
||||||
|
int SetDisk(const DiskIO & disk);
|
||||||
DiskIO* GetDisk(void) {return &myDisk;}
|
DiskIO* GetDisk(void) {return &myDisk;}
|
||||||
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
|
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
|
||||||
int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}
|
int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}
|
||||||
|
|||||||
Reference in New Issue
Block a user