Whamcloud - gitweb
Build the fuzzers from oss-fuzz
authorTheodore Ts'o <tytso@mit.edu>
Sat, 6 Aug 2022 22:35:30 +0000 (18:35 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 9 Aug 2022 23:45:07 +0000 (19:45 -0400)
The fuzzers from oss-fuzz in projects/e2fsprogs/fuzz (as of commit
78ecd3f07fca with some slight modifications for better error
reporting) have been placed in the tests/fuzz directory and the
configure script now supports a new option --enable-fuzzing which will
build these fuzzers using clang's -fsanitize=fuzzer command line
option.

In general, some sanitizer such as --enable-addrsan or --enable-ubsan
(to enable ASAN or UBSAN, respectively) should be enabled alongside
--enable-fuzzing.

A typical configure command to build the fuzzers might be:

  configure CC=clang CXX=clang++ CFLAGS=-g --enable-fuzzing --enable-addrsan

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
13 files changed:
MCONFIG.in
Makefile.in
configure
configure.ac
depfix.sed
lib/support/Makefile.in
lib/support/print_fs_flags.c [new file with mode: 0644]
lib/support/print_fs_flags.h [new file with mode: 0644]
tests/fuzz/.gitignore [new file with mode: 0644]
tests/fuzz/Makefile.in [new file with mode: 0644]
tests/fuzz/ext2fs_check_directory_fuzzer.cc [new file with mode: 0644]
tests/fuzz/ext2fs_image_read_write_fuzzer.cc [new file with mode: 0644]
tests/fuzz/ext2fs_read_bitmap_fuzzer.cc [new file with mode: 0644]

index 3fede36..82c75a2 100644 (file)
@@ -87,6 +87,7 @@ SANITIZER_CFLAGS = @lto_cflags@ @ubsan_cflags@ @addrsan_cflags@ @threadsan_cflag
 SANITIZER_LDFLAGS = @lto_ldflags@ @ubsan_ldflags@ @addrsan_ldflags@ @threadsan_ldflags@
 
 CC = @PTHREAD_CC@
+CXX = @CXX@
 BUILD_CC = @BUILD_CC@
 PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
 PTHREAD_LIBS = @PTHREAD_LIBS@
@@ -99,7 +100,7 @@ ALL_CFLAGS_SHLIB = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS_SHLIB) $(PTHREAD_CFL
 ALL_CFLAGS_STLIB = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS_STLIB) $(PTHREAD_CFLAGS) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
 LDFLAGS = $(SANITIZER_LDFLAGS) $(PTHREAD_CFLAGS) @LDFLAGS@
 LDFLAGS_SHLIB = $(SANITIZER_LDFLAGS) $(PTHREAD_CFLAGS) @LDFLAGS_SHLIB@
-ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@
+ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@ $(LOCAL_LDFLAGS)
 LDFLAGS_STATIC = $(SANITIZER_LDFLAGS) $(PTHREAD_CFLAGS) @LDFLAGS_STATIC@
 BUILD_CFLAGS = $(SANITIZER_CFLAGS) @BUILD_CFLAGS@
 BUILD_LDFLAGS = $(SANITIZER_LDFLAGS) @BUILD_LDFLAGS@
index d412dfb..79b7116 100644 (file)
@@ -22,8 +22,8 @@ MKDIR_P = @MKDIR_P@
 LIB_SUBDIRS=lib/et lib/ss $(E2P_LIB_SUBDIR) $(UUID_LIB_SUBDIR) \
        $(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) $(EXT2FS_LIB_SUBDIR)
 
-PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po \
-       $(E2SCRUB_DIR)
+PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs \
+       tests/fuzz po $(E2SCRUB_DIR)
 
 SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
 
index bfcb1ad..4935423 100755 (executable)
--- a/configure
+++ b/configure
@@ -678,6 +678,13 @@ E2SCRUB_CMT
 UNIX_CMT
 CYGWIN_CMT
 LINUX_CMT
+FUZZING_CMT
+fuzzer_ldflags
+fuzzer_cflags
+have_fuzzer
+ac_ct_CXX
+CXXFLAGS
+CXX
 threadsan_ldflags
 threadsan_cflags
 have_threadsan
@@ -923,6 +930,7 @@ enable_lto
 enable_ubsan
 enable_addrsan
 enable_threadsan
+enable_fuzzing
 with_multiarch
 with_udev_rules_dir
 with_crond_dir
@@ -940,6 +948,9 @@ CPP
 PKG_CONFIG
 PKG_CONFIG_PATH
 PKG_CONFIG_LIBDIR
+CXX
+CXXFLAGS
+CCC
 udev_CFLAGS
 udev_LIBS
 systemd_CFLAGS
