diff --git a/logistic/packer.go b/logistic/packer.go index 3e90089..0a4820f 100644 --- a/logistic/packer.go +++ b/logistic/packer.go @@ -33,7 +33,6 @@ func PackFuzzers(fuzzers []string, fuzzerDirectory string) ([]byte, error) { // Essentially we want to pack three things from each targeted fuzzer: // - the fuzz_bitmap file // - the fuzzer_stats file - // - the is_main_fuzzer file if present // - the queue/ directory - but avoiding duplicates var pkgCont []string // list of queue files already present in the archive for _, fuzzer := range fuzzers { @@ -42,9 +41,8 @@ func PackFuzzers(fuzzers []string, fuzzerDirectory string) ([]byte, error) { relFuzzerPath := strings.TrimPrefix(fuzzer, fuzzerDirectory) // Read-n-Pack™ - packSingleFile(tarWriter, absFuzzerPath, relFuzzerPath, "fuzz_bitmap", false) - packSingleFile(tarWriter, absFuzzerPath, relFuzzerPath, "fuzzer_stats", false) - packSingleFile(tarWriter, absFuzzerPath, relFuzzerPath, "is_main_fuzzer", true) + packSingleFile(tarWriter, absFuzzerPath, relFuzzerPath, "fuzz_bitmap") + packSingleFile(tarWriter, absFuzzerPath, relFuzzerPath, "fuzzer_stats") packQueueFiles(tarWriter, absFuzzerPath, relFuzzerPath, &pkgCont) } @@ -70,15 +68,12 @@ func PackFuzzers(fuzzers []string, fuzzerDirectory string) ([]byte, error) { // fuzzerDirectory is the base directory, e.g. /project/fuzzers/ // fuzzer is the name of the fuzzer itself, e.g. main-fuzzer-01 // filename is the name of the file you want to pack, e.g. fuzzer_stats -// ignoreNotFound is just used for files which may not be present in all fuzzer directories, like is_main_fuzzer -func packSingleFile(tarWriter *tar.Writer, absPath string, relPath string, fileName string, ignoreNotFound bool) { +func packSingleFile(tarWriter *tar.Writer, absPath string, relPath string, fileName string) { // Read file readPath := fmt.Sprintf("%s%c%s%c%s", absPath, os.PathSeparator, relPath, os.PathSeparator, fileName) contents, readErr := ioutil.ReadFile(readPath) if readErr != nil { - if !ignoreNotFound { - log.Printf("Failed to read file %s: %s", readPath, readErr) - } + log.Printf("Failed to read file %s: %s", readPath, readErr) return } @@ -127,7 +122,7 @@ func packQueueFiles(tarWriter *tar.Writer, absPath string, relPath string, pkgCo } // Pack into the archive - packSingleFile(tarWriter, absPath, relPath, fmt.Sprintf("queue%c%s", os.PathSeparator, f.Name()), false) + packSingleFile(tarWriter, absPath, relPath, fmt.Sprintf("queue%c%s", os.PathSeparator, f.Name())) if noDuplicates { // Append added file name to the list of things included in the package diff --git a/watchdog/watchdog.go b/watchdog/watchdog.go index 376e2fd..e18ce2e 100644 --- a/watchdog/watchdog.go +++ b/watchdog/watchdog.go @@ -27,7 +27,7 @@ func WatchFuzzers(outputDirectory string) { // Loop forever for { // Pack important parts of the fuzzers into an archive - packedFuzzers, packerErr := logistic.PackFuzzers(getTargetFuzzers(outputDirectory), outputDirectory) + packedFuzzers, packerErr := logistic.PackFuzzers(getTargetFuzzer(outputDirectory), outputDirectory) if packerErr != nil { log.Printf("Failed to pack fuzzer: %s", packerErr) continue @@ -43,77 +43,45 @@ func WatchFuzzers(outputDirectory string) { // Searches in the specified output directory for fuzzers which we want to pack. // Identifying the main fuzzer is done by searching for the file "is_main_node" -// Identifying local secondary fuzzers is done by searching for a file which is not shared between nodes as it is not required for clusterized fuzzing: 'cmdline'. -// Please note that this is not failsafe, e.g. if you already synced your fuzzers over a different tool or by hand before. -// -// - If we are running in main mode (--main), we want to share the main fuzzers' queue with the secondary nodes -// - If we are not running in main mode, we want to share all of our fuzzers' queues with the main node +// This relies on the "election process" done by secondary fuzzers if they don't find a local main node. +// If that is detected, a secondary fuzzer becomes the main node in terms of syncing. That means we need to focus on +// the main node even if there is no real main node running locally. +// However it is important to avoid transmitting the is_main_node file - else, the secondaries will think that there is +// a main node running locally. Skipping the is_main_node file means the other fuzzers (and especially the elected main +// fuzzer) detect the transmitted fuzzer as a normal (and dead) secondary. ... blabla // // (see AFLplusplus/src/afl-fuzz.run.c:542) -func getTargetFuzzers(outputDirectory string) []string { - if isMainNode { - // find main fuzzer directory - its the only one required by the secondaries +func getTargetFuzzer(outputDirectory string) []string { + // find main fuzzer directory - its the only one required by the secondaries - // List files (read: fuzzers) in output directory - filesInDir, readErr := ioutil.ReadDir(outputDirectory) - if readErr != nil { - log.Printf("Failed to list directory content of %s: %s", outputDirectory, readErr) - return nil - } - - for _, f := range filesInDir { - // Get stat for maybe-existent file - mainnodePath := fmt.Sprintf("%s%c%s%cis_main_node", outputDirectory, os.PathSeparator, f.Name(), os.PathSeparator) - _, statErr := os.Stat(mainnodePath) - if os.IsNotExist(statErr) { - // File does not exist. Not the ~~chosen one~~ main fuzzer. Next. - continue - } else if statErr != nil { - // An error occurred. File is maybe in a Schrödinger state. - log.Printf("Unable to stat file %s: %s", mainnodePath, statErr) - continue - } - - // is_main_node file exists, so we found the correct fuzzer directory - return it - fullPath := fmt.Sprintf("%s%c%s", outputDirectory, os.PathSeparator, f.Name()) - return []string{ - fullPath, - } - } - - // Failed to find the main node - probably we are in --main mode by accident - log.Printf("Unable to find main node in %s - sure afl-transmit should run in --main mode?", outputDirectory) + // List files (read: fuzzers) in output directory + filesInDir, readErr := ioutil.ReadDir(outputDirectory) + if readErr != nil { + log.Printf("Failed to list directory content of %s: %s", outputDirectory, readErr) return nil - } else { - // get all fuzzer directories which are locally available - var localFuzzers []string - - // List files (read: fuzzers) in output directory - filesInDir, readErr := ioutil.ReadDir(outputDirectory) - if readErr != nil { - log.Printf("Failed to list directory content of %s: %s", outputDirectory, readErr) - return nil - } - - // Walk over each fuzzer and search for 'cmdline' file - for _, f := range filesInDir { - // Get stat for maybe-existent file - cmdlinePath := fmt.Sprintf("%s%c%s%ccmdline", outputDirectory, os.PathSeparator, f.Name(), os.PathSeparator) - _, statErr := os.Stat(cmdlinePath) - if os.IsNotExist(statErr) { - // File does not exist. That's fine. Next. - continue - } else if statErr != nil { - // An error occurred. File is maybe in a Schrödinger state. - log.Printf("Unable to stat file %s: %s", cmdlinePath, statErr) - continue - } - - // File exists, let's watch it - fullPath := fmt.Sprintf("%s%c%s", outputDirectory, os.PathSeparator, f.Name()) - localFuzzers = append(localFuzzers, fullPath) - } - - return localFuzzers } + + for _, f := range filesInDir { + // Get stat for maybe-existent file + mainnodePath := fmt.Sprintf("%s%c%s%cis_main_node", outputDirectory, os.PathSeparator, f.Name(), os.PathSeparator) + _, statErr := os.Stat(mainnodePath) + if os.IsNotExist(statErr) { + // File does not exist. Not the ~~chosen one~~ main fuzzer. Next. + continue + } else if statErr != nil { + // An error occurred. File is maybe in a Schrödinger state. + log.Printf("Unable to stat file %s: %s", mainnodePath, statErr) + continue + } + + // is_main_node file exists, so we found the correct fuzzer directory - return it + fullPath := fmt.Sprintf("%s%c%s", outputDirectory, os.PathSeparator, f.Name()) + return []string{ + fullPath, + } + } + + // Failed to find the main node - probably we are in --main mode by accident + log.Printf("Unable to find main node in %s - sure afl-transmit should run in --main mode?", outputDirectory) + return nil }