144 lines
4.3 KiB
C++
144 lines
4.3 KiB
C++
// Copyright (C) 2018-2022 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
/*!
|
|
\file
|
|
\brief Replacement of libFuzzer main entrypoint.
|
|
|
|
[libFuzzer](https://llvm.org/docs/LibFuzzer.html), part of LLVM toolchain,
|
|
implements `main` entry point which runs in-process fuzzing. This provides
|
|
a simplified `main` entry point implementation which is limited to processing
|
|
the inputs.
|
|
*/
|
|
|
|
#if !defined(WITH_LIBFUZZER)
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
#ifdef _WIN32
|
|
# include <windows.h>
|
|
#else // WIN32
|
|
# include <dirent.h>
|
|
# include <sys/stat.h>
|
|
# include <sys/types.h>
|
|
#endif // WIN32
|
|
|
|
/// Fuzzing target
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
|
|
|
|
/// Get basename from path
|
|
std::string basename(std::string const& path) {
|
|
std::string str = std::string("/") + path;
|
|
return str.substr(str.find_last_of("/\\") + 1);
|
|
}
|
|
|
|
/// Get directory content
|
|
std::vector<std::string> list_dir(std::string const& path) {
|
|
std::vector<std::string> res;
|
|
#ifdef _WIN32
|
|
WIN32_FIND_DATA find_data;
|
|
HANDLE find_handle;
|
|
find_handle = FindFirstFile((path + "\\*").c_str(), &find_data);
|
|
if (INVALID_HANDLE_VALUE != find_handle) {
|
|
do {
|
|
std::string filename(find_data.cFileName);
|
|
if (filename == "." || filename == "..") continue;
|
|
res.push_back(path + "\\" + filename);
|
|
} while (FindNextFile(find_handle, &find_data));
|
|
FindClose(find_handle);
|
|
}
|
|
#else // WIN32
|
|
DIR* dir = opendir(path.c_str());
|
|
if (dir) {
|
|
struct dirent* entry;
|
|
while (NULL != (entry = readdir(dir))) {
|
|
if (DT_REG == entry->d_type) res.push_back(path + "/" + std::string(entry->d_name));
|
|
}
|
|
closedir(dir);
|
|
dir = NULL;
|
|
}
|
|
#endif // WIN32
|
|
return res;
|
|
}
|
|
|
|
// Check if file by given path is a directory.
|
|
bool is_dir(std::string const& path) {
|
|
#ifdef _WIN32
|
|
return 0 != (FILE_ATTRIBUTE_DIRECTORY & GetFileAttributes(path.c_str()));
|
|
#else // WIN32
|
|
struct stat stat_res = {0};
|
|
stat(path.c_str(), &stat_res);
|
|
return S_IFDIR & stat_res.st_mode;
|
|
#endif // WIN32
|
|
}
|
|
|
|
// Print usage help
|
|
void print_usage(const std::string& program_name, std::ostream* os) {
|
|
*os << "Usage: " << program_name << " INPUT" << std::endl;
|
|
}
|
|
|
|
/// Main entrypoint
|
|
extern "C" int main(int argc, char* argv[]) {
|
|
std::string program_name = basename(argv[0]);
|
|
|
|
// Parse command line options
|
|
std::vector<std::string> positional;
|
|
for (int i = 1; i < argc; i++) {
|
|
std::string arg(argv[i]);
|
|
// Ignore all options but positional arguments
|
|
if ('-' == arg[0]) {
|
|
std::cout << "Ignoring option " << arg << std::endl;
|
|
continue;
|
|
}
|
|
positional.push_back(arg);
|
|
}
|
|
if (1 != positional.size()) {
|
|
std::cerr << program_name << ": error: wrong number of positional arguments." << std::endl;
|
|
print_usage(program_name, &std::cerr);
|
|
return -1;
|
|
}
|
|
|
|
// Run input files through test function
|
|
std::vector<std::string> input_files;
|
|
if (is_dir(positional[0])) {
|
|
std::cout << "Loading corpus dir: " << positional[0] << std::endl;
|
|
input_files = list_dir(positional[0]);
|
|
} else {
|
|
std::cout << "Running: " << positional[0] << std::endl;
|
|
input_files.push_back(positional[0]);
|
|
}
|
|
time_t time_total = 0;
|
|
for (auto const& path : input_files) {
|
|
std::ifstream test_file(path, std::ios::binary);
|
|
if (!test_file) {
|
|
std::cerr << program_name << ": error: failed to open \"" << path << "\"" << std::endl;
|
|
return -2;
|
|
}
|
|
std::ostringstream data;
|
|
data << test_file.rdbuf();
|
|
test_file.close();
|
|
|
|
time_t time_start = time(nullptr);
|
|
int fuzzer_res;
|
|
if (0 != (fuzzer_res = LLVMFuzzerTestOneInput((const uint8_t*)data.str().c_str(), data.str().size()))) {
|
|
std::cerr << program_name << ": error: testing \"" << path << "\" fails" << std::endl;
|
|
return fuzzer_res;
|
|
}
|
|
time_total += time(nullptr) - time_start;
|
|
}
|
|
std::cout << "Executed " << input_files.size() << " item(s) in " << time_total << " seconds" << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
#endif // !defined(WITH_LIBFUZZER)
|