@@ -1609,6 +1620,7 @@ Optional Features:
   --enable-ubsan          enable undefined behavior sanitizer
   --enable-addrsan        enable address sanitizer
   --enable-threadsan      enable thread sanitizer
+  --enable-fuzzing        enable fuzzing sanitizer
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1647,6 +1659,8 @@ Some influential environment variables:
               directories to add to pkg-config's search path
   PKG_CONFIG_LIBDIR
               path overriding pkg-config's built-in search path
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
   udev_CFLAGS C compiler flags for udev, overriding pkg-config
   udev_LIBS   linker flags for udev, overriding pkg-config
   systemd_CFLAGS
@@ -2354,6 +2368,45 @@ rm -f conftest.val
   as_fn_set_status $ac_retval
 
 } # ac_fn_c_compute_int
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest.beam
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+printf "%s\n" "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_cxx_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext
+then :
+  ac_retval=0
+else $as_nop
+  printf "%s\n" "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
 ac_configure_args_raw=
 for ac_arg
 do
@@ -2970,6 +3023,222 @@ as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H"
 as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H"
 gt_needs="$gt_needs "
 as_fn_append ac_func_c_list " vprintf HAVE_VPRINTF"
+# Test code for whether the C++ compiler supports C++98 (global declarations)
+ac_cxx_conftest_cxx98_globals='
+// Does the compiler advertise C++98 conformance?
+#if !defined __cplusplus || __cplusplus < 199711L
+# error "Compiler does not advertise C++98 conformance"
+#endif
+
+// These inclusions are to reject old compilers that
+// lack the unsuffixed header files.
+#include <cstdlib>
+#include <exception>
+
+// <cassert> and <cstring> are *not* freestanding headers in C++98.
+extern void assert (int);
+namespace std {
+  extern int strcmp (const char *, const char *);
+}
+
+// Namespaces, exceptions, and templates were all added after "C++ 2.0".
+using std::exception;
+using std::strcmp;
+
+namespace {
+
+void test_exception_syntax()
+{
+  try {
+    throw "test";
+  } catch (const char *s) {
+    // Extra parentheses suppress a warning when building autoconf itself,
+    // due to lint rules shared with more typical C programs.
+    assert (!(strcmp) (s, "test"));
+  }
+}
+
+template <typename T> struct test_template
+{
+  T const val;
+  explicit test_template(T t) : val(t) {}
+  template <typename U> T add(U u) { return static_cast<T>(u) + val; }
+};
+
+} // anonymous namespace
+'
+
+# Test code for whether the C++ compiler supports C++98 (body of main)
+ac_cxx_conftest_cxx98_main='
+  assert (argc);
+  assert (! argv[0]);
+{
+  test_exception_syntax ();
+  test_template<double> tt (2.0);
+  assert (tt.add (4) == 6.0);
+  assert (true && !false);
+}
+'
+
+# Test code for whether the C++ compiler supports C++11 (global declarations)
+ac_cxx_conftest_cxx11_globals='
+// Does the compiler advertise C++ 2011 conformance?
+#if !defined __cplusplus || __cplusplus < 201103L
+# error "Compiler does not advertise C++11 conformance"
+#endif
+
+namespace cxx11test
+{
+  constexpr int get_val() { return 20; }
+
+  struct testinit
+  {
+    int i;
+    double d;
+  };
+
+  class delegate
+  {
+  public:
+    delegate(int n) : n(n) {}
+    delegate(): delegate(2354) {}
+
+    virtual int getval() { return this->n; };
+  protected:
+    int n;
+  };
+
+  class overridden : public delegate
+  {
+  public:
+    overridden(int n): delegate(n) {}
+    virtual int getval() override final { return this->n * 2; }
+  };
+
+  class nocopy
+  {
+  public:
+    nocopy(int i): i(i) {}
+    nocopy() = default;
+    nocopy(const nocopy&) = delete;
+    nocopy & operator=(const nocopy&) = delete;
+  private:
+    int i;
+  };
+
+  // for testing lambda expressions
+  template <typename Ret, typename Fn> Ret eval(Fn f, Ret v)
+  {
+    return f(v);
+  }
+
+  // for testing variadic templates and trailing return types
+  template <typename V> auto sum(V first) -> V
+  {
+    return first;
+  }
+  template <typename V, typename... Args> auto sum(V first, Args... rest) -> V
+  {
+    return first + sum(rest...);
+  }
+}
+'
+
+# Test code for whether the C++ compiler supports C++11 (body of main)
+ac_cxx_conftest_cxx11_main='
+{
+  // Test auto and decltype
+  auto a1 = 6538;
+  auto a2 = 48573953.4;
+  auto a3 = "String literal";
+
+  int total = 0;
+  for (auto i = a3; *i; ++i) { total += *i; }
+
+  decltype(a2) a4 = 34895.034;
+}
+{
+  // Test constexpr
+  short sa[cxx11test::get_val()] = { 0 };
+}
+{
+  // Test initializer lists
+  cxx11test::testinit il = { 4323, 435234.23544 };
+}
+{
+  // Test range-based for
+  int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3,
+                 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};
+  for (auto &x : array) { x += 23; }
+}
+{
+  // Test lambda expressions
+  using cxx11test::eval;
+  assert (eval ([](int x) { return x*2; }, 21) == 42);
+  double d = 2.0;
+  assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0);
+  assert (d == 5.0);
+  assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0);
+  assert (d == 5.0);
+}
+{
+  // Test use of variadic templates
+  using cxx11test::sum;
+  auto a = sum(1);
+  auto b = sum(1, 2);
+  auto c = sum(1.0, 2.0, 3.0);
+}
+{
+  // Test constructor delegation
+  cxx11test::delegate d1;
+  cxx11test::delegate d2();
+  cxx11test::delegate d3(45);
+}
+{
+  // Test override and final
+  cxx11test::overridden o1(55464);
+}
+{
+  // Test nullptr
+  char *c = nullptr;
+}
+{
+  // Test template brackets
+  test_template<::test_template<int>> v(test_template<int>(12));
+}
+{
+  // Unicode literals
+  char const *utf8 = u8"UTF-8 string \u2500";
+  char16_t const *utf16 = u"UTF-8 string \u2500";
+  char32_t const *utf32 = U"UTF-32 string \u2500";
+}
+'
+
+# Test code for whether the C compiler supports C++11 (complete).
+ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals}
+${ac_cxx_conftest_cxx11_globals}
+
+int
+main (int argc, char **argv)
+{
+  int ok = 0;
+  ${ac_cxx_conftest_cxx98_main}
+  ${ac_cxx_conftest_cxx11_main}
+  return ok;
+}
+"
+
+# Test code for whether the C compiler supports C++98 (complete).
+ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals}
+int
+main (int argc, char **argv)
+{
+  int ok = 0;
+  ${ac_cxx_conftest_cxx98_main}
+  return ok;
+}
+"
+
 
 # Auxiliary files required by this configure script.
 ac_aux_files="config.rpath install-sh config.guess config.sub"
