From cd0cb1e731abc5f0148eadbaff460937b8e09e35 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Sun, 4 May 2025 11:36:01 +0200 Subject: [PATCH 1/9] Setting the AFL_I_AM_THE_FORKSERVER environment variable in the begining of the forkserver child process, and unsetting it when the target is launched --- instrumentation/afl-compiler-rt.o.c | 1 + src/afl-forkserver.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index cba6436f..33899c84 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1046,6 +1046,7 @@ static void __afl_start_forkserver(void) { /* In child process: close fds, resume execution. */ if (unlikely(!child_pid)) { // just to signal afl-fuzz faster + unsetenv("AFL_I_AM_THE_FORKSERVER"); //(void)nice(-20); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3fc86b3b..17685529 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -878,6 +878,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* CHILD PROCESS */ + setenv("AFL_I_AM_THE_FORKSERVER", "1", 0); + // enable terminating on sigpipe in the children struct sigaction sa; memset((char *)&sa, 0, sizeof(sa)); From 6f4767ea8155ab20e49d1fa341dea9a724fd0407 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 09:42:33 +0200 Subject: [PATCH 2/9] AFL_I_AM_THE_FORKSERVER becomes AFL_FORKSERVER_PARENT --- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-forkserver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 33899c84..46d76624 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1046,7 +1046,7 @@ static void __afl_start_forkserver(void) { /* In child process: close fds, resume execution. */ if (unlikely(!child_pid)) { // just to signal afl-fuzz faster - unsetenv("AFL_I_AM_THE_FORKSERVER"); + unsetenv("AFL_FORKSERVER_PARENT"); //(void)nice(-20); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 17685529..0a1bd75f 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -878,7 +878,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* CHILD PROCESS */ - setenv("AFL_I_AM_THE_FORKSERVER", "1", 0); + setenv("AFL_FORKSERVER_PARENT", "1", 0); // enable terminating on sigpipe in the children struct sigaction sa; From e9f49527e912eb81e9e3c0a1b32c703f858cecda Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 09:49:56 +0200 Subject: [PATCH 3/9] We check before if the AFL_PRELOAD env variable is set --- instrumentation/afl-compiler-rt.o.c | 6 +++++- src/afl-forkserver.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 46d76624..2a563afc 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1046,7 +1046,11 @@ static void __afl_start_forkserver(void) { /* In child process: close fds, resume execution. */ if (unlikely(!child_pid)) { // just to signal afl-fuzz faster - unsetenv("AFL_FORKSERVER_PARENT"); + if (unlikely(getenv("AFL_PRELOAD") != NULL)) { + + unsetenv("AFL_FORKSERVER_PARENT"); + + } //(void)nice(-20); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 0a1bd75f..d289ce8e 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -878,7 +878,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* CHILD PROCESS */ - setenv("AFL_FORKSERVER_PARENT", "1", 0); + if (unlikely(getenv("AFL_PRELOAD") != NULL)) { + + setenv("AFL_FORKSERVER_PARENT", "1", 0); + + } // enable terminating on sigpipe in the children struct sigaction sa; From a76ff5e79835210516d7b3dbaf650e6db86ce80e Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 09:54:53 +0200 Subject: [PATCH 4/9] Specific environment variable to choose if we want to be able to discriminate or not forkserver in preloaded libraries --- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-forkserver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 2a563afc..8dfdc61c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1046,7 +1046,7 @@ static void __afl_start_forkserver(void) { /* In child process: close fds, resume execution. */ if (unlikely(!child_pid)) { // just to signal afl-fuzz faster - if (unlikely(getenv("AFL_PRELOAD") != NULL)) { + if (unlikely(getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL)) { unsetenv("AFL_FORKSERVER_PARENT"); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d289ce8e..b5e1476d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -878,7 +878,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* CHILD PROCESS */ - if (unlikely(getenv("AFL_PRELOAD") != NULL)) { + if (unlikely(getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); From 4d984d6e2b00f76406afea3b50fd5a06e25c8488 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 10:44:34 +0200 Subject: [PATCH 5/9] getenv() call at the beginning of __afl_start_forkserver() --- instrumentation/afl-compiler-rt.o.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 8dfdc61c..18c776e2 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -119,6 +119,8 @@ u64 __afl_map_addr; u32 __afl_first_final_loc; u32 __afl_old_forkserver; +u8 __afl_forkserver_setenv = 0; + #ifdef __AFL_CODE_COVERAGE typedef struct afl_module_info_t afl_module_info_t; @@ -888,6 +890,12 @@ static void __afl_start_forkserver(void) { } + if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) { + + __afl_forkserver_setenv = 1; + + } + /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ @@ -1046,7 +1054,7 @@ static void __afl_start_forkserver(void) { /* In child process: close fds, resume execution. */ if (unlikely(!child_pid)) { // just to signal afl-fuzz faster - if (unlikely(getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL)) { + if (unlikely(__afl_forkserver_setenv)) { unsetenv("AFL_FORKSERVER_PARENT"); From 7d29418db5b4a7c34039d3cc7f5a9641c0ef1d70 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 10:50:13 +0200 Subject: [PATCH 6/9] Auxiliary variable for afl-forkserver.c too --- src/afl-forkserver.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index b5e1476d..c2bf3fcf 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -561,6 +561,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u32 status; s32 rlen; char *ignore_autodict = getenv("AFL_NO_AUTODICT"); + u8 forkserver_setenv = 0; #ifdef __linux__ if (unlikely(fsrv->nyx_mode)) { @@ -867,6 +868,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } + if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) + { + forkserver_setenv = 1; + } + if (pipe(st_pipe) || pipe(ctl_pipe)) { PFATAL("pipe() failed"); } fsrv->last_run_timed_out = 0; @@ -878,7 +884,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* CHILD PROCESS */ - if (unlikely(getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL)) { + if (unlikely(forkserver_setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); From 19bd2984d52acbb985176df15c28df1cffc8efac Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 10:52:27 +0200 Subject: [PATCH 7/9] Writing style mistaske --- src/afl-forkserver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index c2bf3fcf..4265325e 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -868,9 +868,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) - { + if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) { + forkserver_setenv = 1; + } if (pipe(st_pipe) || pipe(ctl_pipe)) { PFATAL("pipe() failed"); } From 320d4b7ef86a03680eb4c659f00132dd4034f417 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 11:03:26 +0200 Subject: [PATCH 8/9] Requested changes --- include/forkserver.h | 2 ++ instrumentation/afl-compiler-rt.o.c | 12 +++++++----- src/afl-forkserver.c | 19 +++++++++++-------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/include/forkserver.h b/include/forkserver.h index 4f574aa1..db3bfcb3 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -159,6 +159,8 @@ typedef struct afl_forkserver { u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */ + bool setenv; /* setenv() to discriminate the forkserver? */ + bool debug; /* debug mode? */ u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented? diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 18c776e2..24d2ed9e 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1054,11 +1054,6 @@ static void __afl_start_forkserver(void) { /* In child process: close fds, resume execution. */ if (unlikely(!child_pid)) { // just to signal afl-fuzz faster - if (unlikely(__afl_forkserver_setenv)) { - - unsetenv("AFL_FORKSERVER_PARENT"); - - } //(void)nice(-20); @@ -1067,6 +1062,13 @@ static void __afl_start_forkserver(void) { close(FORKSRV_FD); close(FORKSRV_FD + 1); + + if (unlikely(__afl_forkserver_setenv)) { + + unsetenv("AFL_FORKSERVER_PARENT"); + + } + return; } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 4265325e..3eadedf1 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -250,6 +250,16 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->child_kill_signal = SIGKILL; fsrv->max_length = MAX_FILE; + if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) { + + fsrv->setenv = 1; + + } else { + + fsrv->setenv = 0; + + } + /* exec related stuff */ fsrv->child_pid = -1; fsrv->map_size = get_map_size(); @@ -561,7 +571,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u32 status; s32 rlen; char *ignore_autodict = getenv("AFL_NO_AUTODICT"); - u8 forkserver_setenv = 0; #ifdef __linux__ if (unlikely(fsrv->nyx_mode)) { @@ -868,12 +877,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) { - - forkserver_setenv = 1; - - } - if (pipe(st_pipe) || pipe(ctl_pipe)) { PFATAL("pipe() failed"); } fsrv->last_run_timed_out = 0; @@ -885,7 +888,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* CHILD PROCESS */ - if (unlikely(forkserver_setenv)) { + if (unlikely(fsrv->setenv)) { setenv("AFL_FORKSERVER_PARENT", "1", 0); From f580fefc5ff61b0fbe267a4715d79b5526c677c6 Mon Sep 17 00:00:00 2001 From: Alexandre DOYEN Date: Mon, 5 May 2025 11:12:51 +0200 Subject: [PATCH 9/9] Doc --- docs/env_variables.md | 18 ++++++++++++++++++ include/envs.h | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/env_variables.md b/docs/env_variables.md index ed44c256..3052663a 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -664,6 +664,24 @@ checks or alter some of the more exotic semantics of the tool: Note that will not be exact and with slow targets it can take seconds until there is a slice for the time test. + - When using `AFL_PRELOAD` with a preload that disable `fork()` calls in + the target, the forkserver becomes unable to fork. + To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT` + permits to be able to check in the preloaded library if the environment + variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla + `fork()` in the forkserver, and the placeholder in the target. + Here is a POC : + ```C + // AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ... + pid_t fork(void) + { + if (getenv("AFL_FORKSERVER_PARENT") == NULL) + return 0; // We are in the target + else + return real_fork(); // We are in the forkserver + } + ``` + ## 6) Settings for afl-qemu-trace The QEMU wrapper used to instrument binary-only code supports several settings: diff --git a/include/envs.h b/include/envs.h index 7913e6b9..433b51a5 100644 --- a/include/envs.h +++ b/include/envs.h @@ -118,7 +118,8 @@ static char *afl_environment_variables[] = { "AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN", "AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME", - "AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", NULL}; + "AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", + "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", NULL}; extern char *afl_environment_variables[];