From 8618fbc0c267b61ca094bc4fd328f0036ad093c8 Mon Sep 17 00:00:00 2001 From: Justus Perlwitz Date: Tue, 29 Apr 2025 14:44:20 +0900 Subject: [PATCH 01/14] Let user pass their own CPU_TARGET in test-pre.sh The target system might be different from the host system. For example, you can fuzz Linux binaries compiled for *mipsel*, while your host is *x86_64*. Some of the tests depend on specific platforms to run correctly. For example, the afl-fuzz qemu_mode cmplog test only works on Intel or ARM systems. The `SYS` variable is populated using `uname -m` and the test cases then consult this variable to decide whether to run the test or not. If you want to test afl-fuzz for qemu_mode on mipsel, you might want to make sure that Intel or ARM tests don't run. With this patch, you can supply your own `CPU_TARGET` environment variable and skip platform specific tests. `SYS` then contains the value of `CPU_TARGET`. This allows you to add tests for *mipsel* or other niche platforms in the future as well. Sample usage: ``` $ cd qemu_mode && env CPU_TARGET=mipsel ./build_qemu_support.sh $ cd ../test && env CPU_TARGET=mipsel ./test-qemu-mode.sh [*] Using environment variable CPU_TARGET=mipsel for SYS [*] starting AFL++ test framework ... [*] Testing: qemu_mode ... ``` --- test/test-pre.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/test-pre.sh b/test/test-pre.sh index cc6344423f..9f30b3cc7a 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -113,8 +113,6 @@ test -e /usr/local/bin/opt && { } AFL_COMPILER=afl-clang-fast -SYS=`uname -m` - GREY="\\033[1;90m" BLUE="\\033[1;94m" GREEN="\\033[0;32m" @@ -122,6 +120,13 @@ RED="\\033[0;31m" YELLOW="\\033[1;93m" RESET="\\033[0m" +if test -n "$CPU_TARGET"; then + $ECHO "${RESET}${GREY}[*] Using environment variable CPU_TARGET=$CPU_TARGET for SYS" + SYS="$CPU_TARGET" +else + SYS=`uname -m` +fi + MEM_LIMIT=none export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" From 91974bfae2c884aa327716a4d2f152ad3cb310db Mon Sep 17 00:00:00 2001 From: Justus Perlwitz Date: Tue, 3 Jun 2025 14:59:09 +0900 Subject: [PATCH 02/14] Clean up test-pre.sh bash syntax shellcheck pointed out a few command substition (backtick vs. $(...)) and quoting issues. This patch fixes them. --- test/test-pre.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test-pre.sh b/test/test-pre.sh index 9f30b3cc7a..8a7dda0c67 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -17,9 +17,9 @@ test -z "" 2>/dev/null || { echo Error: test command not found ; exit 1 ; } GREP=`type grep > /dev/null 2>&1 && echo OK` test "$GREP" = OK || { echo Error: grep command not found ; exit 1 ; } echo foobar | grep -qE 'asd|oob' 2>/dev/null || { echo Error: grep command does not support -q and/or -E option ; exit 1 ; } -test -e ./test-all.sh || cd $(dirname $0) || exit 1 +test -e ./test-all.sh || cd $(dirname "$0") || exit 1 test -e ./test-all.sh || { echo Error: you must be in the test/ directory ; exit 1 ; } -export AFL_PATH=`pwd`/.. +export AFL_PATH="$(pwd)/.." export AFL_TRY_AFFINITY=1 # workaround for travis that fails for no avail cores echo 1 > test.1 @@ -59,7 +59,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || { $ECHO "\\101" 2>&1 | grep -qE '^A' || ECHO= } } -test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; } +test -z "$ECHO" && { echo Error: printf command does not support octal character codes ; exit 1 ; } export AFL_EXIT_WHEN_DONE=1 export AFL_EXIT_ON_TIME=60 @@ -109,7 +109,7 @@ test -n "$TRAVIS_OS_NAME" && { # on OpenBSD we need to work with llvm from /usr/local/bin test -e /usr/local/bin/opt && { - test `uname -s` = 'Darwin' || export PATH="/usr/local/bin:${PATH}" + test "$(uname -s)" = 'Darwin' || export PATH="/usr/local/bin:${PATH}" } AFL_COMPILER=afl-clang-fast @@ -124,7 +124,7 @@ if test -n "$CPU_TARGET"; then $ECHO "${RESET}${GREY}[*] Using environment variable CPU_TARGET=$CPU_TARGET for SYS" SYS="$CPU_TARGET" else - SYS=`uname -m` + SYS=$(uname -m) fi MEM_LIMIT=none From c8d1b66af3706ebd4da831e352d5720fc323312e Mon Sep 17 00:00:00 2001 From: GRAUX Pierre Date: Wed, 23 Apr 2025 14:39:31 +0200 Subject: [PATCH 03/14] add AFL_FORKSRV_UID and AFL_FORKSRV_GID env vars --- docs/env_variables.md | 17 ++++++ include/afl-fuzz.h | 23 +++++++- include/common.h | 4 +- include/config.h | 3 ++ include/envs.h | 3 +- include/forkserver.h | 10 ++++ include/sharedmem.h | 3 +- src/afl-analyze.c | 2 +- src/afl-common.c | 8 +-- src/afl-forkserver.c | 64 ++++++++++++++++++++-- src/afl-fuzz-bitmap.c | 24 +++++++-- src/afl-fuzz-extras.c | 8 ++- src/afl-fuzz-init.c | 117 ++++++++++++++++++++++++++++++++-------- src/afl-fuzz-mutators.c | 8 ++- src/afl-fuzz-one.c | 3 +- src/afl-fuzz-queue.c | 9 +++- src/afl-fuzz-run.c | 44 +++++++++++---- src/afl-fuzz-state.c | 85 +++++++++++++++++++++++++++++ src/afl-fuzz-stats.c | 24 +++++++-- src/afl-fuzz.c | 68 ++++++++++++++++++++--- src/afl-sharedmem.c | 70 ++++++++++++++++++++---- src/afl-showmap.c | 8 +-- src/afl-tmin.c | 8 +-- 23 files changed, 536 insertions(+), 77 deletions(-) diff --git a/docs/env_variables.md b/docs/env_variables.md index a492a1bcb6..1faafcd4f4 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -686,6 +686,23 @@ checks or alter some of the more exotic semantics of the tool: } ``` + - `AFL_FORKSRV_UID` allows you to specify the UID that should be used when + running the fork server. When setting this variable, user should ensure + afl-fuzz binary has enough privileges to modify the UID (e.g. CAP\_SETUID + capability in Linux system). + + - `AFL_FORKSRV_GID` allows you to specify the GID and the supplementary group + IDs that should be used when running the fork server. When setting this + variable, user should ensure afl-fuzz binary has enough privileges to + modify the GIDs (e.g. CAP\_SETGID capability in Linux system). + + - When both `AFL_FORKSRV_UID` and `AFL_FORKSRV_GID` are set, afl-fuzz binary + and the fork server no longer share any IDs. Thus, afl-fuzz binary changes + the group owner of the created files to ensure that the fork server can + still access them. In such case, user should ensure afl-fuzz binary has + enough privileges to modify the ownership of entities (e.g. CAP\_CHOWN + capability in Linux system). + ## 6) Settings for afl-qemu-trace The QEMU wrapper used to instrument binary-only code supports several settings: diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 60cc896b79..a0ee58bf73 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -462,7 +462,10 @@ typedef struct afl_env_vars { afl_no_startup_calibration, afl_no_warn_instability, afl_post_process_keep_original, afl_crashing_seeds_as_new_crash, afl_final_sync, afl_ignore_seed_problems, afl_disable_redundant, - afl_sha1_filenames, afl_no_sync, afl_no_fastresume; + afl_sha1_filenames, afl_no_sync, afl_no_fastresume, afl_forksrv_uid_set, + afl_forksrv_gid_set; + + u16 afl_forksrv_nb_supl_gids; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, @@ -473,6 +476,12 @@ typedef struct afl_env_vars { s32 afl_pizza_mode; + uid_t afl_forksrv_uid; + + gid_t afl_forksrv_gid; + + gid_t *afl_forksrv_supl_gids; + } afl_env_vars_t; struct afl_pass_stat { @@ -555,6 +564,10 @@ typedef struct afl_state { *orig_cmdline, /* Original command line */ *infoexec; /* Command to execute on a new crash */ + mode_t perm, /* File permission when creating files */ + dir_perm; /* File permission when creating directories */ + u8 chown_needed; /* Group owner of files needs to be modified */ + u32 hang_tmout, /* Timeout used for hang det (ms) */ stats_update_freq; /* Stats update frequency (execs) */ @@ -1443,7 +1456,7 @@ char *sha1_hex_for_file(const char *fname, u32 len); * enabled. */ static inline int permissive_create(afl_state_t *afl, const char *fn) { - int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (unlikely(fd < 0)) { if (!(afl->afl_env.afl_sha1_filenames && errno == EEXIST)) { @@ -1454,6 +1467,12 @@ static inline int permissive_create(afl_state_t *afl, const char *fn) { } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + return fd; } diff --git a/include/common.h b/include/common.h index 7c665c9d78..bd16a8ca76 100644 --- a/include/common.h +++ b/include/common.h @@ -144,10 +144,10 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms); u32 get_map_size(void); /* create a stream file */ -FILE *create_ffile(u8 *fn); +FILE *create_ffile(u8 *fn, mode_t perm); /* create a file */ -s32 create_file(u8 *fn); +s32 create_file(u8 *fn, mode_t perm); /* memmem implementation as not all platforms support this */ void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, diff --git a/include/config.h b/include/config.h index d00f170955..4757e559c5 100644 --- a/include/config.h +++ b/include/config.h @@ -49,6 +49,9 @@ Default: 300 (seconds) */ #define STRATEGY_SWITCH_TIME 1000 +/* Default file permission umode when creating directories */ +#define DEFAULT_DIRS_PERMISSION 0700 + /* Default file permission umode when creating files (default: 0600) */ #define DEFAULT_PERMISSION 0600 diff --git a/include/envs.h b/include/envs.h index 25063b8a57..336421740a 100644 --- a/include/envs.h +++ b/include/envs.h @@ -120,7 +120,8 @@ static char *afl_environment_variables[] = { "AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN", "AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME", "AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV", - "AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", NULL}; + "AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", + "AFL_FORKSRV_UID", "AFL_FORKSRV_GID", NULL}; extern char *afl_environment_variables[]; diff --git a/include/forkserver.h b/include/forkserver.h index 41f8532753..cbd4711e18 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -187,6 +187,16 @@ typedef struct afl_forkserver { s32 persistent_record_pid; #endif + u8 uid_set; + uid_t uid; + u8 gid_set; + pid_t gid; + u16 nb_supl_gids; + pid_t *supl_gids; + + mode_t perm; + u8 chown_needed; + /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/include/sharedmem.h b/include/sharedmem.h index 140ee26685..948c92257e 100644 --- a/include/sharedmem.h +++ b/include/sharedmem.h @@ -57,7 +57,8 @@ typedef struct sharedmem { } sharedmem_t; -u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode); +u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode, + mode_t mode, int gid); void afl_shm_deinit(sharedmem_t *); #endif diff --git a/src/afl-analyze.c b/src/afl-analyze.c index a006498a51..250ceab1fc 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -984,7 +984,7 @@ int main(int argc, char **argv_orig, char **envp) { fsrv.target_path = find_binary(argv[optind]); #endif - fsrv.trace_bits = afl_shm_init(&shm, map_size, 0); + fsrv.trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1); detect_file_args(argv + optind, fsrv.out_file, &use_stdin); signal(SIGALRM, kill_child); diff --git a/src/afl-common.c b/src/afl-common.c index fbbf8e0d77..f4050896e9 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1397,12 +1397,12 @@ u32 get_map_size(void) { /* Create a stream file */ -FILE *create_ffile(u8 *fn) { +FILE *create_ffile(u8 *fn, mode_t mode) { s32 fd; FILE *f; - fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, mode); if (fd < 0) { PFATAL("Unable to create '%s'", fn); } @@ -1416,11 +1416,11 @@ FILE *create_ffile(u8 *fn) { /* Create a file */ -s32 create_file(u8 *fn) { +s32 create_file(u8 *fn, mode_t mode) { s32 fd; - fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, mode); if (fd < 0) { PFATAL("Unable to create '%s'", fn); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 5bf300a3b1..a8bb8ca9ab 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -51,6 +51,7 @@ #include #include #include +#include #ifdef __linux__ #include @@ -208,9 +209,35 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { } + if (fsrv->gid_set) { + + if (setregid(fsrv->gid, fsrv->gid) == -1) { + + FATAL("setgid failed: %s\n", strerror(errno)); + + } + + if (setgroups(fsrv->nb_supl_gids, fsrv->supl_gids) == -1) { + + FATAL("setgroups failed: %s\n", strerror(errno)); + + } + + } + + if (fsrv->uid_set) { + + if (setreuid(fsrv->uid, fsrv->uid) == -1) { + + FATAL("setuid failed: %s\n", strerror(errno)); + + } + + } + execv(fsrv->target_path, argv); - WARNF("Execv failed in forkserver."); + WARNF("Execv failed in forkserver: %s.", strerror(errno)); } @@ -274,6 +301,9 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->persistent_trace_bits = NULL; #endif + fsrv->uid_set = 0; + fsrv->gid_set = 0; + fsrv->init_child_func = fsrv_exec_child; list_append(&fsrv_list, fsrv); @@ -493,6 +523,26 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { close(FORKSRV_FD); close(FORKSRV_FD + 1); + if (fsrv->gid_set) { + + if (setgid(fsrv->gid) == -1) { + + FATAL("setgid failed: %s\n", strerror(errno)); + + } + + } + + if (fsrv->uid_set) { + + if (setuid(fsrv->uid) == -1) { + + FATAL("setuid failed: %s\n", strerror(errno)); + + } + + } + // finally: exec... execv(fsrv->target_path, argv); @@ -1839,14 +1889,18 @@ void __attribute__((hot)) afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, if (unlikely(fsrv->no_unlink)) { - fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, - DEFAULT_PERMISSION); + fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, fsrv->perm); } else { unlink(fsrv->out_file); /* Ignore errors. */ - fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, - DEFAULT_PERMISSION); + fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, fsrv->perm); + + } + + if (fsrv->chown_needed) { + + if (fchown(fd, -1, fsrv->gid) == -1) { PFATAL("fchown() failed"); } } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index e3c114f54b..c6b1723d3c 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -84,10 +84,16 @@ void write_bitmap(afl_state_t *afl) { afl->bitmap_changed = 0; snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir); - fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); + fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, afl->perm); if (fd < 0) { PFATAL("Unable to open '%s'", fname); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname); close(fd); @@ -429,12 +435,18 @@ void write_crash_readme(afl_state_t *afl) { sprintf(fn, "%s/crashes/README.txt", afl->out_dir); - fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm); /* Do not die on errors here - that would be impolite. */ if (unlikely(fd < 0)) { return; } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + f = fdopen(fd, "w"); if (unlikely(!f)) { @@ -1076,9 +1088,15 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, u8 fn_log[PATH_MAX]; (void)(snprintf(fn_log, PATH_MAX, "%s.log", fn) + 1); - fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(fn_log, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn_log); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + u32 nyx_aux_string_len = afl->fsrv.nyx_handlers->nyx_get_aux_string( afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string, afl->fsrv.nyx_aux_string_len); diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 09338bb6b4..c2e4b24b67 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -748,10 +748,16 @@ void save_auto(afl_state_t *afl) { s32 fd; - fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", fn); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_write(fd, afl->a_extras[i].data, afl->a_extras[i].len, fn); close(fd); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index d6dee35290..14f36802ba 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1268,9 +1268,20 @@ void perform_dry_run(afl_state_t *afl) { ++afl->saved_crashes; - fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", crash_fn); } ck_write(fd, use_mem, read_len, crash_fn); + + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } + close(fd); #ifdef __linux__ @@ -1279,8 +1290,7 @@ void perform_dry_run(afl_state_t *afl) { u8 crash_log_fn[PATH_MAX]; snprintf(crash_log_fn, PATH_MAX, "%s.log", crash_fn); - fd = open(crash_log_fn, O_WRONLY | O_CREAT | O_EXCL, - DEFAULT_PERMISSION); + fd = open(crash_log_fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", crash_log_fn); @@ -1293,6 +1303,17 @@ void perform_dry_run(afl_state_t *afl) { ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len, crash_log_fn); + + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } + close(fd); } @@ -1483,7 +1504,7 @@ void perform_dry_run(afl_state_t *afl) { /* Helper function: link() if possible, copy otherwise. */ -static void link_or_copy(u8 *old_path, u8 *new_path) { +static void link_or_copy(u8 *old_path, u8 *new_path, mode_t perm) { s32 i = link(old_path, new_path); if (!i) { return; } @@ -1494,7 +1515,7 @@ static void link_or_copy(u8 *old_path, u8 *new_path) { sfd = open(old_path, O_RDONLY); if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); } - dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, perm); if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); } tmp = ck_alloc(64 * 1024); @@ -1630,10 +1651,16 @@ void pivot_inputs(afl_state_t *afl) { /* Pivot to the new queue entry. */ - link_or_copy(q->fname, nfn); + link_or_copy(q->fname, nfn, afl->perm); ck_free(q->fname); q->fname = nfn; + if (afl->chown_needed) { + + if (chown(nfn, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + /* Make sure that the passed_det value carries over, too. */ if (q->passed_det) { mark_as_det_done(afl, q); } @@ -2240,13 +2267,15 @@ void setup_dirs_fds(afl_state_t *afl) { ACTF("Setting up output directories..."); - if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) { + if (afl->sync_id && mkdir(afl->sync_dir, afl->dir_perm) && errno != EEXIST) { PFATAL("Unable to create '%s'", afl->sync_dir); } - if (mkdir(afl->out_dir, 0700)) { + printf("out_dir = %s\n", afl->out_dir); + + if (mkdir(afl->out_dir, afl->dir_perm)) { if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); } @@ -2254,6 +2283,16 @@ void setup_dirs_fds(afl_state_t *afl) { } else { + if (afl->chown_needed) { + + if (chown(afl->out_dir, -1, afl->fsrv.gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } + if (afl->in_place_resume) { FATAL("Resume attempted but old output directory not found"); @@ -2288,27 +2327,27 @@ void setup_dirs_fds(afl_state_t *afl) { /* Queue directory for any starting & discovered paths. */ tmp = alloc_printf("%s/queue", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Top-level directory for queue metadata used for session resume and related tasks. */ tmp = alloc_printf("%s/queue/.state/", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Directory for flagging queue entries that went through deterministic fuzzing in the past. */ tmp = alloc_printf("%s/queue/.state/deterministic_done/", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Directory with the auto-selected dictionary entries. */ tmp = alloc_printf("%s/queue/.state/auto_extras/", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Sync directory for keeping track of cooperating fuzzers. */ @@ -2317,7 +2356,8 @@ void setup_dirs_fds(afl_state_t *afl) { tmp = alloc_printf("%s/.synced/", afl->out_dir); - if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) { + if (mkdir(tmp, afl->dir_perm) && + (!afl->in_place_resume || errno != EEXIST)) { PFATAL("Unable to create '%s'", tmp); @@ -2330,13 +2370,13 @@ void setup_dirs_fds(afl_state_t *afl) { /* All recorded crashes. */ tmp = alloc_printf("%s/crashes", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* All recorded hangs. */ tmp = alloc_printf("%s/hangs", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + if (mkdir(tmp, afl->dir_perm)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Generally useful file descriptors. */ @@ -2353,8 +2393,14 @@ void setup_dirs_fds(afl_state_t *afl) { if (!afl->in_place_resume) { - int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_free(tmp); afl->fsrv.plot_file = fdopen(fd, "w"); @@ -2380,8 +2426,14 @@ void setup_dirs_fds(afl_state_t *afl) { } else { - int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION); + int fd = open(tmp, O_WRONLY | O_CREAT, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_free(tmp); afl->fsrv.plot_file = fdopen(fd, "w"); @@ -2397,8 +2449,14 @@ void setup_dirs_fds(afl_state_t *afl) { tmp = alloc_printf("%s/plot_det_data", afl->out_dir); - int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION); + int fd = open(tmp, O_WRONLY | O_CREAT, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_free(tmp); afl->fsrv.det_plot_file = fdopen(fd, "w"); @@ -2422,8 +2480,14 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) { /* Store the command line to reproduce our findings */ tmp = alloc_printf("%s/cmdline", afl->out_dir); - fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_free(tmp); cmdline_file = fdopen(fd, "w"); @@ -2458,7 +2522,7 @@ void setup_stdio_file(afl_state_t *afl) { unlink(afl->fsrv.out_file); /* Ignore errors */ afl->fsrv.out_fd = - open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, afl->perm); if (afl->fsrv.out_fd < 0) { @@ -2466,6 +2530,16 @@ void setup_stdio_file(afl_state_t *afl) { } + if (afl->chown_needed) { + + if (fchown(afl->fsrv.out_fd, -1, afl->fsrv.gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } + } /* Make sure that core dumps don't go to a program. */ @@ -2902,7 +2976,8 @@ void setup_testcase_shmem(afl_state_t *afl) { // we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT; - u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 1); + u8 *map = afl_shm_init(afl->shm_fuzz, shm_fuzz_map_size, 1, afl->perm, + afl->chown_needed ? afl->fsrv.gid : -1); afl->shm_fuzz->shmemfuzz_mode = 1; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 7c7a4b9f5d..186bac4713 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -623,10 +623,16 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, unlink(q->fname); /* ignore errors */ - fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + ck_write(fd, out_buf, out_len, q->fname); close(fd); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index bccfe45f4f..ea44be5a5e 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -6178,7 +6178,8 @@ u8 fuzz_one(afl_state_t *afl) { if (afl->do_document == 0) { snprintf(path_buf, PATH_MAX, "%s/mutations", afl->out_dir); - afl->do_document = mkdir(path_buf, 0700); // if it exists we do not care + afl->do_document = + mkdir(path_buf, afl->dir_perm); // if it exists we do not care afl->do_document = 1; } else { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index faec406d8c..2b8dbd7110 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -432,8 +432,15 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir, strrchr((char *)q->fname, '/') + 1); - fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", fn); } + + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + close(fd); q->passed_det = 1; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a6a70c59b9..828094c426 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -258,11 +258,21 @@ u32 __attribute__((hot)) write_to_testcase(afl_state_t *afl, void **mem, afl->document_counter++, describe_op(afl, 0, NAME_MAX - strlen("000000000:"))); - if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >= - 0) { + if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, afl->perm)) >= 0) { if (write(doc_fd, *mem, len) != len) PFATAL("write to mutation file failed: %s", fn); + + if (afl->chown_needed) { + + if (fchown(doc_fd, -1, afl->fsrv.gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } + close(doc_fd); } @@ -386,19 +396,23 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, if (unlikely(afl->no_unlink)) { - fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, - DEFAULT_PERMISSION); + fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, afl->perm); } else { unlink(afl->fsrv.out_file); /* Ignore errors. */ - fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, - DEFAULT_PERMISSION); + fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, afl->perm); } if (fd < 0) { PFATAL("Unable to create '%s'", afl->fsrv.out_file); } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + } else { lseek(fd, 0, SEEK_SET); @@ -895,10 +909,16 @@ void sync_fuzzers(afl_state_t *afl) { sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name); - id_fd = open(qd_synced_path, O_RDWR | O_CREAT, DEFAULT_PERMISSION); + id_fd = open(qd_synced_path, O_RDWR | O_CREAT, afl->perm); if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); } + if (afl->chown_needed) { + + if (fchown(id_fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + if (read(id_fd, &min_accept, sizeof(u32)) == sizeof(u32)) { next_min_accept = min_accept; @@ -1296,7 +1316,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (unlikely(afl->no_unlink)) { - fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); + fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } @@ -1311,7 +1331,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } else { unlink(q->fname); /* ignore errors */ - fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, afl->perm); if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } @@ -1319,6 +1339,12 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } + if (afl->chown_needed) { + + if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } + close(fd); queue_testcase_retake_mem(afl, q, in_buf, q->len, orig_len); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f1a9491038..993bb5dbbc 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -683,6 +683,89 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_sha1_filenames = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_FORKSRV_UID", + + afl_environment_variable_len)) { + + u8 *uid_str = (u8 *)get_afl_env(afl_environment_variables[i]); + char *ret; + int uid = strtol(uid_str, &ret, 10); + if (*ret != '\0') { + + WARNF("Incorrect value given to AFL_FORKSRV_UID\n"); + + } else { + + afl->afl_env.afl_forksrv_uid_set = 1; + afl->afl_env.afl_forksrv_uid = uid; + + } + + } else if (!strncmp(env, "AFL_FORKSRV_GID", + + afl_environment_variable_len)) { + + u8 *gid_str = (u8 *)get_afl_env(afl_environment_variables[i]); + + // Count the number of supplementary GIDs + // and prepare the string for the next loop + afl->afl_env.afl_forksrv_nb_supl_gids = 0; + for (u32 i = 0; gid_str[i] != '\0'; i++) { + + if (gid_str[i] == ',') { + + afl->afl_env.afl_forksrv_nb_supl_gids++; + gid_str[i] = '\0'; + + } + + } + + if (afl->afl_env.afl_forksrv_nb_supl_gids > 0) { + + afl->afl_env.afl_forksrv_supl_gids = ck_alloc( + sizeof(gid_t) * afl->afl_env.afl_forksrv_nb_supl_gids); + + } + + for (u16 i = 0; i < afl->afl_env.afl_forksrv_nb_supl_gids + 1; + i++) { + + char *ret; + int gid = strtol(gid_str, &ret, 10); + + if (*ret != '\0') { + + WARNF("Incorrect value given to AFL_FORKSRV_GID\n"); + + afl->afl_env.afl_forksrv_gid_set = 0; + afl->afl_env.afl_forksrv_gid = 0; + free(afl->afl_env.afl_forksrv_supl_gids); + + break; + + } else { + + // First GID is the effective one, others are supplementary + // ones. + if (i == 0) { + + afl->afl_env.afl_forksrv_gid_set = 1; + afl->afl_env.afl_forksrv_gid = gid; + + } else { + + afl->afl_env.afl_forksrv_supl_gids[i - 1] = gid; + + } + + // Jump to next GID + gid_str = ret + 1; + + } + + } + } } else { @@ -808,6 +891,8 @@ void afl_state_deinit(afl_state_t *afl) { ck_free(afl->skipdet_g); ck_free(afl->havoc_prof); + ck_free(afl->afl_env.afl_forksrv_supl_gids); + list_remove(&afl_states, afl); } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 8a04f47524..4de2c8559f 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -86,7 +86,13 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { u8 fn[PATH_MAX], fn2[PATH_MAX]; snprintf(fn2, PATH_MAX, "%s/target_hash", afl->out_dir); - FILE *f2 = create_ffile(fn2); + FILE *f2 = create_ffile(fn2, afl->perm); + + if (afl->chown_needed) { + + if (chown(fn2, -1, afl->fsrv.gid) == -1) { PFATAL("chown() failed"); } + + } #ifdef __linux__ if (afl->fsrv.nyx_mode) { @@ -106,9 +112,15 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { fclose(f2); snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); - FILE *f = create_ffile(fn); + FILE *f = create_ffile(fn, afl->perm); u32 i; + if (afl->chown_needed) { + + if (chown(fn, -1, afl->fsrv.gid) == -1) { PFATAL("chown() failed"); } + + } + fprintf(f, "# environment variables:\n"); u32 s_afl_env = (u32)sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - @@ -323,7 +335,13 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, snprintf(fn_tmp, PATH_MAX, "%s/.fuzzer_stats_tmp", afl->out_dir); snprintf(fn_final, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); - f = create_ffile(fn_tmp); + f = create_ffile(fn_tmp, afl->perm); + + if (afl->chown_needed) { + + if (chown(fn_tmp, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); } + + } /* Keep last values in case we're called from another context where exec/sec stats and such are not readily available. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ae2033492a..07d5367f13 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -602,6 +602,49 @@ int main(int argc, char **argv_orig, char **envp) { if (debug) { afl->fsrv.debug = true; } read_afl_environment(afl, envp); if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; } + + if (afl->afl_env.afl_forksrv_uid_set) { + + afl->fsrv.uid_set = 1; + afl->fsrv.uid = afl->afl_env.afl_forksrv_uid; + + } + + if (afl->afl_env.afl_forksrv_gid_set) { + + afl->fsrv.gid_set = 1; + afl->fsrv.gid = afl->afl_env.afl_forksrv_gid; + afl->fsrv.nb_supl_gids = afl->afl_env.afl_forksrv_nb_supl_gids; + afl->fsrv.supl_gids = afl->afl_env.afl_forksrv_supl_gids; + + } + + if (afl->fsrv.uid_set) { + + /* If the UID is modified, allow group to open files and dirs */ + afl->perm = DEFAULT_PERMISSION | 0060; + afl->fsrv.perm = afl->perm; + afl->dir_perm = DEFAULT_DIRS_PERMISSION | 0070; + + /* Ensure permissions will be really set*/ + umask(~(afl->perm | afl->dir_perm)); + + /* If the GID is also modified, then change the group of files and dirs */ + if (afl->fsrv.gid_set) { + + afl->chown_needed = 1; + afl->fsrv.chown_needed = 1; + + } + + } else { + + afl->perm = DEFAULT_PERMISSION; + afl->fsrv.perm = afl->perm; + afl->dir_perm = DEFAULT_DIRS_PERMISSION; + + } + exit_1 = !!afl->afl_env.afl_bench_just_one; SAYF(cCYA "afl-fuzz" VERSION cRST @@ -2505,7 +2548,8 @@ int main(int argc, char **argv_orig, char **envp) { afl->argv = use_argv; afl->fsrv.trace_bits = - afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); + afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode, + afl->perm, afl->chown_needed ? afl->fsrv.gid : -1); if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode && @@ -2533,7 +2577,8 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_deinit(&afl->shm); afl->fsrv.map_size = new_map_size; afl->fsrv.trace_bits = - afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode); + afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode, + afl->perm, afl->chown_needed ? afl->fsrv.gid : -1); setenv("AFL_NO_AUTODICT", "1", 1); // loaded already afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child); @@ -2630,7 +2675,8 @@ int main(int argc, char **argv_orig, char **envp) { setenv("AFL_NO_AUTODICT", "1", 1); // loaded already afl->fsrv.trace_bits = - afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode); + afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode, + afl->perm, afl->chown_needed ? afl->fsrv.gid : -1); ck_free(afl->san_fsrvs[i].trace_bits); afl->san_fsrvs[i].trace_bits = ck_alloc(afl->fsrv.map_size + 8); afl->san_fsrvs[i].map_size = afl->fsrv.map_size; @@ -2696,7 +2742,8 @@ int main(int argc, char **argv_orig, char **envp) { setenv("AFL_NO_AUTODICT", "1", 1); // loaded already afl->fsrv.trace_bits = - afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode); + afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode, + afl->perm, afl->chown_needed ? afl->fsrv.gid : -1); afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child); @@ -3446,8 +3493,17 @@ int main(int argc, char **argv_orig, char **envp) { if ((fr_fd = ZLIBOPEN(fr, "wb9")) != NULL) { #else - if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >= - 0) { + if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, afl->perm)) >= 0) { + + if (afl->chown_needed) { + + if (fchown(fr_fd, -1, afl->fsrv.gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } #endif diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c index 5de4fc7bea..7ed8fd49ac 100644 --- a/src/afl-sharedmem.c +++ b/src/afl-sharedmem.c @@ -142,7 +142,8 @@ void afl_shm_deinit(sharedmem_t *shm) { */ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, - unsigned char non_instrumented_mode) { + unsigned char non_instrumented_mode, mode_t permission, + int gid) { shm->map_size = 0; @@ -181,7 +182,13 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, shm->g_shm_fd = shm_create_largepage(shm->g_shm_file_path, shmflags, i, - SHM_LARGEPAGE_ALLOC_DEFAULT, DEFAULT_PERMISSION); + SHM_LARGEPAGE_ALLOC_DEFAULT, permission); + + if (gid != -1 && shm->g_shm_fd != -1) { + + if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); } + + } } @@ -193,7 +200,13 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, if (shm->g_shm_fd == -1) { shm->g_shm_fd = - shm_open(shm->g_shm_file_path, shmflags | O_CREAT, DEFAULT_PERMISSION); + shm_open(shm->g_shm_file_path, shmflags | O_CREAT, permission); + + if (gid != -1 && shm->g_shm_fd != -1) { + + if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); } + + } } @@ -234,10 +247,14 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, getpid(), random()); /* create the shared memory segment as if it was a file */ - shm->cmplog_g_shm_fd = - shm_open(shm->cmplog_g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, - DEFAULT_PERMISSION); + shm->cmplog_g_shm_fd = shm_open(shm->cmplog_g_shm_file_path, + O_CREAT | O_RDWR | O_EXCL, permission); if (shm->cmplog_g_shm_fd == -1) { PFATAL("shm_open() failed"); } + if (gid != -1) { + + if (fchown(shm->g_shm_fd, -1, gid) == -1) { PFATAL("fchown() failed"); } + + } /* configure the size of the shared memory segment */ if (ftruncate(shm->cmplog_g_shm_fd, sizeof(struct cmp_map))) { @@ -273,23 +290,41 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, } #else - u8 *shm_str; + u8 *shm_str; + struct shmid_ds shmid_ds; // for qemu+unicorn we have to increase by 8 to account for potential // compcov map overwrite shm->shm_id = shmget(IPC_PRIVATE, map_size == MAP_SIZE ? map_size + 8 : map_size, - IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION); + IPC_CREAT | IPC_EXCL | permission); if (shm->shm_id < 0) { PFATAL("shmget() failed, try running afl-system-config"); } + if (gid != -1) { + + if (shmctl(shm->shm_id, IPC_STAT, &shmid_ds) == -1) { + + PFATAL("shmctl(IPC_STAT) failed"); + + } + + shmid_ds.shm_perm.gid = (gid_t)gid; + if (shmctl(shm->shm_id, IPC_SET, &shmid_ds) == -1) { + + PFATAL("shmctl(IPC_SET) failed"); + + } + + } + if (shm->cmplog_mode) { shm->cmplog_shm_id = shmget(IPC_PRIVATE, sizeof(struct cmp_map), - IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION); + IPC_CREAT | IPC_EXCL | permission); if (shm->cmplog_shm_id < 0) { @@ -298,6 +333,23 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, } + if (gid != -1) { + + if (shmctl(shm->cmplog_shm_id, IPC_STAT, &shmid_ds) == -1) { + + PFATAL("shmctl(IPC_STAT) failed"); + + } + + shmid_ds.shm_perm.gid = (gid_t)gid; + if (shmctl(shm->cmplog_shm_id, IPC_SET, &shmid_ds) == -1) { + + PFATAL("shmctl(IPC_SET) failed"); + + } + + } + } if (!non_instrumented_mode) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index bd0594dcd7..a9e084f995 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1348,7 +1348,7 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->target_path = find_binary(argv[optind]); #endif - fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1); if (!quiet_mode) { @@ -1488,7 +1488,8 @@ int main(int argc, char **argv_orig, char **envp) { atexit(at_exit_handler); size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT; - u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1); + u8 *map = afl_shm_init(shm_fuzz, SHM_FUZZ_MAP_SIZE_DEFAULT, 1, + DEFAULT_PERMISSION, -1); shm_fuzz->shmemfuzz_mode = true; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } @@ -1550,7 +1551,8 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_deinit(&shm); afl_fsrv_kill(fsrv); fsrv->map_size = new_map_size; - fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0); + fsrv->trace_bits = + afl_shm_init(&shm, new_map_size, 0, DEFAULT_PERMISSION, -1); } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 60f0c84f5b..57d970a502 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1332,7 +1332,7 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->target_path = find_binary(argv[optind]); #endif - fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, DEFAULT_PERMISSION, -1); detect_file_args(argv + optind, out_file, &fsrv->use_stdin); signal(SIGALRM, kill_child); @@ -1431,7 +1431,8 @@ int main(int argc, char **argv_orig, char **envp) { shm_fuzz->cmplog_mode = 0; size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT; - u8 *map = afl_shm_init(shm_fuzz, shm_fuzz_map_size, 1); + u8 *map = afl_shm_init(shm_fuzz, SHM_FUZZ_MAP_SIZE_DEFAULT, 1, + DEFAULT_PERMISSION, -1); shm_fuzz->shmemfuzz_mode = 1; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } @@ -1502,7 +1503,8 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_deinit(&shm); afl_fsrv_kill(fsrv); fsrv->map_size = new_map_size; - fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0); + fsrv->trace_bits = + afl_shm_init(&shm, new_map_size, 0, DEFAULT_PERMISSION, -1); afl_fsrv_start(fsrv, use_argv, &stop_soon, (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) From ee480aeb7a8bca6fbb50508b777ffc2a8ab88638 Mon Sep 17 00:00:00 2001 From: Justus Perlwitz Date: Tue, 3 Jun 2025 15:39:35 +0900 Subject: [PATCH 04/14] Enable qemu persistent mode tests for mipsel qemuafl now supports persistent mode for *mipsel* targets. This patch changes the `SYS` variable tests and runs the persistent qemu_mode tests for *mipsel* as well. This also adds an optional environment variable called `CPU_TARGET_CC` that you can pass to the `./test-qemu-mode.sh` test script. This allows you to specify a cross-compiler for the target platform. The test script then it uses to compile `test-instr.c` and `test-compcov.c`. Example usage: ``` CPU_TARGET_CC=mipsel-linux-gnu-cc CPU_TARGET=mipsel ./test-qemu-mode.sh ``` The output should look something like this: ``` [*] Using environment variable CPU_TARGET=mipsel for SYS [*] starting AFL++ test framework ... [*] Testing: qemu_mode [*] Using mipsel-linux-gnu-cc as compiler for target [*] running afl-fuzz for qemu_mode, this will take approx 10 seconds [+] afl-fuzz is working correctly with qemu_mode [*] running afl-fuzz for qemu_mode AFL_ENTRYPOINT, this will take approx 6 seconds [+] afl-fuzz is working correctly with qemu_mode AFL_ENTRYPOINT [-] not an intel or arm platform, cannot test qemu_mode compcov [-] not an intel or arm platform, cannot test qemu_mode cmplog [*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds [+] afl-fuzz is working correctly with persistent qemu_mode [+] persistent qemu_mode was noticeable faster than standard qemu_mode [*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds [+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS [+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode [-] we cannot test qemu_mode unsigaction library (32 bit) because it is not present [+] qemu_mode unsigaction library (64 bit) ignores signals [*] 1 test cases completed. [-] not all test cases were executed [+] all tests were successful :-) ``` --- test/test-qemu-mode.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/test-qemu-mode.sh b/test/test-qemu-mode.sh index 00751cedf8..d29a5c4c0d 100755 --- a/test/test-qemu-mode.sh +++ b/test/test-qemu-mode.sh @@ -13,10 +13,16 @@ test -z "$AFL_CC" && { fi } +if test -n "$CPU_TARGET_CC"; then + $ECHO "$GREY[*] Using $CPU_TARGET_CC as compiler for target" +else + CPU_TARGET_CC=cc +fi + test -e ../afl-qemu-trace && { - cc -pie -fPIE -o test-instr ../test-instr.c - cc -o test-compcov test-compcov.c - cc -pie -fPIE -o test-instr-exit-at-end -DEXIT_AT_END ../test-instr.c + ${CPU_TARGET_CC} -pie -fPIE -o test-instr ../test-instr.c + ${CPU_TARGET_CC} -o test-compcov test-compcov.c + ${CPU_TARGET_CC} -pie -fPIE -o test-instr-exit-at-end -DEXIT_AT_END ../test-instr.c test -e test-instr -a -e test-compcov -a -e test-instr-exit-at-end && { { mkdir -p in @@ -105,7 +111,7 @@ test -e ../afl-qemu-trace && { $ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode cmplog" } - test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && { + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" -o "$SYS" = "mipsel" && { $ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds" { IS_STATIC="" @@ -155,7 +161,7 @@ test -e ../afl-qemu-trace && { $ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent qemu_mode" } - test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && { + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" -o "$SYS" = "mipsel" && { $ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds" { IS_STATIC="" From 9951c38515a2f4115a0d5ff8f83abb78d64b886c Mon Sep 17 00:00:00 2001 From: Justus Perlwitz Date: Wed, 4 Jun 2025 10:13:59 +0900 Subject: [PATCH 05/14] Document QEMU persistent hook on mipsel This adds a new persistent hook library `mipsel_read_into_a0.c`. With it, you can test the persistent hook on the *mipsel* architecture. I'm also updating the README in `utils/qemu_persistent_hook` and Makefile and explain how to test the persistent hook on *mipsel*. This all works thanks to qemuafl already having the correct CPU struct for *mipsel* in `qemuafl/api.h`. This patch also updates the root `.gitignore` file to ignore the two test binaries `test` and `mipsel_test`. --- .gitignore | 2 + utils/qemu_persistent_hook/Makefile | 6 +- utils/qemu_persistent_hook/README.md | 117 +++++++++++++++++- .../mipsel_read_into_a0.c | 35 ++++++ 4 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 utils/qemu_persistent_hook/mipsel_read_into_a0.c diff --git a/.gitignore b/.gitignore index 4f25e5e4bb..f641c0be39 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,8 @@ utils/persistent_mode/persistent_demo utils/persistent_mode/persistent_demo_new utils/persistent_mode/persistent_demo_new_compat utils/persistent_mode/test-instr +utils/qemu_persistent_hook/mipsel_test +utils/qemu_persistent_hook/test utils/replay_record/persistent_demo_replay utils/replay_record/persistent_demo_replay_compat utils/replay_record/persistent_demo_replay_argparse diff --git a/utils/qemu_persistent_hook/Makefile b/utils/qemu_persistent_hook/Makefile index 85db1b46a9..a9ac99abe9 100644 --- a/utils/qemu_persistent_hook/Makefile +++ b/utils/qemu_persistent_hook/Makefile @@ -2,5 +2,9 @@ all: $(CC) -no-pie test.c -o test $(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so +all_mipsel: test.c mipsel_read_into_a0.c + $(CPU_TARGET_CC) -no-pie test.c -o mipsel_test + $(CC) -fPIC -shared mipsel_read_into_a0.c -o mipsel_read_into_a0.so + clean: - rm -rf in out test read_into_rdi.so + rm -rf in out test read_into_rdi.so mipsel_test mipsel_read_into_a0.so diff --git a/utils/qemu_persistent_hook/README.md b/utils/qemu_persistent_hook/README.md index 3bbaef6b83..d5d39801d1 100644 --- a/utils/qemu_persistent_hook/README.md +++ b/utils/qemu_persistent_hook/README.md @@ -16,4 +16,119 @@ mkdir in echo 0000 > in/in ../../afl-fuzz -Q -i in -o out -- ./test -``` \ No newline at end of file +``` + +## Example for mipsel architecture + +Compile QEMU with `mipsel` support by running the following: + +```bash +# From root directory +cd qemu_mode && CPU_TARGET=mipsel ./build_qemu_support.sh +``` + +To compile binaries for `mipsel`, you need a GCC cross-compiler for +the target architecture. +How to build a GCC cross-compiler is out of scope for this document, but you +may find this +[OSDev Wiki Tutorial](https://wiki.osdev.org/GCC_Cross-Compiler) helpful. +If you are using Nix, you may find +[this tutorial](https://ayats.org/blog/nix-cross) useful. + +The next step assumes that you have a GCC cross-compiler for `mipsel` available +under `mipsel-gnu-linux-cc`. Verify that `qemu_mode` works properly by running +`test/test-qemu-mode.sh`: + +```bash +# From root directory +cd test +CPU_TARGET_CC=mipsel-linux-gnu-cc CPU_TARGET=mipsel ./test-qemu-mode.sh +``` + +The output should look something like this: + +``` +[*] Using environment variable CPU_TARGET=mipsel for SYS +[*] starting AFL++ test framework ... +[*] Testing: qemu_mode +[*] Using mipsel-linux-gnu-cc as compiler for target +[*] running afl-fuzz for qemu_mode, this will take approx 10 seconds +[+] afl-fuzz is working correctly with qemu_mode +[*] running afl-fuzz for qemu_mode AFL_ENTRYPOINT, this will take approx 6 seconds +[+] afl-fuzz is working correctly with qemu_mode AFL_ENTRYPOINT +[-] not an intel or arm platform, cannot test qemu_mode compcov +[-] not an intel or arm platform, cannot test qemu_mode cmplog +[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds +[+] afl-fuzz is working correctly with persistent qemu_mode +[+] persistent qemu_mode was noticeable faster than standard qemu_mode +[*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds +[+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS +[+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode +[-] we cannot test qemu_mode unsigaction library (32 bit) because it is not present +[+] qemu_mode unsigaction library (64 bit) ignores signals +[*] 1 test cases completed. +[-] not all test cases were executed +[+] all tests were successful :-) +``` + +Then, compile the test binary and library for `mipsel` using the following +`make` command: + +```bash +CPU_TARGET_CC=mipsel-linux-gnu-cc make all_mipsel +``` + +Make sure that the test binary and library have the correct format. When you +run `file` on the two output files, you should see something like the +following: + +``` +$ file mipsel_read_into_a0.so mipsel_test +mipsel_read_into_a0.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, not stripped +mipsel_test: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /nix/store/837z8p51k37n0s1l3hlawx6inc60cq9d-uclibc-ng-mipsel-linux-gnu-1.0.50/lib/ld64-uClibc.so.1, not stripped +``` + +Then, like in the previous section, prepare the fuzzing environment: + +```bash +export AFL_QEMU_PERSISTENT_ADDR=0x$(nm mipsel_test | grep "T target_func" | awk '{print $1}') +export AFL_QEMU_PERSISTENT_HOOK=./mipsel_read_into_a0.so + +mkdir in +echo 0000 > in/in + +# Set the following environment variables to avoid having to adjust +# kernel settings: +export AFL_SKIP_CPUFREQ=1 +export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +``` + +Run the fuzzer using the following command: + +```bash +../../afl-fuzz -V10 -Q -i in -o out -- ./mipsel_test +``` + +If you run the fuzzer with `export AFL_DEBUG=1`, you should see the following +repeating output: + +``` +... +Placing input into 0x410950 +buffer:0x410950, size:1 +Placing input into 0x410950 +buffer:0x410950, size:1 +Placing input into 0x410950 +buffer:0x410950, size:185 +Placing input into 0x410950 +buffer:0x410950, size:5 +Placing input into 0x410950 +buffer:0x410950, size:113 +Placing input into 0x410950 +buffer:0x410950, size:28 +Placing input into 0x410950 +buffer:0x410950, size:78 +Placing input into 0x410950 +buffer:0x410950, size:2 +... +``` diff --git a/utils/qemu_persistent_hook/mipsel_read_into_a0.c b/utils/qemu_persistent_hook/mipsel_read_into_a0.c new file mode 100644 index 0000000000..d64e7710f6 --- /dev/null +++ b/utils/qemu_persistent_hook/mipsel_read_into_a0.c @@ -0,0 +1,35 @@ +#define TARGET_MIPS +#include "../../qemu_mode/qemuafl/qemuafl/api.h" + +#include +#include + +#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) +#define h2g(x) ((uint64_t)(x) - guest_base) + +void afl_persistent_hook(struct mips_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + // In this example the register $a0 is pointing to the memory location + // of the target buffer, and the length of the input is in $a1. + // This can be seen with a debugger, e.g. gdb (and "disass main") + + printf("Placing input into 0x%lx\n", regs->a0); + + if (input_buf_len > 1024) input_buf_len = 1024; + memcpy(g2h(regs->a0), input_buf, input_buf_len); + regs->a1 = input_buf_len; + +} + +#undef g2h +#undef h2g + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + From ad44e30cbfd57969d4aebe69a56d46b9368e12bf Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Fri, 6 Jun 2025 11:25:17 +0200 Subject: [PATCH 06/14] Replace FATAL by WARNF when using another power scheduling with -M --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ae2033492a..07acbbb098 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1502,7 +1502,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->is_main_node == 1 && afl->schedule != FAST && afl->schedule != EXPLORE) { - FATAL("-M is compatible only with fast and explore -p power schedules"); + WARNF("-M is compatible only with fast and explore -p power schedules"); } From 1c7176bd96321db1542c8b122dacd9c274e03562 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Fri, 6 Jun 2025 11:39:02 +0200 Subject: [PATCH 07/14] Better message --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 07acbbb098..725c60c790 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1502,7 +1502,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->is_main_node == 1 && afl->schedule != FAST && afl->schedule != EXPLORE) { - WARNF("-M is compatible only with fast and explore -p power schedules"); + WARNF("When using -M, it is recommended to use only fast or explore -p power schedules"); } From a16bc3f36c7ab9fcd758f22544cf46561402b1f9 Mon Sep 17 00:00:00 2001 From: Sam James Date: Sun, 8 Jun 2025 13:06:54 +0100 Subject: [PATCH 08/14] instrumentation: drop removed TODO flag from GCC plugins TODO_verify_il was removed in GCC trunk by 9739ae9384dd7cd3bb1c7683d6b80b7a9116eaf8, so drop it here. --- instrumentation/afl-gcc-cmplog-pass.so.cc | 3 +-- instrumentation/afl-gcc-cmptrs-pass.so.cc | 3 +-- instrumentation/afl-gcc-pass.so.cc | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/instrumentation/afl-gcc-cmplog-pass.so.cc b/instrumentation/afl-gcc-cmplog-pass.so.cc index 38fce96113..f3906719c9 100644 --- a/instrumentation/afl-gcc-cmplog-pass.so.cc +++ b/instrumentation/afl-gcc-cmplog-pass.so.cc @@ -44,8 +44,7 @@ static const struct pass_data afl_cmplog_pass_data = { .properties_provided = 0, .properties_destroyed = 0, .todo_flags_start = 0, - .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il | - TODO_rebuild_cgraph_edges), + .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges), }; diff --git a/instrumentation/afl-gcc-cmptrs-pass.so.cc b/instrumentation/afl-gcc-cmptrs-pass.so.cc index 360b035a37..94a5599cc8 100644 --- a/instrumentation/afl-gcc-cmptrs-pass.so.cc +++ b/instrumentation/afl-gcc-cmptrs-pass.so.cc @@ -44,8 +44,7 @@ static const struct pass_data afl_cmptrs_pass_data = { .properties_provided = 0, .properties_destroyed = 0, .todo_flags_start = 0, - .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il | - TODO_rebuild_cgraph_edges), + .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges), }; diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index eeef4e02a0..f7ec3df572 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -65,7 +65,6 @@ The new pass is to be a GIMPLE_PASS. Given the sort of instrumentation it's supposed to do, its todo_flags_finish will certainly need TODO_update_ssa, and TODO_cleanup_cfg. - TODO_verify_il is probably desirable, at least during debugging. TODO_rebuild_cgraph_edges is required only in the out-of-line instrumentation mode. @@ -148,7 +147,7 @@ static constexpr struct pass_data afl_pass_data = { .properties_provided = 0, .properties_destroyed = 0, .todo_flags_start = 0, - .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il), + .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg), }; From 7d017f1cb10e52cc208f1ea73d309c7a9411ca34 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Mon, 9 Jun 2025 15:20:20 +0900 Subject: [PATCH 09/14] chore: modify help strings --- utils/autodict_ql/autodict-ql.py | 2 +- utils/autodict_ql/litan.py | 4 ++-- utils/autodict_ql/memcmp-strings.py | 4 ++-- utils/autodict_ql/stan-strings.py | 4 ++-- utils/autodict_ql/strcmp-strings.py | 4 ++-- utils/autodict_ql/strncmp-strings.py | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py index f64e3fae7e..b728084e5a 100644 --- a/utils/autodict_ql/autodict-ql.py +++ b/utils/autodict_ql/autodict-ql.py @@ -33,7 +33,7 @@ def ensure_dir(dir): def parse_args(): parser = argparse.ArgumentParser( description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt" ) ) diff --git a/utils/autodict_ql/litan.py b/utils/autodict_ql/litan.py index 7033d363f9..1c1ce1763a 100644 --- a/utils/autodict_ql/litan.py +++ b/utils/autodict_ql/litan.py @@ -17,7 +17,7 @@ def parse_args(): parser = argparse.ArgumentParser( description=( - "Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python2 thisfile.py outdir o.txt" + "Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python3 thisfile.py outdir o.txt" ) ) parser.add_argument( @@ -25,7 +25,7 @@ def parse_args(): ) parser.add_argument( "infile", - help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt", + help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python3 thisfile.py outdir out.txt", ) return parser.parse_args() diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py index 0b8293ef6f..dd5110ce89 100644 --- a/utils/autodict_ql/memcmp-strings.py +++ b/utils/autodict_ql/memcmp-strings.py @@ -25,7 +25,7 @@ def ensure_dir(dir): def parse_args(): parser = argparse.ArgumentParser( description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt" ) ) parser.add_argument( @@ -33,7 +33,7 @@ def parse_args(): ) parser.add_argument( "infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt", ) return parser.parse_args() diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py index d61dafe728..eccf6eae80 100644 --- a/utils/autodict_ql/stan-strings.py +++ b/utils/autodict_ql/stan-strings.py @@ -25,7 +25,7 @@ def ensure_dir(dir): def parse_args(): parser = argparse.ArgumentParser( description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt" ) ) parser.add_argument( @@ -33,7 +33,7 @@ def parse_args(): ) parser.add_argument( "infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt", ) return parser.parse_args() diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py index 59a2a0f686..bc8ff39fc9 100644 --- a/utils/autodict_ql/strcmp-strings.py +++ b/utils/autodict_ql/strcmp-strings.py @@ -25,7 +25,7 @@ def ensure_dir(dir): def parse_args(): parser = argparse.ArgumentParser( description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt" ) ) parser.add_argument( @@ -33,7 +33,7 @@ def parse_args(): ) parser.add_argument( "infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt", ) return parser.parse_args() diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py index 171dfe7382..e493613fb0 100644 --- a/utils/autodict_ql/strncmp-strings.py +++ b/utils/autodict_ql/strncmp-strings.py @@ -25,7 +25,7 @@ def ensure_dir(dir): def parse_args(): parser = argparse.ArgumentParser( description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python3 thisfile.py outdir str.txt" ) ) parser.add_argument( @@ -33,7 +33,7 @@ def parse_args(): ) parser.add_argument( "infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python3 thisfile.py outdir strings.txt", ) return parser.parse_args() From 0975c8dddefcbdbcabd8a6d1bf74d4a352e600d5 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Mon, 9 Jun 2025 15:18:17 +0900 Subject: [PATCH 10/14] refactor!: drop python2 --- GNUmakefile | 11 ----------- custom_mutators/examples/README.md | 3 +-- custom_mutators/gramatron/build_gramatron_mutator.sh | 2 +- .../grammar_mutator/build_grammar_mutator.sh | 2 +- test/test-unicorn-mode.sh | 2 +- unicorn_mode/build_unicorn_support.sh | 4 ++-- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 73cf6e775f..1997c1bdb5 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -255,17 +255,6 @@ ifeq "$(PYTHON_INCLUDE)" "" endif endif -# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7 -ifeq "$(PYTHON_INCLUDE)" "" - ifneq "$(shell command -v python2.7 2>/dev/null)" "" - ifneq "$(shell command -v python2.7-config 2>/dev/null)" "" - PYTHON_INCLUDE := $(shell python2.7-config --includes) - PYTHON_LIB := $(shell python2.7-config --ldflags) - PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1)) - endif - endif -endif - ifdef SOURCE_DATE_EPOCH BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d") else diff --git a/custom_mutators/examples/README.md b/custom_mutators/examples/README.md index 112db2432a..8c3a1ce4e7 100644 --- a/custom_mutators/examples/README.md +++ b/custom_mutators/examples/README.md @@ -3,8 +3,7 @@ These are example and helper files for the custom mutator feature. See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information -Note that if you compile with python3.7 you must use python3 scripts, and if -you use python2.7 to compile python2 scripts! +Note that if you compile with python3.7 you must use python3 scripts. simple_example.c - most simplest example. generates a random sized buffer filled with 'A' diff --git a/custom_mutators/gramatron/build_gramatron_mutator.sh b/custom_mutators/gramatron/build_gramatron_mutator.sh index f6c53464b2..2635235a3c 100755 --- a/custom_mutators/gramatron/build_gramatron_mutator.sh +++ b/custom_mutators/gramatron/build_gramatron_mutator.sh @@ -56,7 +56,7 @@ if [ ! -f "../../src/afl-performance.o" ]; then fi -PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3` +PYTHONBIN=`command -v python3 || command -v python || echo python3` MAKECMD=make TARCMD=tar diff --git a/custom_mutators/grammar_mutator/build_grammar_mutator.sh b/custom_mutators/grammar_mutator/build_grammar_mutator.sh index 593cd2dc7d..bc7f32bb7a 100755 --- a/custom_mutators/grammar_mutator/build_grammar_mutator.sh +++ b/custom_mutators/grammar_mutator/build_grammar_mutator.sh @@ -52,7 +52,7 @@ if [ ! -f "../../config.h" ]; then fi -PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3` +PYTHONBIN=`command -v python3 || command -v python || echo python3` MAKECMD=make TARCMD=tar diff --git a/test/test-unicorn-mode.sh b/test/test-unicorn-mode.sh index 733d3d19ec..f4f9b13959 100755 --- a/test/test-unicorn-mode.sh +++ b/test/test-unicorn-mode.sh @@ -10,7 +10,7 @@ test -s ../unicorn_mode/unicornafl/build/libunicornafl.a && { export AFL_DEBUG_CHILD=1 # some python version should be available now - PYTHONS="`command -v python3` `command -v python` `command -v python2`" + PYTHONS="`command -v python3` `command -v python`" EASY_INSTALL_FOUND=0 for PYTHON in $PYTHONS ; do diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 1be399ff9a..93090f3da5 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -65,7 +65,7 @@ if [ ! -f "../afl-showmap" ]; then fi -PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3` +PYTHONBIN=`command -v python3 || command -v python || echo python3` MAKECMD=make TARCMD=tar @@ -116,7 +116,7 @@ for i in $PYTHONBIN automake autoconf git $MAKECMD $TARCMD; do done # some python version should be available now -PYTHONS="`command -v python3` `command -v python` `command -v python2`" +PYTHONS="`command -v python3` `command -v python`" PIP_FOUND=0 for PYTHON in $PYTHONS ; do From 00e5449ad6f7ed4ffd62f905722af9862c336e30 Mon Sep 17 00:00:00 2001 From: GRAUX Pierre Date: Mon, 9 Jun 2025 16:33:16 +0200 Subject: [PATCH 11/14] fix and clean UID/GID modification --- src/afl-forkserver.c | 18 ++++++++++++++++++ src/afl-fuzz-init.c | 2 -- utils/afl_network_proxy/afl-network-server.c | 15 +++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a8bb8ca9ab..fb129fa396 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -235,6 +235,24 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { } + if (fsrv->chown_needed && fsrv->out_file != NULL) { + + if (access(fsrv->out_file, R_OK) == -1) { + + if (errno == EACCES) { + + FATAL( + "Access to the file to fuzz denied. Most likely the requested\n" + " UID and/or GID is denied search permission ('x') for one of " + "the directories\n in the path prefix of \"%s\".", + fsrv->out_file); + + } + + } + + } + execv(fsrv->target_path, argv); WARNF("Execv failed in forkserver: %s.", strerror(errno)); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 14f36802ba..9268984ade 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2273,8 +2273,6 @@ void setup_dirs_fds(afl_state_t *afl) { } - printf("out_dir = %s\n", afl->out_dir); - if (mkdir(afl->out_dir, afl->dir_perm)) { if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); } diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c index 19619b5b44..1e692a8153 100644 --- a/utils/afl_network_proxy/afl-network-server.c +++ b/utils/afl_network_proxy/afl-network-server.c @@ -179,7 +179,17 @@ static void set_up_environment(afl_forkserver_t *fsrv) { unlink(out_file); - fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600); + fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, fsrv->perm); + + if (fsrv->chown_needed) { + + if (fchown(fsrv->out_fd, -1, fsrv->gid) == -1) { + + PFATAL("fchown() failed"); + + } + + } if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } @@ -526,7 +536,8 @@ int main(int argc, char **argv_orig, char **envp) { check_environment_vars(envp); sharedmem_t shm = {0}; - fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0, fsrv->perm, + fsrv->chown_needed ? fsrv->gid : -1); in_data = afl_realloc((void **)&in_data, 65536); if (unlikely(!in_data)) { PFATAL("Alloc"); } From 6f381d346bb504bf8cbbdc5c8e944d2b89c259c1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 10 Jun 2025 10:01:29 +0200 Subject: [PATCH 12/14] update Dockerfile to 24.04 --- Dockerfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index ece1239c73..7552c75dd2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it. # -FROM ubuntu:22.04 AS aflplusplus +FROM ubuntu:24.04 AS aflplusplus LABEL "maintainer"="AFL++ team " LABEL "about"="AFLplusplus container image" @@ -17,7 +17,7 @@ ENV NO_NYX=1 ### Only change these if you know what you are doing: # Current recommended LLVM version is 16 -ENV LLVM_VERSION=16 +ENV LLVM_VERSION=19 # GCC 12 is producing compile errors for some targets so we stay at GCC 11 ENV GCC_VERSION=11 @@ -32,8 +32,8 @@ RUN apt-get update && apt-get full-upgrade -y && \ apt-get install -y --no-install-recommends wget ca-certificates apt-utils && \ rm -rf /var/lib/apt/lists/* -RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \ - wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key +#RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \ +# wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key RUN apt-get update && \ apt-get -y install --no-install-recommends \ @@ -65,8 +65,8 @@ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \ update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0 -RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path -ENV PATH=$PATH:/etc/cargo/bin +#RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path +#ENV PATH=$PATH:/etc/cargo/bin RUN apt clean -y From b08f13c9fe027ec39c7d264157490f7eff6ac74b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 10 Jun 2025 10:01:55 +0200 Subject: [PATCH 13/14] code format --- instrumentation/afl-gcc-cmplog-pass.so.cc | 3 ++- instrumentation/afl-gcc-cmptrs-pass.so.cc | 3 ++- src/afl-fuzz.c | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/instrumentation/afl-gcc-cmplog-pass.so.cc b/instrumentation/afl-gcc-cmplog-pass.so.cc index f3906719c9..fe1ccb207c 100644 --- a/instrumentation/afl-gcc-cmplog-pass.so.cc +++ b/instrumentation/afl-gcc-cmplog-pass.so.cc @@ -44,7 +44,8 @@ static const struct pass_data afl_cmplog_pass_data = { .properties_provided = 0, .properties_destroyed = 0, .todo_flags_start = 0, - .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges), + .todo_flags_finish = + (TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges), }; diff --git a/instrumentation/afl-gcc-cmptrs-pass.so.cc b/instrumentation/afl-gcc-cmptrs-pass.so.cc index 94a5599cc8..ba95bb866a 100644 --- a/instrumentation/afl-gcc-cmptrs-pass.so.cc +++ b/instrumentation/afl-gcc-cmptrs-pass.so.cc @@ -44,7 +44,8 @@ static const struct pass_data afl_cmptrs_pass_data = { .properties_provided = 0, .properties_destroyed = 0, .todo_flags_start = 0, - .todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges), + .todo_flags_finish = + (TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges), }; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index fd76c98138..0262efd0ff 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1545,7 +1545,9 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->is_main_node == 1 && afl->schedule != FAST && afl->schedule != EXPLORE) { - WARNF("When using -M, it is recommended to use only fast or explore -p power schedules"); + WARNF( + "When using -M, it is recommended to use only fast or explore -p power " + "schedules"); } From d6f27adcd0e0aad8cbb577422465798ec2971f31 Mon Sep 17 00:00:00 2001 From: "re:fi.64" Date: Thu, 12 Jun 2025 20:25:54 -0500 Subject: [PATCH 14/14] Fix persistent qemu_mode test base address on aarch64 qemu_mode/README.persistent.md documents the different base address, but the test still only had the cases for x86 and x64. --- test/test-qemu-mode.sh | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/test-qemu-mode.sh b/test/test-qemu-mode.sh index d29a5c4c0d..16485043ca 100755 --- a/test/test-qemu-mode.sh +++ b/test/test-qemu-mode.sh @@ -120,11 +120,16 @@ test -e ../afl-qemu-trace && { if file test-instr | grep -q "32-bit"; then # for 32-bit reduce 8 nibbles to the lower 7 nibbles ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.//'` + export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}` + elif [ "$SYS" = "aarch64" ]; then + # for aarch64 reduce 16 nibbles to the lower 8 nibbles + ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^........//'` + export AFL_QEMU_PERSISTENT_ADDR=`expr 0x55${ADDR_LOWER_PART}` else - # for 64-bit reduce 16 nibbles to the lower 9 nibbles + # for x64 reduce 16 nibbles to the lower 9 nibbles ADDR_LOWER_PART=`nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.......//'` + export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}` fi - export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}` } test -n "$IS_STATIC" && { export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr | grep "T main" | awk '{print $1}'` @@ -170,11 +175,16 @@ test -e ../afl-qemu-trace && { if file test-instr-exit-at-end | grep -q "32-bit"; then # for 32-bit reduce 8 nibbles to the lower 7 nibbles ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.//'` + export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}` + elif [ "$SYS" = "aarch64" ]; then + # for aarch64 reduce 16 nibbles to the lower 8 nibbles + ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^........//'` + export AFL_QEMU_PERSISTENT_ADDR=`expr 0x55${ADDR_LOWER_PART}` else - # for 64-bit reduce 16 nibbles to the lower 9 nibbles + # for x64 reduce 16 nibbles to the lower 9 nibbles ADDR_LOWER_PART=`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}' | sed 's/^.......//'` + export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}` fi - export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4${ADDR_LOWER_PART}` } test -n "$IS_STATIC" && { export AFL_QEMU_PERSISTENT_ADDR=0x`nm test-instr-exit-at-end | grep "T main" | awk '{print $1}'`