Trouble figuring out fuzzing with AFL

Hello.

I am trying to set up fuzzing for tatfi, and I have been trying to use zig-afl-kit. And it like an obstacle course, every time I figure out something a new error pops up !

This is the build.zig portion

fn set_up_fuzzing(
    b: *std.Build,
    mod: *std.Build.Module,
    target: std.Build.ResolvedTarget,
    optimize: std.builtin.OptimizeMode,
) void {
    const afl = @import("afl_kit");
    const fuzz = b.step("fuzz", "Generate an instrumented executable for AFL++");

    const fuzz_mod = b.createModule(.{
        .root_source_file = b.path("src/fuzz_glyph_index.zig"),
        .target = target,
        .optimize = .Debug,
    });
    fuzz_mod.addImport("tatfi", mod);

    const afl_obj = b.addObject(.{
        .name = "my_fuzz_obj",
        .root_module = fuzz_mod,
    });

    afl_obj.root_module.stack_check = false; // not linking with compiler-rt
    afl_obj.root_module.link_libc = true; // afl runtime depends on libc
    afl_obj.root_module.fuzz = true;

    if (afl.addInstrumentedExe(
        b,
        target,
        optimize,
        &.{"/opt/homebrew/opt/llvm/bin"},
        false,
        afl_obj,
        &.{},
    )) |afl_fuzz| fuzz.dependOn(&b.addInstallBinFile(afl_fuzz, "myfuzz-afl").step);
}

Then I am hit with a giant ball of errors

Build Summary: 55/86 steps succeeded; 12 failed
fuzz transitive failure
└─ install generated to myfuzz-afl transitive failure
   └─ run .zig-cache/i/a3d10ad363c9d634b2e9fcafebef5868/bin/afl-cc (my_fuzz_obj) transitive failure
      └─ llvm_exes transitive failure
         β”œβ”€ install afl-cc transitive failure
         β”‚  └─ llvm_libs transitive failure
         β”‚     β”œβ”€ install afl-llvm-dict2file transitive failure
         β”‚     β”‚  └─ compile lib afl-llvm-dict2file Debug native 2 errors
         β”‚     β”œβ”€ install afl-llvm-pass transitive failure
         β”‚     β”‚  └─ compile lib afl-llvm-pass Debug native 2 errors
         β”‚     β”œβ”€ install cmplog-instructions-pass transitive failure
         β”‚     β”‚  └─ compile lib cmplog-instructions-pass Debug native 2 errors
         β”‚     β”œβ”€ install cmplog-routines-pass transitive failure
         β”‚     β”‚  └─ compile lib cmplog-routines-pass Debug native 2 errors
         β”‚     β”œβ”€ install cmplog-switches-pass transitive failure
         β”‚     β”‚  └─ compile lib cmplog-switches-pass Debug native 2 errors
         β”‚     β”œβ”€ install compare-transform-pass transitive failure
         β”‚     β”‚  └─ compile lib compare-transform-pass Debug native 2 errors
         β”‚     β”œβ”€ install injection-pass transitive failure
         β”‚     β”‚  └─ compile lib injection-pass Debug native 2 errors
         β”‚     β”œβ”€ install SanitizerCoveragePCGUARD transitive failure
         β”‚     β”‚  └─ compile lib SanitizerCoveragePCGUARD Debug native 2 errors
         β”‚     β”œβ”€ install split-compares-pass transitive failure
         β”‚     β”‚  └─ compile lib split-compares-pass Debug native 2 errors
         β”‚     β”œβ”€ install split-switches-pass transitive failure
         β”‚     β”‚  └─ compile lib split-switches-pass Debug native 2 errors
         β”‚     β”œβ”€ install afl-llvm-lto-instrumentlist transitive failure
         β”‚     β”‚  └─ compile lib afl-llvm-lto-instrumentlist Debug native 2 errors
         β”‚     └─ install SanitizerCoverageLTO transitive failure
         β”‚        └─ compile lib SanitizerCoverageLTO Debug native 2 errors
         └─ install afl-ld-lto transitive failure
            └─ llvm_libs (+12 more reused dependencies)

Any ideas on how to proceed? I am on M2 MacBook Air.

this is fuzz_glyph_index.zig file

const std = @import("std");
const ttf = @import("tatfi");

const CHARS: []const u21 = &.{ '\u{0}', 'A', 'Π€', '0', '\u{D7FF}', '\u{10FFFF}' };

export fn zig_fuzz_init() void {}

export fn zig_fuzz_test(buf: [*]u8, len: isize) void {
    const data = buf[0..@intCast(len)];
    const face = ttf.Face.parse(data, 0) catch return;

    // how do i know this doesnt get optimized out?
    for (CHARS) |char|
        _ = face.glyph_index(char);
}

Since you’re building AFL from source (using afl-kit) I have a gut feeling that it could not find all the needed LLVM files despite providing the config path.

This was my problem in fedora 42 where the paths for the expected version were placed somewhere else forcing me to choose a different version.

Try using the system’s AFL or compiling from source your self using their build system. See if you can reproduce the problem. Good luck!

1 Like

Thanks, using a brew installed AFL++ worked. Funnily enough it by its turn fails with new errors due to crash reporting and System Integrity on macOS and other stuff I generally feel uncomfortable doing, so I think I will just skip this round.

I would use zig’d integrated fuzzing utility but there is no way to influence the input as far as I can tell.