@@ -14091,6 +14360,449 @@ if test "$have_threadsan" = "yes" && test "$have_addrsan" = "yes"; then
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ADDRSAN and THREADSAN are not known to work together." >&5
 printf "%s\n" "$as_me: WARNING: ADDRSAN and THREADSAN are not known to work together." >&2;}
 fi
+FUZZING_CMT="#"
+# Check whether --enable-fuzzing was given.
+if test ${enable_fuzzing+y}
+then :
+  enableval=$enable_fuzzing;
+else $as_nop
+  enable_fuzzing=no
+fi
+
+if test "$enable_fuzzing" = "yes" || test "$enable_fuzzing" = "probe"; then
+
+
+
+
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CXX+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+printf "%s\n" "$CXX" >&6; }
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CXX+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+printf "%s\n" "$ac_ct_CXX" >&6; }
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+printf "%s\n" "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5
+printf %s "checking whether the compiler supports GNU C++... " >&6; }
+if test ${ac_cv_cxx_compiler_gnu+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main (void)
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+  ac_compiler_gnu=yes
+else $as_nop
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+y}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+printf %s "checking whether $CXX accepts -g... " >&6; }
+if test ${ac_cv_prog_cxx_g+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+  ac_cv_prog_cxx_g=yes
+else $as_nop
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+
+else $as_nop
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+        CXXFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+printf "%s\n" "$ac_cv_prog_cxx_g" >&6; }
+if test $ac_test_CXXFLAGS; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_prog_cxx_stdcxx=no
+if test x$ac_prog_cxx_stdcxx = xno
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5
+printf %s "checking for $CXX option to enable C++11 features... " >&6; }
+if test ${ac_cv_prog_cxx_11+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  ac_cv_prog_cxx_11=no
+ac_save_CXX=$CXX
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_cxx_conftest_cxx11_program
+_ACEOF
+for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA
+do
+  CXX="$ac_save_CXX $ac_arg"
+  if ac_fn_cxx_try_compile "$LINENO"
+then :
+  ac_cv_prog_cxx_cxx11=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+  test "x$ac_cv_prog_cxx_cxx11" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+fi
+
+if test "x$ac_cv_prog_cxx_cxx11" = xno
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+  if test "x$ac_cv_prog_cxx_cxx11" = x
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5
+printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; }
+     CXX="$CXX $ac_cv_prog_cxx_cxx11"
+fi
+  ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11
+  ac_prog_cxx_stdcxx=cxx11
+fi
+fi
+if test x$ac_prog_cxx_stdcxx = xno
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5
+printf %s "checking for $CXX option to enable C++98 features... " >&6; }
+if test ${ac_cv_prog_cxx_98+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  ac_cv_prog_cxx_98=no
+ac_save_CXX=$CXX
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_cxx_conftest_cxx98_program
+_ACEOF
+for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA
+do
+  CXX="$ac_save_CXX $ac_arg"
+  if ac_fn_cxx_try_compile "$LINENO"
+then :
+  ac_cv_prog_cxx_cxx98=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+  test "x$ac_cv_prog_cxx_cxx98" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+fi
+
+if test "x$ac_cv_prog_cxx_cxx98" = xno
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+  if test "x$ac_cv_prog_cxx_cxx98" = x
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5
+printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; }
+     CXX="$CXX $ac_cv_prog_cxx_cxx98"
+fi
+  ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98
+  ac_prog_cxx_stdcxx=cxx98
+fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if C compiler supports fuzzing sanitizer" >&5
+printf %s "checking if C compiler supports fuzzing sanitizer... " >&6; }
+       ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+       OLD_CXXFLAGS="$CXXFLAGS"
+       OLD_LDFLAGS="$LDFLAGS"
+       FUZZER_FLAGS="-fsanitize=fuzzer"
+       CXXFLAGS="$CXXFLAGS $FUZZER_FLAGS"
+       LDFLAGS="$LDFLAGS $FUZZER_FLAGS"
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+               #include <stddef.h>
+               #include <stdint.h>
+
+int
+main (void)
+{
+ return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+               fuzzer_cflags=$FUZZER_FLAGS
+               fuzzer_ldflags=$FUZZER_FLAGS
+               FUZZING_CMT=
+               have_fuzzer=yes
+else $as_nop
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+               as_fn_error $? "fuzzing requested but not available" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+       CXXFLAGS="${OLD_CXXFLAGS}"
+       LDFLAGS="${OLD_LDFLAGS}"
+       ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+fi
+if test "$enable_fuzzer" = "yes" && test "$have_fuzzer" != "yes"; then
+       as_fn_error $? "Fuzzing not supported by compiler." "$LINENO" 5
+fi
+
 LINUX_CMT="#"
 CYGWIN_CMT="#"
 UNIX_CMT=
@@ -14584,7 +15296,8 @@ for i in MCONFIG Makefile \
        lib/ss/ss.pc lib/et/com_err.pc lib/e2p/e2p.pc lib/ext2fs/ext2fs.pc \
        misc/Makefile ext2ed/Makefile e2fsck/Makefile \
        debugfs/Makefile tests/Makefile tests/progs/Makefile \
-       resize/Makefile doc/Makefile po/Makefile.in scrub/Makefile; do
+       tests/fuzz/Makefile resize/Makefile doc/Makefile \
+       po/Makefile.in scrub/Makefile; do
        if test -d `dirname ${srcdir}/$i` ; then
                outlist="$outlist $i"
        fi
index cb528da..78f71fd 100644 (file)
@@ -1495,6 +1495,45 @@ if test "$have_threadsan" = "yes" && test "$have_addrsan" = "yes"; then
        AC_MSG_WARN([ADDRSAN and THREADSAN are not known to work together.])
 fi
 dnl
+dnl Enable the fuzzer sanitizer for all packages
+dnl
+FUZZING_CMT="#"
+AC_ARG_ENABLE([fuzzing],
+AS_HELP_STRING([--enable-fuzzing],[enable fuzzing sanitizer]),,
+enable_fuzzing=no)
+if test "$enable_fuzzing" = "yes" || test "$enable_fuzzing" = "probe"; then
+       AC_PROG_CXX
+       AC_MSG_CHECKING([if C compiler supports fuzzing sanitizer])
+       AC_LANG_PUSH([C++])
+       OLD_CXXFLAGS="$CXXFLAGS"
+       OLD_LDFLAGS="$LDFLAGS"
+       FUZZER_FLAGS="-fsanitize=fuzzer"
+       CXXFLAGS="$CXXFLAGS $FUZZER_FLAGS"
+       LDFLAGS="$LDFLAGS $FUZZER_FLAGS"
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+               #include <stddef.h>
+               #include <stdint.h>
+               ]],
+               [ return 0; ])],
+               [AC_MSG_RESULT([yes])]
+               [fuzzer_cflags=$FUZZER_FLAGS]
+               [fuzzer_ldflags=$FUZZER_FLAGS]
+               [FUZZING_CMT=]
+               [have_fuzzer=yes],
+               [AC_MSG_RESULT([no])]
+               [AC_MSG_ERROR([fuzzing requested but not available])])
+       CXXFLAGS="${OLD_CXXFLAGS}"
+       LDFLAGS="${OLD_LDFLAGS}"
+       AC_LANG_POP([C++])
+       AC_SUBST(have_fuzzer)
+       AC_SUBST(fuzzer_cflags)
+       AC_SUBST(fuzzer_ldflags)
+fi
+if test "$enable_fuzzer" = "yes" && test "$have_fuzzer" != "yes"; then
+       AC_MSG_ERROR([Fuzzing not supported by compiler.])
+fi
+AC_SUBST(FUZZING_CMT)
+dnl
 dnl OS-specific uncomment control
 dnl
 LINUX_CMT="#"
@@ -1819,7 +1858,8 @@ for i in MCONFIG Makefile \
        lib/ss/ss.pc lib/et/com_err.pc lib/e2p/e2p.pc lib/ext2fs/ext2fs.pc \
        misc/Makefile ext2ed/Makefile e2fsck/Makefile \
        debugfs/Makefile tests/Makefile tests/progs/Makefile \
-       resize/Makefile doc/Makefile po/Makefile.in scrub/Makefile; do
+       tests/fuzz/Makefile resize/Makefile doc/Makefile \
+       po/Makefile.in scrub/Makefile; do
        if test -d `dirname ${srcdir}/$i` ; then
                outlist="$outlist $i"
        fi
index 582d79f..680fb22 100644 (file)
@@ -24,7 +24,7 @@ s/  */ /g
 
 s;/usr/include/[^ ]* *;;g
 s;/usr/lib/[^ ]* *;;g
-s;/mit/cygnus[^ ]* *;;g
+s;/bin/[^ ]* *;;g
 s;\.\./[^ ]*lib/blkid/blkid[^ ]* *;;g
 s;\.\./[^ ]*lib/uuid/uuid.h[^ ]* *;;g
 
index f3c7981..e5600a8 100644 (file)
@@ -18,6 +18,7 @@ OBJS=         cstring.o \
                plausible.o \
                profile.o \
                parse_qtype.o \
