From 4aa6a3f8344a450433a21862890e791c76bb464b Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Mon, 25 Aug 2025 02:05:22 -0700 Subject: [PATCH] add fuzzing --- .gitignore | 2 ++ build.zig | 43 ++++++++++++++++++++++++ fuzz/input/input.yml | 31 +++++++++++++++++ fuzz/main.zig | 16 +++++++++ fuzz/yaml.dict | 80 ++++++++++++++++++++++++++++++++++++++++++++ shell.nix | 9 +++++ 6 files changed, 181 insertions(+) create mode 100644 fuzz/input/input.yml create mode 100644 fuzz/main.zig create mode 100644 fuzz/yaml.dict create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore index a6c10d7177d639b8387d322dea2b239d8939242b..269685869a915178123fbfecb6f7e37723e6f7b0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .zigmod zigmod.lock deps.zig +zig-out +fuzz/output diff --git a/build.zig b/build.zig index 886757098a08997338526600f3d375e0df2d9d28..7c2aa07d3d75bfc4985e95775436584f4e4ca2b9 100644 --- a/build.zig +++ b/build.zig @@ -23,4 +23,47 @@ pub fn build(b: *std.Build) void { const tests_run = b.addRunArtifact(tests); tests_run.has_side_effects = true; test_step.dependOn(&tests_run.step); + + // + + const fuzz_exe = addFuzzer(b, target, "yaml", &.{}); + + const fuzz_run = b.addSystemCommand(&.{"afl-fuzz"}); + fuzz_run.step.dependOn(&fuzz_exe.step); + fuzz_run.addArgs(&.{ "-i", "fuzz/input" }); + fuzz_run.addArgs(&.{ "-o", "fuzz/output" }); + fuzz_run.addArgs(&.{ "-x", "fuzz/yaml.dict" }); + fuzz_run.addArg("--"); + fuzz_run.addFileArg(fuzz_exe.source); + + const fuzz_step = b.step("fuzz", "Run AFL++"); + fuzz_step.dependOn(&fuzz_run.step); +} + +fn addFuzzer(b: *std.Build, target: std.Build.ResolvedTarget, comptime name: []const u8, afl_clang_args: []const []const u8) *std.Build.Step.InstallFile { + const fuzz_lib = b.addStaticLibrary(.{ + .name = "fuzz-" ++ name ++ "-lib", + .root_source_file = b.path("fuzz/main.zig"), + .target = target, + .optimize = .Debug, + }); + fuzz_lib.want_lto = true; + fuzz_lib.bundle_compiler_rt = true; + fuzz_lib.use_llvm = true; + fuzz_lib.use_lld = true; + fuzz_lib.root_module.pic = true; + + deps.addAllTo(fuzz_lib); + + const fuzz_executable_name = "fuzz-" ++ name; + + const fuzz_compile = b.addSystemCommand(&.{ "afl-clang-lto", "-v", "-o" }); + const output_path = fuzz_compile.addOutputFileArg(fuzz_executable_name); + fuzz_compile.addArtifactArg(fuzz_lib); + fuzz_compile.addArgs(afl_clang_args); + + const fuzz_install = b.addInstallBinFile(output_path, fuzz_executable_name); + fuzz_install.step.dependOn(&fuzz_compile.step); + + return fuzz_install; } diff --git a/fuzz/input/input.yml b/fuzz/input/input.yml new file mode 100644 index 0000000000000000000000000000000000000000..99f39ec77cf268d2d064dfe895b83f096f9bbd45 --- /dev/null +++ b/fuzz/input/input.yml @@ -0,0 +1,31 @@ +id: g982zq6e8wsvnmduerpbf8787hu85brugmngn8wf +name: yaml +main: yaml.zig +license: MIT +description: A Yaml parser built on top of libyaml +dependencies: + - src: git https://github.com/yaml/libyaml tag-0.2.5 + id: 8mdbh0zuneb0i3hs5jby5je0heem1i6yxusl7c8y8qx68hqc + license: MIT + c_include_dirs: + - include + c_source_flags: + - -DYAML_VERSION_MAJOR=0 + - -DYAML_VERSION_MINOR=2 + - -DYAML_VERSION_PATCH=5 + - -DYAML_VERSION_STRING="0.2.5" + - -DYAML_DECLARE_STATIC=1 + c_source_files: + - src/api.c + - src/dumper.c + - src/emitter.c + - src/loader.c + - src/parser.c + - src/reader.c + - src/scanner.c + - src/writer.c + + - src: git https://github.com/nektro/zig-extras + +root_dependencies: + - src: git https://github.com/nektro/zig-expect diff --git a/fuzz/main.zig b/fuzz/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..8ae5f4c60f04a23305d10892854299414325fac7 --- /dev/null +++ b/fuzz/main.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const yaml = @import("yaml"); +const nfs = @import("nfs"); + +pub export fn main() void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer std.debug.assert(gpa.deinit() == .ok); + const allocator = gpa.allocator(); + + const stdin = nfs.stdin(); + const input = stdin.readToEndAlloc(allocator, 1024 * 1024, null) catch @panic("too big"); + defer allocator.free(input); + + const doc = yaml.parse(allocator, input) catch return; + defer doc.deinit(allocator); +} diff --git a/fuzz/yaml.dict b/fuzz/yaml.dict new file mode 100644 index 0000000000000000000000000000000000000000..442ac7f39d60f55c9419beb4f06943e567f13966 --- /dev/null +++ b/fuzz/yaml.dict @@ -0,0 +1,80 @@ +# https://github.com/AFLplusplus/AFLplusplus/blob/stable/dictionaries/yaml.dict +# sources: +# - https://en.wikipedia.org/wiki/YAML +# - https://yaml.org/spec/1.1/ +# - https://yaml.org/type/ + +directive_yaml="%YAML 1.2" +directive_tag="%TAG !yaml! tag:yaml.org,2002:" +directive_tag2="%TAG !m! !my-" +true="true" +caps_true="TRUE" +caps_false="FALSE" +literal_true="YES" +literal_false="NO" +false="false" +start="---" +comment="#" +list="- " +key="k: " +walrus="=:" +question_key="?k: " +number="\"0e5\"" +expand="!!" +list="[a,b]" +dict="{k: v, x: y}" +value=": v" +exponent="e+03" +neg_inf="-.inf" +nan=".NaN" +end="..." +quoted_key="'k'" +newline="k: |" +newline2="k: >" +anchor="&a" +reference="*a" +type_binary="!!binary" +type_bool="!!bool" +type_float="!!float" +type_int="!!int" +type_map="!!map" +type_merge="!!merge" +type_null="!!null" +type_omap="!!omap" +type_pairs="!!pairs" +type_seq="!!seq" +type_set="!!set" +type_str="!!str" +type_timestamp="!!timestamp" +type_value="!!value" +type_yaml="!!yaml" +type_python="!!python" +merge = "<<" +number_separation="_" +decimal_number="+30_123" +octal_number="0123" +hex_number="0x_12_23" +bin_number="0b1001_1001" +sexa_number="123:34:75" +complex_mapping="? " +litteral_style=" |" +folded_style=" >" +timestamp="2001-12-14t21:59:43.10-05:00" +escaped_unicode="\\u2029" +"[" +"]" +"{" +"}" +"-" +"," +"&" +"<<" +":" +"|" +"!!" +">" +"\"" +"'" +integer="123" +float="12.5" +mantissa="1.3e+9" diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000000000000000000000000000000000..31a182f82828bd1762e1b12eacaf09bb2fa4dfa9 --- /dev/null +++ b/shell.nix @@ -0,0 +1,9 @@ +with import {}; + +pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + aflplusplus + ]; + + hardeningDisable = [ "all" ]; +} -- 2.54.0