Skip to content

Modify the UID and GIDs of fuzzing target #2462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/env_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
23 changes: 21 additions & 2 deletions include/afl-fuzz.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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) */

Expand Down Expand Up @@ -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)) {
Expand All @@ -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;

}
Expand Down
4 changes: 2 additions & 2 deletions include/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion include/envs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];

Expand Down
10 changes: 10 additions & 0 deletions include/forkserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion include/sharedmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/afl-analyze.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 4 additions & 4 deletions src/afl-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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); }

Expand All @@ -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); }

Expand Down
64 changes: 59 additions & 5 deletions src/afl-forkserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <grp.h>

#ifdef __linux__
#include <dlfcn.h>
Expand Down Expand Up @@ -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));

}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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"); }

}

Expand Down
24 changes: 21 additions & 3 deletions src/afl-fuzz-bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 7 additions & 1 deletion src/afl-fuzz-extras.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy