aboutsummaryrefslogtreecommitdiff
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,