forked from OSchip/llvm-project
[libFuzzer] Error and exit if user supplied fuzzer writeable directories don't exist
Currently, libFuzzer will exit with an error message if a non-existent corpus directory is provided. However, if a user provides a non-existent directory for the `artifact_prefix`, `exact_artifact_path`, or `features_dir`, libFuzzer will continue execution but silently fail to write artifacts/features. To improve the user experience, this PR adds validation for the existence of all user supplied directories before executing the main fuzzing loop. If they don't exist, libFuzzer will exit with an error message. Patch By: dgg5503 Reviewed By: morehouse Differential Revision: https://reviews.llvm.org/D84808
This commit is contained in:
parent
5b9c2b1bea
commit
2392ff093a
|
@ -250,6 +250,13 @@ static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
|
|||
}
|
||||
}
|
||||
|
||||
static void ValidateDirectoryExists(const std::string &Path) {
|
||||
if (!Path.empty() && !IsDirectory(Path)) {
|
||||
Printf("ERROR: The required directory \"%s\" does not exist\n", Path.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string CloneArgsWithoutX(const Vector<std::string> &Args,
|
||||
const char *X1, const char *X2) {
|
||||
std::string Cmd;
|
||||
|
@ -678,13 +685,32 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
|||
Options.MallocLimitMb = Options.RssLimitMb;
|
||||
if (Flags.runs >= 0)
|
||||
Options.MaxNumberOfRuns = Flags.runs;
|
||||
if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
|
||||
Options.OutputCorpus = (*Inputs)[0];
|
||||
if (!Inputs->empty() && !Flags.minimize_crash_internal_step) {
|
||||
// Ensure output corpus assumed to be the first arbitrary argument input
|
||||
// is not a path to an existing file.
|
||||
std::string OutputCorpusDir = (*Inputs)[0];
|
||||
if (!IsFile(OutputCorpusDir)) {
|
||||
Options.OutputCorpus = OutputCorpusDir;
|
||||
ValidateDirectoryExists(Options.OutputCorpus);
|
||||
}
|
||||
}
|
||||
Options.ReportSlowUnits = Flags.report_slow_units;
|
||||
if (Flags.artifact_prefix)
|
||||
if (Flags.artifact_prefix) {
|
||||
Options.ArtifactPrefix = Flags.artifact_prefix;
|
||||
if (Flags.exact_artifact_path)
|
||||
|
||||
// Since the prefix could be a full path to a file name prefix, assume
|
||||
// that if the path ends with the platform's separator that a directory
|
||||
// is desired
|
||||
std::string ArtifactPathDir = Options.ArtifactPrefix;
|
||||
if (!IsSeparator(ArtifactPathDir[ArtifactPathDir.length() - 1])) {
|
||||
ArtifactPathDir = DirName(ArtifactPathDir);
|
||||
}
|
||||
ValidateDirectoryExists(ArtifactPathDir);
|
||||
}
|
||||
if (Flags.exact_artifact_path) {
|
||||
Options.ExactArtifactPath = Flags.exact_artifact_path;
|
||||
ValidateDirectoryExists(DirName(Options.ExactArtifactPath));
|
||||
}
|
||||
Vector<Unit> Dictionary;
|
||||
if (Flags.dict)
|
||||
if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
|
||||
|
@ -707,8 +733,10 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
|||
Options.FocusFunction = Flags.focus_function;
|
||||
if (Flags.data_flow_trace)
|
||||
Options.DataFlowTrace = Flags.data_flow_trace;
|
||||
if (Flags.features_dir)
|
||||
if (Flags.features_dir) {
|
||||
Options.FeaturesDir = Flags.features_dir;
|
||||
ValidateDirectoryExists(Options.FeaturesDir);
|
||||
}
|
||||
if (Flags.collect_data_flow)
|
||||
Options.CollectDataFlow = Flags.collect_data_flow;
|
||||
if (Flags.stop_file)
|
||||
|
|
|
@ -58,6 +58,7 @@ void RawPrint(const char *Str);
|
|||
|
||||
// Platform specific functions:
|
||||
bool IsFile(const std::string &Path);
|
||||
bool IsDirectory(const std::string &Path);
|
||||
size_t FileSize(const std::string &Path);
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
|
@ -82,6 +83,7 @@ struct SizedFile {
|
|||
void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
|
||||
|
||||
char GetSeparator();
|
||||
bool IsSeparator(char C);
|
||||
// Similar to the basename utility: returns the file name w/o the dir prefix.
|
||||
std::string Basename(const std::string &Path);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ bool IsFile(const std::string &Path) {
|
|||
return S_ISREG(St.st_mode);
|
||||
}
|
||||
|
||||
static bool IsDirectory(const std::string &Path) {
|
||||
bool IsDirectory(const std::string &Path) {
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St))
|
||||
return false;
|
||||
|
@ -104,6 +104,10 @@ char GetSeparator() {
|
|||
return '/';
|
||||
}
|
||||
|
||||
bool IsSeparator(char C) {
|
||||
return C == '/';
|
||||
}
|
||||
|
||||
FILE* OpenFile(int Fd, const char* Mode) {
|
||||
return fdopen(Fd, Mode);
|
||||
}
|
||||
|
|
|
@ -76,6 +76,18 @@ static bool IsDir(DWORD FileAttrs) {
|
|||
return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
bool IsDirectory(const std::string &Path) {
|
||||
DWORD Att = GetFileAttributesA(Path.c_str());
|
||||
|
||||
if (Att == INVALID_FILE_ATTRIBUTES) {
|
||||
Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
|
||||
Path.c_str(), GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsDir(Att);
|
||||
}
|
||||
|
||||
std::string Basename(const std::string &Path) {
|
||||
size_t Pos = Path.find_last_of("/\\");
|
||||
if (Pos == std::string::npos) return Path;
|
||||
|
@ -227,7 +239,7 @@ intptr_t GetHandleFromFd(int fd) {
|
|||
return _get_osfhandle(fd);
|
||||
}
|
||||
|
||||
static bool IsSeparator(char C) {
|
||||
bool IsSeparator(char C) {
|
||||
return C == '\\' || C == '/';
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ RUN: %run %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG
|
|||
LONG: INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 8192 bytes
|
||||
RUN: rm -rf %t/SUB1
|
||||
|
||||
RUN: not %run %t-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR
|
||||
NONEXISTENT_DIR: No such file or directory: NONEXISTENT_DIR; exiting
|
||||
|
||||
RUN: rm -rf %t.dir && mkdir -p %t.dir
|
||||
RUN: not %run %t-SimpleTest -artifact_prefix=%t.dir/NONEXISTENT_DIR/ 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR_RGX
|
||||
RUN: not %run %t-SimpleTest -artifact_prefix=%t.dir/NONEXISTENT_DIR/myprefix 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR_RGX
|
||||
RUN: not %run %t-SimpleTest -features_dir=%t.dir/NONEXISTENT_DIR/ 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR_RGX
|
||||
RUN: not %run %t-SimpleTest %t.dir/NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR_RGX
|
||||
RUN: not %run %t-SimpleTest -exact_artifact_path=%t.dir/NONEXISTENT_DIR/myprefix 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR_RGX
|
||||
NONEXISTENT_DIR_RGX: ERROR: The required directory "{{.*/NONEXISTENT_DIR/?}}" does not exist
|
||||
|
|
Loading…
Reference in New Issue