oss-fuzz: Ctrl-C not working in libFuzzer's fork mode.

@kcc @morehouse hardik from the fuzzing discord told me about this problem and I have been able to repro. If you compile this program with -fsanitize=fuzzer,address (using OSS-Fuzz’s clang) and run it with ./a.out -fork=1 -ignore_crashes=1 Ctrl-C does nothing and libFuzzer will run forever.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I am hoping to make some form of announcement any day now. The team has switched to working on https://github.com/google/centipede. libFuzzer will remain maintained at some level though, for some time.

This is the simple patch:

commit fb10537766c6216c43efb29b931787a89ff5bfd3
Author: Marcel Boehme <marcel.boehme@acm.org>
Date:   Sun Nov 8 23:21:14 2020 +0000

    [LibFuzzer] Bug Fix for https://github.com/google/oss-fuzz/issues/4547

diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
index 981f9a8..2c25e46 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
@@ -1,41 +1,44 @@
 //===- FuzzerUtilLinux.cpp - Misc utils for Linux. ------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
 // Misc utils for Linux.
 //===----------------------------------------------------------------------===//
 #include "FuzzerPlatform.h"
 #if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||                \
     LIBFUZZER_EMSCRIPTEN
 #include "FuzzerCommand.h"
 
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
 
 namespace fuzzer {
 
 int ExecuteCommand(const Command &Cmd) {
   std::string CmdLine = Cmd.toString();
   int exit_code = system(CmdLine.c_str());
-  if (WIFEXITED(exit_code))
-    return WEXITSTATUS(exit_code);
+  if (WIFEXITED(exit_code)) {
+     return WEXITSTATUS(exit_code);
+  } else if (WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGINT) {
+    return 72; // Options->InterruptExitCode
+  }
   return exit_code;
 }
 
 void DiscardOutput(int Fd) {
   FILE* Temp = fopen("/dev/null", "w");
   if (!Temp)
     return;
   dup2(fileno(Temp), Fd);
   fclose(Temp);
 }
 
 } // namespace fuzzer
 
 #endif

To properly patch this, though, you might need to route the FuzzingOptions object to ExecuteCommand, which requires extending the FuzzerUtil header and all instances of the ExecuteCommand API. Then, you can retrieve the return value as Options->InterruptExitCode.

This fixes it for me:

diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
index 981f9a8..18de684 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
@@ -23,6 +23,7 @@ namespace fuzzer {
 int ExecuteCommand(const Command &Cmd) {
   std::string CmdLine = Cmd.toString();
   int exit_code = system(CmdLine.c_str());
+  if (exit_code == 2) exit_code = 72;
   if (WIFEXITED(exit_code))
     return WEXITSTATUS(exit_code);
   return exit_code;

Not sure why, but this call to libfuzzer returns with exit code 2 when interrupted. Copying, running, and interrupting the exact same command in the bash terminal gives the proper exit code 72 (Options.InterruptExitCode). Even forced the interrupt handler of the child to return immediately with 72. It still ends up as 2.