about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-common.c28
-rw-r--r--src/afl-fuzz-cmplog.c14
-rw-r--r--src/afl-fuzz-globals.c2
-rw-r--r--src/afl-fuzz-init.c2
-rw-r--r--src/afl-fuzz-redqueen.c87
-rw-r--r--src/afl-fuzz-stats.c107
-rw-r--r--src/afl-fuzz.c4
-rw-r--r--src/afl-showmap.c114
-rw-r--r--src/third_party/libradamsa/libradamsa.c6
9 files changed, 257 insertions, 107 deletions
diff --git a/src/afl-common.c b/src/afl-common.c
index 6cb97cdf..958b9b7d 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -72,23 +72,27 @@ void detect_file_args(char** argv, u8* prog_in) {
 
       if (!prog_in) FATAL("@@ syntax is not supported by this tool.");
 
-      /* Be sure that we're always using fully-qualified paths. */
+      use_stdin = 0;
 
-      if (prog_in[0] == '/')
-        aa_subst = prog_in;
-      else
-        aa_subst = alloc_printf("%s/%s", cwd, prog_in);
+      if (prog_in[0] != 0) {  // not afl-showmap special case
 
-      use_stdin = 0;
+        /* Be sure that we're always using fully-qualified paths. */
+
+        if (prog_in[0] == '/')
+          aa_subst = prog_in;
+        else
+          aa_subst = alloc_printf("%s/%s", cwd, prog_in);
 
-      /* Construct a replacement argv value. */
+        /* Construct a replacement argv value. */
 
-      *aa_loc = 0;
-      n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
-      argv[i] = n_arg;
-      *aa_loc = '@';
+        *aa_loc = 0;
+        n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
+        argv[i] = n_arg;
+        *aa_loc = '@';
 
-      if (prog_in[0] != '/') ck_free(aa_subst);
+        if (prog_in[0] != '/') ck_free(aa_subst);
+
+      }
 
     }
 
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 92bac4ab..3d34bf71 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -27,7 +27,7 @@
 #include "afl-fuzz.h"
 #include "cmplog.h"
 
-static s32 cmplog_child_pid, cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
+static s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
 
 void init_cmplog_forkserver(char** argv) {
 
@@ -150,8 +150,10 @@ void init_cmplog_forkserver(char** argv) {
            "msan_track_origins=0",
            0);
 
-    argv[0] = cmplog_binary;
-    execv(cmplog_binary, argv);
+    setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
+
+    if (!qemu_mode) argv[0] = cmplog_binary;
+    execv(argv[0], argv);
 
     /* Use a distinctive bitmap signature to tell the parent about execv()
        falling through. */
@@ -441,8 +443,10 @@ u8 run_cmplog_target(char** argv, u32 timeout) {
                              "symbolize=0:"
                              "msan_track_origins=0", 0);
 
-      argv[0] = cmplog_binary;
-      execv(cmplog_binary, argv);
+      setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
+
+      if (!qemu_mode) argv[0] = cmplog_binary;
+      execv(argv[0], argv);
 
       /* Use a distinctive bitmap value to tell the parent about execv()
          falling through. */
diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-globals.c
index 154f281e..d5d70542 100644
--- a/src/afl-fuzz-globals.c
+++ b/src/afl-fuzz-globals.c
@@ -252,7 +252,7 @@ u32                a_extras_cnt;        /* Total number of tokens available */
 u8 *(*post_handler)(u8 *buf, u32 *len);
 
 u8 *cmplog_binary;
-s32 cmplog_forksrv_pid;
+s32 cmplog_child_pid, cmplog_forksrv_pid;
 
 /* hooks for the custom mutator function */
 size_t (*custom_mutator)(u8 *data, size_t size, u8 *mutated_out,
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 9265e4a5..fc3e1140 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1822,6 +1822,8 @@ static void handle_stop_sig(int sig) {
 
   if (child_pid > 0) kill(child_pid, SIGKILL);
   if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);
+  if (cmplog_child_pid > 0) kill(cmplog_child_pid, SIGKILL);
+  if (cmplog_forksrv_pid > 0) kill(cmplog_forksrv_pid, SIGKILL);
 
 }
 
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index c21c973f..296fcd98 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -108,6 +108,8 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) {
   struct range* ranges = add_range(NULL, 0, len);
   u8*           backup = ck_alloc_nozero(len);
 
+  u8 needs_write = 0;
+
   u64 orig_hit_cnt, new_hit_cnt;
   orig_hit_cnt = queued_paths + unique_crashes;
 
@@ -120,6 +122,8 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) {
   while ((rng = pop_biggest_range(&ranges)) != NULL && stage_cur) {
 
     u32 s = rng->end - rng->start;
+    if (s == 0) goto empty_range;
+
     memcpy(backup, buf + rng->start, s);
     rand_replace(buf + rng->start, s);
 
@@ -132,8 +136,11 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) {
       ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end);
       memcpy(buf + rng->start, backup, s);
 
-    }
+    } else
 
