From 12da866a19a201c002a5e2c67f42f208067421aa Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Wed, 24 Jul 2024 16:31:06 +0200 Subject: [PATCH] make tools dependant on llvm optional --- FailStep.zig | 37 ++++++ build.zig | 330 +++++++++++++++++++++++++++++---------------------- 2 files changed, 226 insertions(+), 141 deletions(-) create mode 100644 FailStep.zig diff --git a/FailStep.zig b/FailStep.zig new file mode 100644 index 0000000..0d42702 --- /dev/null +++ b/FailStep.zig @@ -0,0 +1,37 @@ +// This file implements a fail step for the build system +// it's taken from Zig 0.14.0-dev and pasted here to be +// used temporarily while we still target Zig 0.13.0 +const std = @import("std"); +const Step = std.Build.Step; +const Fail = @This(); + +step: Step, +error_msg: []const u8, + +pub const base_id: Step.Id = .custom; + +pub fn create(owner: *std.Build, error_msg: []const u8) *Fail { + const fail = owner.allocator.create(Fail) catch @panic("OOM"); + + fail.* = .{ + .step = Step.init(.{ + .id = base_id, + .name = "fail", + .owner = owner, + .makeFn = make, + }), + .error_msg = owner.dupe(error_msg), + }; + + return fail; +} + +fn make(step: *Step, prog_node: std.Progress.Node) !void { + _ = prog_node; + + const fail: *Fail = @fieldParentPtr("step", step); + + try step.result_error_msgs.append(step.owner.allocator, fail.error_msg); + + return error.MakeFailed; +} diff --git a/build.zig b/build.zig index 0d8a899..44e0f2b 100644 --- a/build.zig +++ b/build.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const FailStep = @import("FailStep.zig"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); @@ -10,18 +11,15 @@ pub fn build(b: *std.Build) !void { // Custom options const use_z = b.option(bool, "use-z", "Use system zlib") orelse true; - const enable_lto = b.option(bool, "enable-lto", "Enable LTO mode") orelse true; - const build_nyx = b.option(bool, "build-nyx", "Build Nyx mode on Linux") orelse true; - const enable_wafl = b.option(bool, "enable-wafl", "Enable WAFL mode on WASI") orelse false; const build_coresight = b.option(bool, "build-coresight", "Build CoreSight mode on ARM64 Linux") orelse true; const build_unicorn_aarch64 = b.option(bool, "build-unicorn-aarch64", "Build Unicorn mode on ARM64") orelse true; + const build_nyx = b.option(bool, "build-nyx", "Build Nyx mode on Linux") orelse true; // Dependencies const AFLplusplus_dep = b.dependency("AFLplusplus", .{}); const AFLplusplus_src_path = AFLplusplus_dep.path("src/"); const AFLplusplus_utl_path = AFLplusplus_dep.path("utils/"); const AFLplusplus_inc_path = AFLplusplus_dep.path("include/"); - const AFLplusplus_ins_path = AFLplusplus_dep.path("instrumentation/"); // Common flags var flags = std.BoundedArray([]const u8, 16){}; @@ -67,10 +65,12 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, }); + sharedmem_obj.addCSourceFile(.{ .file = AFLplusplus_src_path.path(b, "afl-sharedmem.c"), .flags = flags.constSlice(), }); + sharedmem_obj.addIncludePath(AFLplusplus_inc_path); sharedmem_obj.linkLibC(); @@ -88,7 +88,19 @@ pub fn build(b: *std.Build) !void { common_obj.linkLibC(); // Executable suite - const exes_step = b.step("exes", "Install executable suite"); + const exes_step = b.step("exes", "Install fuzzing tools"); + + // LLVM tooling + try setupLLVMTooling( + b, + target, + optimize, + version, + lib_path_flag, + bin_path_flag, + AFLplusplus_dep, + common_obj, + ); const fuzz_exe = b.addExecutable(.{ .name = "afl-fuzz", @@ -128,10 +140,12 @@ pub fn build(b: *std.Build) !void { .files = &.{ "afl-showmap.c", "afl-fuzz-mutators.c", "afl-fuzz-python.c" }, .flags = flags.constSlice(), }); + if (use_z) { showmap_exe.root_module.addCMacro("HAVE_ZLIB", ""); showmap_exe.linkSystemLibrary("z"); } + showmap_exe.addIncludePath(AFLplusplus_inc_path); showmap_exe.addObject(performance_obj); showmap_exe.addObject(forkserver_obj); @@ -153,10 +167,12 @@ pub fn build(b: *std.Build) !void { .file = AFLplusplus_src_path.path(b, "afl-tmin.c"), .flags = flags.constSlice(), }); + if (use_z) { tmin_exe.root_module.addCMacro("HAVE_ZLIB", ""); tmin_exe.linkSystemLibrary("z"); } + tmin_exe.addIncludePath(AFLplusplus_inc_path); tmin_exe.addObject(performance_obj); tmin_exe.addObject(forkserver_obj); @@ -237,15 +253,179 @@ pub fn build(b: *std.Build) !void { b.default_step.dependOn(exes_step); + // Utility library suite + const util_libs_step = b.step("util_libs", "Install utility library suite"); + + if (!target.result.isDarwin()) { + const dislocator_lib = b.addSharedLibrary(.{ + .name = "dislocator", + .pic = true, + .target = target, + .version = version, + .optimize = optimize, + }); + dislocator_lib.addCSourceFile(.{ + .file = AFLplusplus_utl_path.path(b, "libdislocator/libdislocator.so.c"), + .flags = &(UTIL_LIB_FLAGS ++ .{ "-DUSEHUGEPAGE", "-DUSENAMEDPAGE" }), + }); + dislocator_lib.addIncludePath(AFLplusplus_inc_path); + dislocator_lib.linkLibC(); + + const dislocator_lib_install = b.addInstallArtifact(dislocator_lib, .{ .dylib_symlinks = false }); + util_libs_step.dependOn(&dislocator_lib_install.step); + + const tokencap_lib = b.addSharedLibrary(.{ + .name = "tokencap", + .pic = true, + .target = target, + .version = version, + .optimize = optimize, + }); + tokencap_lib.addCSourceFile(.{ + .file = AFLplusplus_utl_path.path(b, "libtokencap/libtokencap.so.c"), + .flags = &UTIL_LIB_FLAGS, + }); + tokencap_lib.addIncludePath(AFLplusplus_inc_path); + tokencap_lib.linkLibC(); + + const tokencap_lib_install = b.addInstallArtifact(tokencap_lib, .{ .dylib_symlinks = false }); + util_libs_step.dependOn(&tokencap_lib_install.step); + + if (build_coresight and target.result.cpu.arch.isAARCH64() and target.result.os.tag == .linux) { + // TODO: CoreSight mode (coresight_mode/GNUmakefile) + } + } + + const socketfuzz_lib = b.addSharedLibrary(.{ + .name = "socketfuzz", + .pic = true, + .target = target, + .version = version, + .optimize = optimize, + }); + socketfuzz_lib.addCSourceFile(.{ + .file = AFLplusplus_utl_path.path(b, "socket_fuzzing/socketfuzz.c"), + .flags = &.{ + if (ptr_bit_width == 32) "-m32" else "-m64", + "-Wall", + "-Wextra", + "-fsanitize=undefined", + "-fsanitize-trap=undefined", + }, + }); + socketfuzz_lib.addIncludePath(AFLplusplus_inc_path); + socketfuzz_lib.linkLibC(); + + const socketfuzz_lib_install = b.addInstallArtifact(socketfuzz_lib, .{ + .dest_sub_path = if (ptr_bit_width == 32) "socketfuzz32.so" else "socketfuzz64.so", + .dylib_symlinks = false, + }); + util_libs_step.dependOn(&socketfuzz_lib_install.step); + + const argvfuzz_lib = b.addSharedLibrary(.{ + .name = "argvfuzz", + .pic = true, + .target = target, + .version = version, + .optimize = optimize, + }); + argvfuzz_lib.addCSourceFile(.{ + .file = AFLplusplus_utl_path.path(b, "argv_fuzzing/argvfuzz.c"), + .flags = &.{ + if (ptr_bit_width == 32) "-m32" else "-m64", + "-Wall", + "-Wextra", + "-fsanitize=undefined", + "-fsanitize-trap=undefined", + }, + }); + argvfuzz_lib.addIncludePath(AFLplusplus_inc_path); + argvfuzz_lib.linkLibC(); + + const argvfuzz_lib_install = b.addInstallArtifact(argvfuzz_lib, .{ + .dest_sub_path = if (ptr_bit_width == 32) "argvfuzz32.so" else "argvfuzz64.so", + .dylib_symlinks = false, + }); + util_libs_step.dependOn(&argvfuzz_lib_install.step); + + // TODO: FRIDA mode (frida_mode/GNUmakefile) + + // TODO: QEMU mode (qemu_mode/build_qemu_support.sh) + + if (build_nyx and target.result.os.tag == .linux) { + // TODO: Nyx mode (nyx_mode/build_nyx_support.sh) + } + + if (build_unicorn_aarch64 or !target.result.cpu.arch.isAARCH64()) { + // TODO: Unicorn mode (unicorn_mode/build_unicorn_support.sh) + } + + b.default_step.dependOn(util_libs_step); + + // Formatting checks + const fmt_step = b.step("fmt", "Run formatting checks"); + + const fmt = b.addFmt(.{ + .paths = &.{ + "build.zig", + }, + .check = true, + }); + fmt_step.dependOn(&fmt.step); + b.default_step.dependOn(fmt_step); +} + +fn setupLLVMTooling( + b: *std.Build, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + version: std.SemanticVersion, + lib_path_flag: []const u8, + bin_path_flag: []const u8, + AFLplusplus_dep: *std.Build.Dependency, + common_obj: *std.Build.Step.Compile, +) !void { + const ptr_bit_width = target.result.ptrBitWidth(); + const AFLplusplus_src_path = AFLplusplus_dep.path("src/"); + const AFLplusplus_inc_path = AFLplusplus_dep.path("include/"); + const AFLplusplus_ins_path = AFLplusplus_dep.path("instrumentation/"); + + const enable_lto = b.option(bool, "enable-lto", "Enable LTO mode") orelse true; + const enable_wafl = b.option(bool, "enable-wafl", "Enable WAFL mode on WASI") orelse false; + + // LLVM instrumentation object suite + const llvm_objs_step = b.step("llvm_objs", "Install LLVM instrumentation object suite, requires LLVM"); + + // LLVM instrumentation library suite + const llvm_libs_step = b.step("llvm_libs", "Install LLVM instrumentation library suite, requires LLVM"); + + // LLVM instrumentation executable suite + const llvm_exes_step = b.step("llvm_exes", "Install LLVM instrumentation executable suite, requires LLVM"); + + const llvm_config_path = b.findProgram( + &.{"llvm-config"}, + b.option([]const []const u8, "llvm-config-path", "Path that contains llvm-config") orelse &.{}, + ) catch { + const fail = FailStep.create( + b, + "Could not find 'llvm-config', which is required to build, set '-Dllvm-config-path' to specify a location not in PATH", + ); + + llvm_objs_step.dependOn(&fail.step); + llvm_libs_step.dependOn(&fail.step); + llvm_exes_step.dependOn(&fail.step); + return; + }; + // LLVM instrumentation C flags var llvm_c_flags = std.BoundedArray([]const u8, 32){}; llvm_c_flags.appendSliceAssumeCapacity(&LLVM_EXE_C_FLAGS); - const llvm_version = std.mem.trimRight(u8, b.run(&.{ "llvm-config", "--version" }), "\n"); + const llvm_version = std.mem.trimRight(u8, b.run(&.{ llvm_config_path, "--version" }), "\n"); var llvm_version_iter = std.mem.tokenizeScalar(u8, llvm_version, '.'); const llvm_major = try std.fmt.parseUnsigned(u8, llvm_version_iter.next().?, 10); const llvm_minor = try std.fmt.parseUnsigned(u8, llvm_version_iter.next().?, 10); - const llvm_bin_dir = std.mem.trimRight(u8, b.run(&.{ "llvm-config", "--bindir" }), "\n"); - const llvm_lib_dir = std.mem.trimRight(u8, b.run(&.{ "llvm-config", "--libdir" }), "\n"); + const llvm_bin_dir = std.mem.trimRight(u8, b.run(&.{ llvm_config_path, "--bindir" }), "\n"); + const llvm_lib_dir = std.mem.trimRight(u8, b.run(&.{ llvm_config_path, "--libdir" }), "\n"); const llvm_lib_path = std.Build.LazyPath{ .cwd_relative = llvm_lib_dir }; llvm_c_flags.appendSliceAssumeCapacity(&.{ lib_path_flag, @@ -278,9 +458,6 @@ pub fn build(b: *std.Build) !void { llvm_cpp_flags.appendSliceAssumeCapacity(&.{ "-DNDEBUG", "-DNO_TLS" }); } - // LLVM instrumentation object suite - const llvm_objs_step = b.step("llvm_objs", "Install LLVM instrumentation object suite"); - inline for (LLVM_OBJ_NAMES) |NAME| { const has_lto = std.mem.endsWith(u8, NAME, "lto"); if (has_lto) { @@ -323,10 +500,7 @@ pub fn build(b: *std.Build) !void { } } - // LLVM instrumentation library suite - const llvm_libs_step = b.step("llvm_libs", "Install LLVM instrumentation library suite"); - - const llvm_inc_dir = std.mem.trimRight(u8, b.run(&.{ "llvm-config", "--includedir" }), "\n"); + const llvm_inc_dir = std.mem.trimRight(u8, b.run(&.{ llvm_config_path, "--includedir" }), "\n"); const llvm_inc_path = std.Build.LazyPath{ .cwd_relative = llvm_inc_dir }; const llvm_name = b.fmt("LLVM-{}", .{llvm_major}); @@ -381,9 +555,6 @@ pub fn build(b: *std.Build) !void { llvm_libs_step.dependOn(&lib_install.step); } - // LLVM instrumentation executable suite - const llvm_exes_step = b.step("llvm_exes", "Install LLVM instrumentation executable suite"); - const dynamic_list_install = b.addInstallFile(AFLplusplus_dep.path("dynamic_list.txt"), "lib/dynamic_list.txt"); const cc_exe = b.addExecutable(.{ @@ -429,129 +600,6 @@ pub fn build(b: *std.Build) !void { ld_lto_exe_install.step.dependOn(llvm_libs_step); llvm_exes_step.dependOn(&ld_lto_exe_install.step); } - - b.default_step.dependOn(llvm_exes_step); - - // Utility library suite - const util_libs_step = b.step("util_libs", "Install utility library suite"); - - if (!target.result.isDarwin()) { - const dislocator_lib = b.addSharedLibrary(.{ - .name = "dislocator", - .pic = true, - .target = target, - .version = version, - .optimize = optimize, - }); - dislocator_lib.addCSourceFile(.{ - .file = AFLplusplus_utl_path.path(b, "libdislocator/libdislocator.so.c"), - .flags = &(UTIL_LIB_FLAGS ++ .{ "-DUSEHUGEPAGE", "-DUSENAMEDPAGE" }), - }); - dislocator_lib.addIncludePath(AFLplusplus_inc_path); - dislocator_lib.linkLibC(); - - const dislocator_lib_install = b.addInstallArtifact(dislocator_lib, .{ .dylib_symlinks = false }); - util_libs_step.dependOn(&dislocator_lib_install.step); - - const tokencap_lib = b.addSharedLibrary(.{ - .name = "tokencap", - .pic = true, - .target = target, - .version = version, - .optimize = optimize, - }); - tokencap_lib.addCSourceFile(.{ - .file = AFLplusplus_utl_path.path(b, "libtokencap/libtokencap.so.c"), - .flags = &UTIL_LIB_FLAGS, - }); - tokencap_lib.addIncludePath(AFLplusplus_inc_path); - tokencap_lib.linkLibC(); - - const tokencap_lib_install = b.addInstallArtifact(tokencap_lib, .{ .dylib_symlinks = false }); - util_libs_step.dependOn(&tokencap_lib_install.step); - - if (build_coresight and target.result.cpu.arch.isAARCH64() and target.result.os.tag == .linux) { - // TODO: CoreSight mode (coresight_mode/GNUmakefile) - } - } - - const socketfuzz_lib = b.addSharedLibrary(.{ - .name = "socketfuzz", - .pic = true, - .target = target, - .version = version, - .optimize = optimize, - }); - socketfuzz_lib.addCSourceFile(.{ - .file = AFLplusplus_utl_path.path(b, "socket_fuzzing/socketfuzz.c"), - .flags = &.{ - if (ptr_bit_width == 32) "-m32" else "-m64", - "-Wall", - "-Wextra", - "-fsanitize=undefined", - "-fsanitize-trap=undefined", - }, - }); - socketfuzz_lib.addIncludePath(AFLplusplus_inc_path); - socketfuzz_lib.linkLibC(); - - const socketfuzz_lib_install = b.addInstallArtifact(socketfuzz_lib, .{ - .dest_sub_path = if (ptr_bit_width == 32) "socketfuzz32.so" else "socketfuzz64.so", - .dylib_symlinks = false, - }); - util_libs_step.dependOn(&socketfuzz_lib_install.step); - - const argvfuzz_lib = b.addSharedLibrary(.{ - .name = "argvfuzz", - .pic = true, - .target = target, - .version = version, - .optimize = optimize, - }); - argvfuzz_lib.addCSourceFile(.{ - .file = AFLplusplus_utl_path.path(b, "argv_fuzzing/argvfuzz.c"), - .flags = &.{ - if (ptr_bit_width == 32) "-m32" else "-m64", - "-Wall", - "-Wextra", - "-fsanitize=undefined", - "-fsanitize-trap=undefined", - }, - }); - argvfuzz_lib.addIncludePath(AFLplusplus_inc_path); - argvfuzz_lib.linkLibC(); - - const argvfuzz_lib_install = b.addInstallArtifact(argvfuzz_lib, .{ - .dest_sub_path = if (ptr_bit_width == 32) "argvfuzz32.so" else "argvfuzz64.so", - .dylib_symlinks = false, - }); - util_libs_step.dependOn(&argvfuzz_lib_install.step); - - // TODO: FRIDA mode (frida_mode/GNUmakefile) - - // TODO: QEMU mode (qemu_mode/build_qemu_support.sh) - - if (build_nyx and target.result.os.tag == .linux) { - // TODO: Nyx mode (nyx_mode/build_nyx_support.sh) - } - - if (build_unicorn_aarch64 or !target.result.cpu.arch.isAARCH64()) { - // TODO: Unicorn mode (unicorn_mode/build_unicorn_support.sh) - } - - b.default_step.dependOn(util_libs_step); - - // Formatting checks - const fmt_step = b.step("fmt", "Run formatting checks"); - - const fmt = b.addFmt(.{ - .paths = &.{ - "build.zig", - }, - .check = true, - }); - fmt_step.dependOn(&fmt.step); - b.default_step.dependOn(fmt_step); } const EXE_FUZZ_SOURCES = .{