summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2025-11-17 23:13:49 +0100
committerFlorian Westphal <fw@strlen.de>2025-11-20 22:16:43 +0100
commit32c994f84904e9854d527217ececf0b97d89410d (patch)
treedb2a1a6468fc1cf9c9c15b08f27dccb6074a2d44 /src
parent6cee2d0e7b4dc3274728ae6681d87e356ddcf31a (diff)
src: move fuzzer functionality to separate tool
This means some loss of functionality since you can no longer combine --fuzzer with options like --debug, --define, --include. On the upside, this adds new --random-outflags mode which will randomly switch --terse, --numeric, --echo ... on/off. Update README to reflect this change. Signed-off-by: Florian Westphal <fw@strlen.de> Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/afl++.c219
-rw-r--r--src/main.c97
2 files changed, 0 insertions, 316 deletions
diff --git a/src/afl++.c b/src/afl++.c
deleted file mode 100644
index 79925952..00000000
--- a/src/afl++.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) Red Hat GmbH. Author: Florian Westphal <fw@strlen.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 (or any
- * later) as published by the Free Software Foundation.
- */
-
-#include <nft.h>
-#include <stdio.h>
-
-#include <errno.h>
-#include <ctype.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <time.h>
-
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <afl++.h>
-#include <nftables.h>
-
-static const char self_fault_inject_file[] = "/proc/self/make-it-fail";
-
-#ifdef __AFL_FUZZ_TESTCASE_LEN
-/* the below macro gets passed via afl-cc, declares prototypes
- * depending on the afl-cc flavor.
- */
-__AFL_FUZZ_INIT();
-#else
-/* this lets the source compile without afl-clang-fast/lto */
-static unsigned char fuzz_buf[4096];
-static ssize_t fuzz_len;
-
-#define __AFL_FUZZ_TESTCASE_LEN fuzz_len
-#define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
-#define __AFL_FUZZ_INIT() do { } while (0)
-#define __AFL_LOOP(x) \
- ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
-#endif
-
-struct nft_afl_state {
- FILE *make_it_fail_fp;
-};
-
-static struct nft_afl_state state;
-
-static char *preprocess(unsigned char *input, ssize_t len)
-{
- ssize_t real_len = strnlen((char *)input, len);
-
- if (real_len == 0)
- return NULL;
-
- if (real_len >= len)
- input[len - 1] = 0;
-
- return (char *)input;
-}
-
-static bool kernel_is_tainted(void)
-{
- FILE *fp = fopen("/proc/sys/kernel/tainted", "r");
- unsigned int taint;
- bool ret = false;
-
- if (fp) {
- if (fscanf(fp, "%u", &taint) == 1 && taint) {
- fprintf(stderr, "Kernel is tainted: 0x%x\n", taint);
- sleep(3); /* in case we run under fuzzer, don't restart right away */
- ret = true;
- }
-
- fclose(fp);
- }
-
- return ret;
-}
-
-static void fault_inject_write(FILE *fp, unsigned int v)
-{
- rewind(fp);
- fprintf(fp, "%u\n", v);
- fflush(fp);
-}
-
-static void fault_inject_enable(const struct nft_afl_state *state)
-{
- if (state->make_it_fail_fp)
- fault_inject_write(state->make_it_fail_fp, 1);
-}
-
-static void fault_inject_disable(const struct nft_afl_state *state)
-{
- if (state->make_it_fail_fp)
- fault_inject_write(state->make_it_fail_fp, 0);
-}
-
-static bool nft_afl_run_cmd(struct nft_ctx *ctx, const char *input_cmd)
-{
- if (kernel_is_tainted())
- return false;
-
- switch (ctx->afl_ctx_stage) {
- case NFT_AFL_FUZZER_PARSER:
- case NFT_AFL_FUZZER_EVALUATION:
- case NFT_AFL_FUZZER_NETLINK_RO:
- nft_run_cmd_from_buffer(ctx, input_cmd);
- return true;
- case NFT_AFL_FUZZER_NETLINK_RW:
- break;
- }
-
- fault_inject_enable(&state);
- nft_run_cmd_from_buffer(ctx, input_cmd);
- fault_inject_disable(&state);
-
- return kernel_is_tainted();
-}
-
-static FILE *fault_inject_open(void)
-{
- return fopen(self_fault_inject_file, "r+");
-}
-
-static bool nft_afl_state_init(struct nft_afl_state *state)
-{
- state->make_it_fail_fp = fault_inject_open();
- return true;
-}
-
-int nft_afl_init(struct nft_ctx *ctx, enum nft_afl_fuzzer_stage stage)
-{
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- const char instrumented[] = "afl instrumented";
-#else
- const char instrumented[] = "no afl instrumentation";
-#endif
- nft_afl_print_build_info(stderr);
-
- if (!nft_afl_state_init(&state))
- return -1;
-
- ctx->afl_ctx_stage = stage;
-
- if (state.make_it_fail_fp) {
- unsigned int value;
- int ret;
-
- rewind(state.make_it_fail_fp);
- ret = fscanf(state.make_it_fail_fp, "%u", &value);
- if (ret != 1 || value != 1) {
- fclose(state.make_it_fail_fp);
- state.make_it_fail_fp = NULL;
- }
-
- /* if its enabled, disable and then re-enable ONLY
- * when submitting data to the kernel.
- *
- * Otherwise even libnftables memory allocations could fail
- * which is not what we want.
- */
- fault_inject_disable(&state);
- }
-
- fprintf(stderr, "starting (%s, %s fault injection)", instrumented, state.make_it_fail_fp ? "with" : "no");
- return 0;
-}
-
-int nft_afl_main(struct nft_ctx *ctx)
-{
- unsigned char *buf;
- ssize_t len;
-
- if (kernel_is_tainted())
- return -1;
-
- if (state.make_it_fail_fp) {
- FILE *fp = fault_inject_open();
-
- /* reopen is needed because /proc/self is a symlink, i.e.
- * fp refers to parent process, not "us".
- */
- if (!fp) {
- fprintf(stderr, "Could not reopen %s: %s", self_fault_inject_file, strerror(errno));
- return -1;
- }
-
- fclose(state.make_it_fail_fp);
- state.make_it_fail_fp = fp;
- }
-
- buf = __AFL_FUZZ_TESTCASE_BUF;
-
- while (__AFL_LOOP(UINT_MAX)) {
- char *input;
-
- len = __AFL_FUZZ_TESTCASE_LEN; // do not use the macro directly in a call!
-
- input = preprocess(buf, len);
- if (!input)
- continue;
-
- /* buf is null terminated at this point */
- if (!nft_afl_run_cmd(ctx, input))
- continue;
-
- /* Kernel is tainted.
- * exit() will cause a restart from afl-fuzz.
- * Avoid burning cpu cycles in this case.
- */
- sleep(1);
- }
-
- /* afl-fuzz will restart us. */
- return 0;
-}
diff --git a/src/main.c b/src/main.c
index c2e909d2..29b0533d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -21,7 +21,6 @@
#include <nftables/libnftables.h>
#include <utils.h>
#include <cli.h>
-#include <afl++.h>
static struct nft_ctx *nft;
@@ -87,11 +86,6 @@ enum opt_vals {
OPT_TERSE = 't',
OPT_OPTIMIZE = 'o',
OPT_INVALID = '?',
-
-#if HAVE_FUZZER_BUILD
- /* keep last */
- OPT_FUZZER = 254
-#endif
};
struct nft_opt {
@@ -149,10 +143,6 @@ static const struct nft_opt nft_options[] = {
"Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)"),
[IDX_OPTIMIZE] = NFT_OPT("optimize", OPT_OPTIMIZE, NULL,
"Optimize ruleset"),
-#if HAVE_FUZZER_BUILD
- [IDX_FUZZER] = NFT_OPT("fuzzer", OPT_FUZZER, "stage",
- "fuzzer stage to run (parser, eval, netlink-ro, netlink-rw)"),
-#endif
};
#define NR_NFT_OPTIONS (sizeof(nft_options) / sizeof(nft_options[0]))
@@ -243,7 +233,6 @@ static void show_help(const char *name)
print_option(&nft_options[i]);
fputs("\n", stdout);
- nft_afl_print_build_info(stdout);
}
static void show_version(void)
@@ -286,7 +275,6 @@ static void show_version(void)
PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME,
cli, json, minigmp, xt);
- nft_afl_print_build_info(stdout);
}
static const struct {
@@ -327,38 +315,6 @@ static const struct {
},
};
-#if HAVE_FUZZER_BUILD
-static const struct {
- const char *name;
- enum nft_afl_fuzzer_stage stage;
-} fuzzer_stage_param[] = {
- {
- .name = "parser",
- .stage = NFT_AFL_FUZZER_PARSER,
- },
- {
- .name = "eval",
- .stage = NFT_AFL_FUZZER_EVALUATION,
- },
- {
- .name = "netlink-ro",
- .stage = NFT_AFL_FUZZER_NETLINK_RO,
- },
- {
- .name = "netlink-rw",
- .stage = NFT_AFL_FUZZER_NETLINK_RW,
- },
-};
-static void afl_exit(const char *err)
-{
- fprintf(stderr, "Error: fuzzer: %s\n", err);
- sleep(60); /* assume we're running under afl-fuzz and would be restarted right away */
- exit(EXIT_FAILURE);
-}
-#else
-static inline void afl_exit(const char *err) { }
-#endif
-
static void nft_options_error(int argc, char * const argv[], int pos)
{
int i;
@@ -407,7 +363,6 @@ static bool nft_options_check(int argc, char * const argv[])
int main(int argc, char * const *argv)
{
const struct option *options = get_options();
- enum nft_afl_fuzzer_stage fuzzer_stage = 0;
bool interactive = false, define = false;
const char *optstring = get_optstring();
unsigned int output_flags = 0;
@@ -549,26 +504,6 @@ int main(int argc, char * const *argv)
case OPT_OPTIMIZE:
nft_ctx_set_optimize(nft, 0x1);
break;
-#if HAVE_FUZZER_BUILD
- case OPT_FUZZER:
- {
- unsigned int i;
-
- for (i = 0; i < array_size(fuzzer_stage_param); i++) {
- if (strcmp(fuzzer_stage_param[i].name, optarg))
- continue;
- fuzzer_stage = fuzzer_stage_param[i].stage;
- break;
- }
-
- if (i == array_size(fuzzer_stage_param)) {
- fprintf(stderr, "invalid fuzzer stage `%s'\n",
- optarg);
- goto out_fail;
- }
- }
- break;
-#endif
case OPT_INVALID:
goto out_fail;
}
@@ -581,38 +516,6 @@ int main(int argc, char * const *argv)
nft_ctx_output_set_flags(nft, output_flags);
- if (fuzzer_stage) {
- unsigned int input_flags;
-
- if (filename || define || interactive)
- afl_exit("-D/--define, -f/--filename and -i/--interactive are incompatible options");
-
- rc = nft_afl_init(nft, fuzzer_stage);
- if (rc != 0)
- afl_exit("cannot initialize");
-
- input_flags = nft_ctx_input_get_flags(nft);
-
- /* DNS lookups can result in severe fuzzer slowdown */
- input_flags |= NFT_CTX_INPUT_NO_DNS;
- nft_ctx_input_set_flags(nft, input_flags);
-
- if (fuzzer_stage < NFT_AFL_FUZZER_NETLINK_RW)
- nft_ctx_set_dry_run(nft, true);
-
- fprintf(stderr, "Awaiting fuzzer-generated inputs\n");
- }
-
- __AFL_INIT();
-
- if (fuzzer_stage) {
- rc = nft_afl_main(nft);
- if (rc != 0)
- afl_exit("fatal error");
-
- return EXIT_SUCCESS;
- }
-
if (optind != argc) {
char *buf;