+      needs_write = 1;
+
+  empty_range:
     ck_free(rng);
     --stage_cur;
 
@@ -151,6 +158,32 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) {
 
   }
 
+  // save the input with the high entropy
+
+  if (needs_write) {
+
+    s32 fd;
+
+    if (no_unlink) {
+
+      fd = open(queue_cur->fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+    } else {
+
+      unlink(queue_cur->fname);                            /* ignore errors */
+      fd = open(queue_cur->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
+
+    }
+
+    if (fd < 0) PFATAL("Unable to create '%s'", queue_cur->fname);
+
+    ck_write(fd, buf, len, queue_cur->fname);
+    queue_cur->len = len;  // no-op, just to be 100% safe
+
+    close(fd);
+
+  }
+
   return 0;
 
 }
@@ -270,6 +303,48 @@ u8 cmp_extend_encoding(struct cmp_header* h, u64 pattern, u64 repl, u32 idx,
 
 }
 
+void try_to_add_to_dict(u64 v, u8 shape) {
+
+  u8* b = (u8*)&v;
+
+  u32 k;
+  u8  cons_ff = 0, cons_0 = 0;
+  for (k = 0; k < shape; ++k) {
+
+    if (b[k] == 0)
+      ++cons_0;
+    else if (b[k] == 0xff)
+      ++cons_0;
+    else
+      cons_0 = cons_ff = 0;
+
+    if (cons_0 > 1 || cons_ff > 1) return;
+
+  }
+
+  maybe_add_auto((u8*)&v, shape);
+
+  u64 rev;
+  switch (shape) {
+
+    case 1: break;
+    case 2:
+      rev = SWAP16((u16)v);
+      maybe_add_auto((u8*)&rev, shape);
+      break;
+    case 4:
+      rev = SWAP32((u32)v);
+      maybe_add_auto((u8*)&rev, shape);
+      break;
+    case 8:
+      rev = SWAP64(v);
+      maybe_add_auto((u8*)&rev, shape);
+      break;
+
+  }
+
+}
+
 u8 cmp_fuzz(u32 key, u8* orig_buf, u8* buf, u32 len) {
 
   struct cmp_header* h = &cmp_map->headers[key];
@@ -311,6 +386,14 @@ u8 cmp_fuzz(u32 key, u8* orig_buf, u8* buf, u32 len) {
 
     }
 
+    // If failed, add to dictionary
+    if (fails == 8) {
+
+      try_to_add_to_dict(o->v0, SHAPE_BYTES(h->shape));
+      try_to_add_to_dict(o->v1, SHAPE_BYTES(h->shape));
+
+    }
+
   cmp_fuzz_next_iter:
     stage_cur++;
 
@@ -362,7 +445,7 @@ u8 input_to_state_stage(char** argv, u8* orig_buf, u8* buf, u32 len,
 
   }
 
-  memcpy(buf, orig_buf, len);
+  memcpy(orig_buf, buf, len);
 
   new_hit_cnt = queued_paths + unique_crashes;
   stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt;
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 9dc4b917..344e0abf 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -65,59 +65,62 @@ void write_stats_file(double bitmap_cvg, double stability, double eps) {
 
   if (getrusage(RUSAGE_CHILDREN, &rus)) rus.ru_maxrss = 0;
 
-  fprintf(f,
-          "start_time        : %llu\n"
-          "last_update       : %llu\n"
-          "fuzzer_pid        : %d\n"
-          "cycles_done       : %llu\n"
-          "execs_done        : %llu\n"
-          "execs_per_sec     : %0.02f\n"
-          "paths_total       : %u\n"
-          "paths_favored     : %u\n"
-          "paths_found       : %u\n"
-          "paths_imported    : %u\n"
-          "max_depth         : %u\n"
-          "cur_path          : %u\n"    /* Must match find_start_position() */
-          "pending_favs      : %u\n"
-          "pending_total     : %u\n"
-          "variable_paths    : %u\n"
-          "stability         : %0.02f%%\n"
-          "bitmap_cvg        : %0.02f%%\n"
-          "unique_crashes    : %llu\n"
-          "unique_hangs      : %llu\n"
-          "last_path         : %llu\n"
-          "last_crash        : %llu\n"
-          "last_hang         : %llu\n"
-          "execs_since_crash : %llu\n"
-          "exec_timeout      : %u\n"
-          "slowest_exec_ms   : %llu\n"
-          "peak_rss_mb       : %lu\n"
-          "afl_banner        : %s\n"
-          "afl_version       : " VERSION
-          "\n"
-          "target_mode       : %s%s%s%s%s%s%s%s\n"
-          "command_line      : %s\n",
-          start_time / 1000, get_cur_time() / 1000, getpid(),
-          queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, queued_paths,
-          queued_favored, queued_discovered, queued_imported, max_depth,
-          current_entry, pending_favored, pending_not_fuzzed, queued_variable,
-          stability, bitmap_cvg, unique_crashes, unique_hangs,
-          last_path_time / 1000, last_crash_time / 1000, last_hang_time / 1000,
-          total_execs - last_crash_execs, exec_tmout, slowest_exec_ms,
+  fprintf(
+      f,
+      "start_time        : %llu\n"
+      "last_update       : %llu\n"
+      "fuzzer_pid        : %d\n"
+      "cycles_done       : %llu\n"
+      "execs_done        : %llu\n"
+      "execs_per_sec     : %0.02f\n"
+      //          "real_execs_per_sec: %0.02f\n"  // damn the name is too long
+      "paths_total       : %u\n"
+      "paths_favored     : %u\n"
+      "paths_found       : %u\n"
+      "paths_imported    : %u\n"
+      "max_depth         : %u\n"
+      "cur_path          : %u\n"        /* Must match find_start_position() */
+      "pending_favs      : %u\n"
+      "pending_total     : %u\n"
+      "variable_paths    : %u\n"
+      "stability         : %0.02f%%\n"
+      "bitmap_cvg        : %0.02f%%\n"
+      "unique_crashes    : %llu\n"
+      "unique_hangs      : %llu\n"
+      "last_path         : %llu\n"
+      "last_crash        : %llu\n"
+      "last_hang         : %llu\n"
+      "execs_since_crash : %llu\n"
+      "exec_timeout      : %u\n"
+      "slowest_exec_ms   : %llu\n"
+      "peak_rss_mb       : %lu\n"
+      "afl_banner        : %s\n"
+      "afl_version       : " VERSION
+      "\n"
+      "target_mode       : %s%s%s%s%s%s%s%s\n"
+      "command_line      : %s\n",
+      start_time / 1000, get_cur_time() / 1000, getpid(),
+      queue_cycle ? (queue_cycle - 1) : 0, total_execs,
+      /*eps,*/ total_execs / ((double)(get_cur_time() - start_time) / 1000),
+      queued_paths, queued_favored, queued_discovered, queued_imported,
+      max_depth, current_entry, pending_favored, pending_not_fuzzed,
+      queued_variable, stability, bitmap_cvg, unique_crashes, unique_hangs,
+      last_path_time / 1000, last_crash_time / 1000, last_hang_time / 1000,
+      total_execs - last_crash_execs, exec_tmout, slowest_exec_ms,
 #ifdef __APPLE__
-          (unsigned long int)(rus.ru_maxrss >> 20),
+      (unsigned long int)(rus.ru_maxrss >> 20),
 #else
-          (unsigned long int)(rus.ru_maxrss >> 10),
+      (unsigned long int)(rus.ru_maxrss >> 10),
 #endif
-          use_banner, unicorn_mode ? "unicorn" : "", qemu_mode ? "qemu " : "",
-          dumb_mode ? " dumb " : "", no_forkserver ? "no_forksrv " : "",
-          crash_mode ? "crash " : "", persistent_mode ? "persistent " : "",
-          deferred_mode ? "deferred " : "",
-          (unicorn_mode || qemu_mode || dumb_mode || no_forkserver ||
-           crash_mode || persistent_mode || deferred_mode)
-              ? ""
-              : "default",
-          orig_cmdline);
+      use_banner, unicorn_mode ? "unicorn" : "", qemu_mode ? "qemu " : "",
+      dumb_mode ? " dumb " : "", no_forkserver ? "no_forksrv " : "",
+      crash_mode ? "crash " : "", persistent_mode ? "persistent " : "",
+      deferred_mode ? "deferred " : "",
+      (unicorn_mode || qemu_mode || dumb_mode || no_forkserver || crash_mode ||
+       persistent_mode || deferred_mode)
+          ? ""
+          : "default",
+      orig_cmdline);
   /* ignore errors */
 
   fclose(f);
@@ -765,8 +768,8 @@ void show_init_stats(void) {
       WARNF(cLRD "Some test cases are huge (%s) - see %s/perf_tips.md!",
             DMS(max_len), doc_path);
     else if (max_len > 10 * 1024)
-      WARNF("Some test cases are big (%s) - see %s/perf_tips.md.",
-            DMS(max_len), doc_path);
+      WARNF("Some test cases are big (%s) - see %s/perf_tips.md.", DMS(max_len),
+            doc_path);
 
     if (useless_at_start && !in_bitmap)
       WARNF(cLRD "Some test cases look useless. Consider using a smaller set.");
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 8833244d..8e4b22b1 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -100,7 +100,7 @@ static void usage(u8* argv0) {
       "  -f file       - location read by the fuzzed program (stdin)\n"
       "  -t msec       - timeout for each run (auto-scaled, 50-%d ms)\n"
       "  -m megs       - memory limit for child process (%d MB)\n"
-      "  -c program    - enable CmpLog specifying a binary compiled for it\n"
+      "  -c program    - enable CmpLog by specifying a binary compiled for it\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
       "  -W            - use qemu-based instrumentation with Wine (Wine "
@@ -1017,6 +1017,8 @@ int main(int argc, char** argv) {
 
     if (child_pid > 0) kill(child_pid, SIGKILL);
     if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);
+    if (cmplog_child_pid > 0) kill(cmplog_child_pid, SIGKILL);
+    if (cmplog_forksrv_pid > 0) kill(cmplog_forksrv_pid, SIGKILL);
     /* Now that we've killed the forkserver, we wait for it to be able to get
      * rusage stats. */
     if (waitpid(forksrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 5061ca31..1fd425a2 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -67,7 +67,7 @@ s32 forksrv_pid,                       /* PID of the fork server            */
 s32 fsrv_ctl_fd,                       /* Fork server control pipe (write)  */
     fsrv_st_fd;                        /* Fork server status pipe (read)    */
 
-s32 out_fd;                            /* Persistent fd for out_file        */
+s32 out_fd;                            /* Persistent fd for stdin_file      */
 s32 dev_null_fd = -1;                  /* FD to /dev/null                   */
 
 s32   out_fd = -1, out_dir_fd = -1, dev_urandom_fd = -1;
@@ -77,6 +77,7 @@ u8    uses_asan;
 u8* trace_bits;                        /* SHM with instrumentation bitmap   */
 
 u8 *out_file,                          /* Trace output file                 */
+    *stdin_file,                       /* stdin file                        */
     *in_dir,                           /* input folder                      */
     *doc_path,                         /* Path to docs                      */
     *at_file;                          /* Substitution string for @@        */
@@ -88,8 +89,7 @@ u32 exec_tmout;                        /* Exec timeout (ms)                 */
 static u32 total, highest;             /* tuple content information         */
 
 static u32 in_len,                     /* Input data length                 */
-    arg_offset,
-    total_execs;                       /* Total number of execs             */
+    arg_offset, total_execs;           /* Total number of execs             */
 
 u64 mem_limit = MEM_LIMIT;             /* Memory limit (MB)                 */
 
@@ -158,9 +158,17 @@ static void classify_counts(u8* mem, const u8* map) {
 
 }
 
+/* Get rid of temp files (atexit handler). */
+
+static void at_exit_handler(void) {
+
+  if (out_file) unlink(out_file);                          /* Ignore errors */
+
+}
+
 /* Write results. */
 
-static u32 write_results_to_file(u8 *out_file) {
+static u32 write_results_to_file(u8* out_file) {
 
   s32 fd;
   u32 i, ret = 0;
@@ -234,7 +242,7 @@ static u32 write_results_to_file(u8 *out_file) {
 static u32 write_results(void) {
 
   return write_results_to_file(out_file);
-  
+
 }
 
 /* Write output file. */
@@ -263,16 +271,10 @@ static s32 write_to_file(u8* path, u8* mem, u32 len) {
 
 static void write_to_testcase(void* mem, u32 len) {
 
-  if (use_stdin) {
-
-    lseek(0, 0, SEEK_SET);
-
-    ck_write(0, mem, len, out_file);
-
-    if (ftruncate(0, len)) PFATAL("ftruncate() failed");
-    lseek(0, 0, SEEK_SET);
-
-  }
+  lseek(out_fd, 0, SEEK_SET);
+  ck_write(out_fd, mem, len, out_file);
+  if (ftruncate(out_fd, len)) PFATAL("ftruncate() failed");
+  lseek(out_fd, 0, SEEK_SET);
 
 }
 
@@ -374,14 +376,15 @@ static u8 run_target_forkserver(char** argv, u8* mem, u32 len) {
 
 /* Read initial file. */
 
-u32 read_file(u8 *in_file) {
+u32 read_file(u8* in_file) {
 
   struct stat st;
   s32         fd = open(in_file, O_RDONLY);
 
   if (fd < 0) WARNF("Unable to open '%s'", in_file);
 
-  if (fstat(fd, &st) || !st.st_size) WARNF("Zero-sized input file '%s'.", in_file);
+  if (fstat(fd, &st) || !st.st_size)
+    WARNF("Zero-sized input file '%s'.", in_file);
 
   in_len = st.st_size;
   in_data = ck_alloc_nozero(in_len);
@@ -390,9 +393,10 @@ u32 read_file(u8 *in_file) {
 
   close(fd);
 
-  //OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
+  // OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
 
   return in_len;
+
 }
 
 /* Execute target application. */
@@ -634,7 +638,8 @@ static void usage(u8* argv0) {
 
       "Other settings:\n\n"
 
-      "  -i dir        - process all files in this directory, -o must be a directory\n"
+      "  -i dir        - process all files in this directory, -o must be a "
+      "directory\n"
       "                  and each bitmap will be written there individually.\n"
       "  -q            - sink program's output and don't show messages\n"
       "  -e            - show edge coverage only, ignore hit counts\n"
@@ -887,22 +892,21 @@ int main(int argc, char** argv) {
   if (!quiet_mode) {
 
     show_banner();
-    ACTF("Executing '%s'...\n", target_path);
+    ACTF("Executing '%s'...", target_path);
 
   }
 
-  if (in_dir)  {
-  
+  if (in_dir) {
+
     if (at_file) PFATAL("Options -A and -i are mutually exclusive");
     at_file = "@@";
-  
+
   }
 
-  detect_file_args(argv + optind, at_file);
-  
+  detect_file_args(argv + optind, "");
+
   for (i = optind; i < argc; i++)
-    if (strcmp(argv[i], "@@") == 0)
-      arg_offset = i;
+    if (strcmp(argv[i], "@@") == 0) arg_offset = i;
 
   if (qemu_mode) {
 
@@ -917,10 +921,13 @@ int main(int argc, char** argv) {
 
   if (in_dir) {
 
-    DIR *dir_in, *dir_out;
+    DIR *          dir_in, *dir_out;
     struct dirent* dir_ent;
-    int  done = 0;
-    u8 infile[4096], outfile[4096];
+    int            done = 0;
+    u8             infile[4096], outfile[4096];
+#if !defined(DT_REG)
+    struct stat statbuf;
+#endif
 
     dev_null_fd = open("/dev/null", O_RDWR);
     if (dev_null_fd < 0) PFATAL("Unable to open /dev/null");
@@ -931,26 +938,66 @@ int main(int argc, char** argv) {
       if (mkdir(out_file, 0700))
         PFATAL("cannot create output directory %s", out_file);
 
-    if (arg_offset) argv[arg_offset] = infile;
+    u8* use_dir = ".";
+
+    if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+      use_dir = getenv("TMPDIR");
+      if (!use_dir) use_dir = "/tmp";
+
+    }
+
+    stdin_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
+    unlink(stdin_file);
+    atexit(at_exit_handler);
+    out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600);
+    if (out_fd < 0) PFATAL("Unable to create '%s'", out_file);
+
+    if (arg_offset) argv[arg_offset] = stdin_file;
+
+    if (getenv("AFL_DEBUG")) {
+
+      int i = optind;
+      SAYF(cMGN "[D]" cRST " %s:", target_path);
+      while (argv[i] != NULL)
+        SAYF(" \"%s\"", argv[i++]);
+      SAYF("\n");
+      SAYF(cMGN "[D]" cRST " %d - %d = %d, %s\n", arg_offset, optind,
+           arg_offset - optind, infile);
+
+    }
 
     init_forkserver(use_argv);
 
     while (done == 0 && (dir_ent = readdir(dir_in))) {
 
-      if (dir_ent->d_name[0] == '.') continue; // skip anything that starts with '.'
-      if (dir_ent->d_type != DT_REG) continue; // only regular files
+      if (dir_ent->d_name[0] == '.')
+        continue;  // skip anything that starts with '.'
+
+#if defined(DT_REG)      /* Posix and Solaris do not know d_type and DT_REG */
+      if (dir_ent->d_type != DT_REG) continue;  // only regular files
+#endif
 
       snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name);
+
+#if !defined(DT_REG)                                          /* use stat() */
+      if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue;
+#endif
+
       snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
 
       if (read_file(infile)) {
+
         run_target_forkserver(use_argv, in_data, in_len);
         ck_free(in_data);
         tcnt = write_results_to_file(outfile);
+
       }
 
     }
 
+    if (!quiet_mode) OKF("Processed %u input files.", total_execs);
+
   } else {
 
     run_target(use_argv);
@@ -969,3 +1016,4 @@ int main(int argc, char** argv) {
   exit(child_crashed * 2 + child_timed_out);
 
 }
+
diff --git a/src/third_party/libradamsa/libradamsa.c b/src/third_party/libradamsa/libradamsa.c
index be3050b1..f3677fa7 100644
--- a/src/third_party/libradamsa/libradamsa.c
+++ b/src/third_party/libradamsa/libradamsa.c
@@ -2405,7 +2405,11 @@ static word prim_sys(word op, word a, word b, word c) {
             EOPNOTSUPP, EOVERFLOW, EOWNERDEAD, EPERM, EPIPE, EPROTO, EPROTONOSUPPORT, EPROTOTYPE,
             ERANGE, EROFS, ESPIPE, ESRCH, ESTALE, ETIME, ETIMEDOUT, ETXTBSY,
             EWOULDBLOCK, EXDEV, SEEK_SET, SEEK_CUR, SEEK_END, O_EXEC, O_RDONLY, O_RDWR,
-            O_SEARCH, O_WRONLY, O_APPEND, O_CLOEXEC, O_CREAT, O_DIRECTORY, O_DSYNC, O_EXCL,
+            O_SEARCH, O_WRONLY, O_APPEND, O_CLOEXEC, O_CREAT,
+#if defined O_DIRECTORY
+                                                              O_DIRECTORY,
+#endif
+                                                                           O_DSYNC, O_EXCL,
             O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_RSYNC, O_SYNC, O_TRUNC, O_TTY_INIT, O_ACCMODE,
             FD_CLOEXEC, F_DUPFD, F_DUPFD_CLOEXEC, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETOWN,
             F_SETOWN, F_GETLK, F_SETLK, F_SETLKW, F_RDLCK, F_UNLCK, F_WRLCK, CLOCK_MONOTONIC,