+               print_fs_flags.o \
                profile_helpers.o \
                prof_err.o \
                quotaio.o \
@@ -30,6 +31,7 @@ SRCS=         $(srcdir)/argv_parse.c \
                $(srcdir)/mkquota.c \
                $(srcdir)/parse_qtype.c \
                $(srcdir)/plausible.c \
+               $(srcdir)/print_fs_flags.c \
                $(srcdir)/profile.c \
                $(srcdir)/profile_helpers.c \
                prof_err.c \
diff --git a/lib/support/print_fs_flags.c b/lib/support/print_fs_flags.c
new file mode 100644 (file)
index 0000000..e54acc0
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * print_flags.c       - Print ext2_filsys flags
+ *
+ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
+ *                           Laboratoire MASI, Institut Blaise Pascal
+ *                           Universite Pierre et Marie Curie (Paris VI)
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "ext2fs/ext2fs.h"
+
+struct flags_name {
+       unsigned long   flag;
+       const char      *name;
+};
+
+static struct flags_name flags_array[] = {
+       EXT2_FLAG_RW, "EXT2_FLAG_RW",
+       EXT2_FLAG_CHANGED, "EXT2_FLAG_CHANGED",
+       EXT2_FLAG_DIRTY, "EXT2_FLAG_DIRTY",
+       EXT2_FLAG_VALID, "EXT2_FLAG_VALID",
+       EXT2_FLAG_IB_DIRTY, "EXT2_FLAG_IB_DIRTY",
+       EXT2_FLAG_BB_DIRTY, "EXT2_FLAG_BB_DIRTY",
+       EXT2_FLAG_SWAP_BYTES, "EXT2_FLAG_SWAP_BYTES",
+       EXT2_FLAG_SWAP_BYTES_READ, "EXT2_FLAG_SWAP_BYTES_READ",
+       EXT2_FLAG_SWAP_BYTES_WRITE, "EXT2_FLAG_SWAP_BYTES_WRITE",
+       EXT2_FLAG_MASTER_SB_ONLY, "EXT2_FLAG_MASTER_SB_ONLY",
+       EXT2_FLAG_FORCE, "EXT2_FLAG_FORCE",
+       EXT2_FLAG_SUPER_ONLY, "EXT2_FLAG_SUPER_ONLY",
+       EXT2_FLAG_JOURNAL_DEV_OK, "EXT2_FLAG_JOURNAL_DEV_OK",
+       EXT2_FLAG_IMAGE_FILE, "EXT2_FLAG_IMAGE_FILE",
+       EXT2_FLAG_EXCLUSIVE, "EXT2_FLAG_EXCLUSIVE",
+       EXT2_FLAG_SOFTSUPP_FEATURES, "EXT2_FLAG_SOFTSUPP_FEATURES",
+       EXT2_FLAG_NOFREE_ON_ERROR, "EXT2_FLAG_NOFREE_ON_ERROR",
+       EXT2_FLAG_64BITS, "EXT2_FLAG_64BITS",
+       EXT2_FLAG_PRINT_PROGRESS, "EXT2_FLAG_PRINT_PROGRESS",
+       EXT2_FLAG_DIRECT_IO, "EXT2_FLAG_DIRECT_IO",
+       EXT2_FLAG_SKIP_MMP, "EXT2_FLAG_SKIP_MMP",
+       EXT2_FLAG_IGNORE_CSUM_ERRORS, "EXT2_FLAG_IGNORE_CSUM_ERRORS",
+       EXT2_FLAG_SHARE_DUP, "EXT2_FLAG_SHARE_DUP",
+       EXT2_FLAG_IGNORE_SB_ERRORS, "EXT2_FLAG_IGNORE_SB_ERRORS",
+       EXT2_FLAG_BBITMAP_TAIL_PROBLEM, "EXT2_FLAG_BBITMAP_TAIL_PROBLEM",
+       EXT2_FLAG_IBITMAP_TAIL_PROBLEM, "EXT2_FLAG_IBITMAP_TAIL_PROBLEM",
+       EXT2_FLAG_THREADS, "EXT2_FLAG_THREADS",
+       0
+};
+
+void print_fs_flags(FILE * f, unsigned long flags)
+{
+       struct flags_name *fp;
+       int     first = 1, pos = 16;
+
+       for (fp = flags_array; fp->flag != 0; fp++) {
+               if ((flags & fp->flag) == 0)
+                       continue;
+               pos += strlen(fp->name) + 1;
+               if (pos > 72) {
+                       fputs("\n\t", f);
+                       pos = 9 + strlen(fp->name);
+               }
+               if (first)
+                       first = 0;
+               else
+                       fputc(' ', f);
+               fputs(fp->name, f);
+       }
+       fputc('\n', f);
+}
diff --git a/lib/support/print_fs_flags.h b/lib/support/print_fs_flags.h
new file mode 100644 (file)
index 0000000..bdd58a0
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * print_flags.h -- header file for printing the fs flags
+ */
+
+void print_fs_flags(FILE * f, unsigned long flags);
diff --git a/tests/fuzz/.gitignore b/tests/fuzz/.gitignore
new file mode 100644 (file)
index 0000000..381b20a
--- /dev/null
@@ -0,0 +1,3 @@
+ext2fs_check_directory_fuzzer
+ext2fs_image_read_write_fuzzer
+ext2fs_read_bitmap_fuzzer
diff --git a/tests/fuzz/Makefile.in b/tests/fuzz/Makefile.in
new file mode 100644 (file)
index 0000000..a6d8063
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# Makefile for the tests/fuzz directory
+#
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = ../..
+my_dir = tests/fuzz
+
+@MCONFIG@
+
+PROGS= ext2fs_check_directory_fuzzer \
+               ext2fs_image_read_write_fuzzer \
+               ext2fs_read_bitmap_fuzzer
+
+SRCS=  $(srcdir)/ext2fs_check_directory_fuzzer.cc \
+               $(srcdir)/ext2fs_image_read_write_fuzzer.cc \
+               $(srcdir)/ext2fs_read_bitmap_fuzzer.cc
+
+LOCAL_CFLAGS= @fuzzer_cflags@
+LOCAL_LDFLAGS= @fuzzer_ldflags@
+
+LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT)
+DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT)
+
+STATIC_LIBS= $(LIBSUPPORT) $(STATIC_LIBE2P) $(STATIC_LIBEXT2FS) \
+       $(STATIC_LIBCOM_ERR)
+STATIC_DEPLIBS= $(DEPLIBSUPPORT) $(STATIC_LIBE2P) $(STATIC_LIBEXT2FS) \
+       $(DEPSTATIC_LIBCOM_ERR)
+
+FUZZ_LDFLAGS= $(ALL_LDFLAGS)
+FUZZ_DEP= $(STATIC_DEPLIBS) $(srcdir)/Makefile.in
+
+.cc.o:
+       $(E) "  CXX $<"
+       $(Q) $(CXX) -c $(ALL_CFLAGS) $< -o $@
+
+@FUZZING_CMT@all::  $(PROGS)
+
+clean::
+       $(RM) -f $(PROGS) *.o
+
+ext2fs_check_directory_fuzzer: ext2fs_check_directory_fuzzer.o $(FUZZ_DEP)
+       $(E) "  LD $@"
+       $(Q) $(CXX) $(FUZZ_LDFLAGS) -o $@ $< $(STATIC_LIBS) $(SYSLIBS)
+
+ext2fs_image_read_write_fuzzer: ext2fs_image_read_write_fuzzer.o  $(FUZZ_DEP)
+       $(E) "  LD $@"
+       $(Q) $(CXX) $(FUZZ_LDFLAGS) -o $@ $< $(STATIC_LIBS) $(SYSLIBS)
+
+ext2fs_read_bitmap_fuzzer: ext2fs_read_bitmap_fuzzer.o $(FUZZ_DEP)
+       $(E) "  LD $@"
+       $(Q) $(CXX) $(FUZZ_LDFLAGS) -o $@ $< $(STATIC_LIBS) $(SYSLIBS)
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+ext2fs_check_directory_fuzzer.o: $(srcdir)/ext2fs_check_directory_fuzzer.cc \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/hashmap.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h
+ext2fs_image_read_write_fuzzer.o: $(srcdir)/ext2fs_image_read_write_fuzzer.cc \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/hashmap.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(top_srcdir)/lib/support/print_fs_flags.h
+ext2fs_read_bitmap_fuzzer.o: $(srcdir)/ext2fs_read_bitmap_fuzzer.cc \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/hashmap.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(top_srcdir)/lib/support/print_fs_flags.h
diff --git a/tests/fuzz/ext2fs_check_directory_fuzzer.cc b/tests/fuzz/ext2fs_check_directory_fuzzer.cc
new file mode 100644 (file)
index 0000000..61cf42f
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "ext2fs/ext2fs.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  static const char* fname = "/tmp/ext2_test_file";
+
+  // Write our data to a temp file.
+  int fd = open(fname, O_RDWR|O_CREAT|O_TRUNC);
+  write(fd, data, size);
+  close(fd);
+
+  ext2_filsys fs;
+  errcode_t retval = ext2fs_open(
+      fname,
+      EXT2_FLAG_IGNORE_CSUM_ERRORS, 0, 0,
+      unix_io_manager,
+      &fs);
+
+  if (!retval) {
+    retval = ext2fs_check_directory(fs, EXT2_ROOT_INO);
+    ext2fs_close(fs);
+  }
+
+  return 0;
+}
diff --git a/tests/fuzz/ext2fs_image_read_write_fuzzer.cc b/tests/fuzz/ext2fs_image_read_write_fuzzer.cc
new file mode 100644 (file)
index 0000000..8aa0cb8
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// #define USE_FLAGS
+// #define DUMP_SUPER
+// #define SAVE_FS_IMAGE
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <linux/memfd.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "ext2fs/ext2fs.h"
+extern "C" {
+#include "e2p/e2p.h"
+#include "support/print_fs_flags.h"
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+
+  const char *progname = "ext2fs_image_read_write_fuzzer";
+  add_error_table(&et_ext2_error_table);
+
+  enum FuzzerType {
+    ext2fsImageBitmapRead,
+    ext2fsImageInodeRead,
+    ext2fsImageSuperRead,
+    ext2fsImageBitmapWrite,
+    ext2fsImageInodeWrite,
+    ext2fsImageSuperWrite,
+    kMaxValue = ext2fsImageSuperWrite
+  };
+
+  FuzzedDataProvider stream(data, size);
+  const FuzzerType f = stream.ConsumeEnum<FuzzerType>();
+  int flags = stream.ConsumeIntegral<int>();
+#ifndef USE_FLAGS
+  flags = 0;
+#endif
+
+  static const char* fname = "/tmp/ext2_test_file";
+
+  // Write our data to a temp file.
+#ifdef SAVE_FS_IMAGE
+  int fd = open(fname, O_CREAT|O_TRUNC|O_RDWR, 0644);
+#else
+  int fd = syscall(SYS_memfd_create, fname, 0);
+#endif
+  std::vector<char> buffer = stream.ConsumeRemainingBytes<char>();
+  write(fd, buffer.data(), buffer.size());
+
+  std::string fspath("/proc/self/fd/" + std::to_string(fd));
+
+  ext2_filsys fs;
+#ifdef USE_FLAGS
+  printf("Flags: 0x%08x ", flags);
+  print_fs_flags(stdout, flags);
+  flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
+#endif
+  errcode_t retval = ext2fs_open(
+      fspath.c_str(),
+      flags | EXT2_FLAG_IGNORE_CSUM_ERRORS, 0, 0,
+      unix_io_manager,
+      &fs);
+
+  if (retval) {
+    com_err(progname, retval, "while trying to open file system");
+  } else {
+#ifdef DUMP_SUPER
+    list_super2(fs->super, stdout);
+#endif
+    printf("FuzzerType: %d\n", (int) f);
+    switch (f) {
+      case ext2fsImageBitmapRead: {
+        retval = ext2fs_image_bitmap_read(fs, fd, 0);
+        if (retval)
+          com_err(progname, retval, "while trying to read image bitmap");
+        break;
+      }
+      case ext2fsImageInodeRead: {
+        retval = ext2fs_image_inode_read(fs, fd, 0);
+        if (retval)
+          com_err(progname, retval, "while trying to read image inode");
+        break;
+      }
+      case ext2fsImageSuperRead: {
+        retval = ext2fs_image_super_read(fs, fd, 0);
+        if (retval)
+          com_err(progname, retval, "while trying to read image superblock");
+        break;
+      }
+      case ext2fsImageBitmapWrite: {
+        retval = ext2fs_image_bitmap_write(fs, fd, 0);
+        if (retval)
+          com_err(progname, retval, "while trying to write image bitmap");
+        break;
+      }
+      case ext2fsImageInodeWrite: {
+        retval = ext2fs_image_inode_write(fs, fd, 0);
+        if (retval)
+          com_err(progname, retval, "while trying to write image inode");
+        break;
+      }
+      case ext2fsImageSuperWrite: {
+        retval = ext2fs_image_super_write(fs, fd, 0);
+        if (retval)
+          com_err(progname, retval, "while trying to write image superblock");
+        break;
+      }
+      default: {
+        assert(false);
+      }
+    }
+    ext2fs_close(fs);
+  }
+  close(fd);
+
+  return 0;
+}
diff --git a/tests/fuzz/ext2fs_read_bitmap_fuzzer.cc b/tests/fuzz/ext2fs_read_bitmap_fuzzer.cc
new file mode 100644 (file)
index 0000000..fa3d7e7
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// #define USE_FLAGS
+// #define DUMP_SUPER
+// #define SAVE_FS_IMAGE
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <linux/memfd.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "ext2fs/ext2fs.h"
+extern "C" {
+#include "e2p/e2p.h"
+#include "support/print_fs_flags.h"
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+
+  const char *progname = "ext2fs_read_bitmap_fuzzer";
+  add_error_table(&et_ext2_error_table);
+
+  enum FuzzerType {
+    ext2fsReadBlockBitmap,
+    ext2fsReadInodeBitmap,
+    kMaxValue = ext2fsReadInodeBitmap
+  };
+
+  FuzzedDataProvider stream(data, size);
+  const FuzzerType f = stream.ConsumeEnum<FuzzerType>();
+  int flags = stream.ConsumeIntegral<int>();
+#ifndef USE_FLAGS
+  flags = 0;
+#endif
+
+  static const char* fname = "/tmp/ext2_test_file";
+
+  // Write our data to a temp file.
+#ifdef SAVE_FS_IMAGE
+  int fd = open(fname, O_CREAT|O_TRUNC|O_RDWR, 0644);
+#else
+  int fd = syscall(SYS_memfd_create, fname, 0);
+#endif
+  std::vector<char> buffer = stream.ConsumeRemainingBytes<char>();
+  write(fd, buffer.data(), buffer.size());
+
+  std::string fspath("/proc/self/fd/" + std::to_string(fd));
+
+  ext2_filsys fs;
+#ifdef USE_FLAGS
+  printf("Flags: 0x%08x ", flags);
+  print_fs_flags(stdout, flags);
+  flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
+#endif
+  errcode_t retval = ext2fs_open(
+      fspath.c_str(),
+      flags | EXT2_FLAG_IGNORE_CSUM_ERRORS, 0, 0,
+      unix_io_manager,
+      &fs);
+
+  if (retval) {
+    com_err(progname, retval, "while trying to open file system");
+  } else {
+#ifdef DUMP_SUPER
+    list_super2(fs->super, stdout);
+#endif
+    switch (f) {
+      case ext2fsReadBlockBitmap: {
+        retval = ext2fs_read_block_bitmap(fs);
+        if (retval)
+          com_err(progname, retval, "while trying to read block bitmap");
+        break;
+      }
+      case ext2fsReadInodeBitmap: {
+        retval = ext2fs_read_inode_bitmap(fs);
+        if (retval)
+          com_err(progname, retval, "while trying to read inode bitmap");
+        break;
+      }
+      default: {
+        assert(false);
+      }
+    }
+    retval = ext2fs_close(fs);
+    if (retval)
+      com_err(progname, retval, "while trying to close file system");
+  }
+  close(fd);
+
+  return 0;
+}