From 37375cb2768d5493f8717c1e34169c59c4c5f008 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 25 May 2022 10:14:44 -0700 Subject: [PATCH] WIP: core helper fuzzer scaffolding Signed-off-by: Dave Thaler Initial chunk of business logic Signed-off-by: Dave Thaler More business logic Signed-off-by: Dave Thaler Add initial helper fuzzer corpus Signed-off-by: Dave Thaler Fix code analysis warning Signed-off-by: Dave Thaler Update docs and CI/CD Signed-off-by: Dave Thaler Update README.md Signed-off-by: Dave Thaler Fix analysis warning Signed-off-by: Dave Thaler Add verifier_fuzzer step to github CI/CD Signed-off-by: Dave Thaler Add core helper and bpf2c fuzzers to CI/CD Signed-off-by: Dave Thaler Fix fuzzers in CI/CD Signed-off-by: Dave Thaler Remove changes for other fuzzers from cicd file Signed-off-by: Dave Thaler Cleanup Signed-off-by: Dave Thaler --- .github/workflows/cicd.yml | 15 +- ebpf-for-windows.sln | 23 + scripts/create_core_helper_corpus.bat | 9 + tests/libfuzzer/README.md | 2 +- .../core_helper_fuzzer.vcxproj | 102 ++++ .../core_helper_fuzzer.vcxproj.filters | 31 ++ .../core_helper_fuzzer/corpus/bpf_csum_diff | 2 + .../corpus/bpf_get_current_pid_tgid | 1 + .../corpus/bpf_get_prandom_u32 | 1 + .../corpus/bpf_get_smp_processor_id | 1 + .../corpus/bpf_ktime_get_boot_ns | 1 + .../corpus/bpf_ktime_get_ns | 1 + .../corpus/bpf_map_delete_elem | Bin 0 -> 6 bytes .../corpus/bpf_map_lookup_and_delete_elem | Bin 0 -> 6 bytes .../corpus/bpf_map_lookup_elem | Bin 0 -> 6 bytes .../corpus/bpf_map_peek_elem | Bin 0 -> 6 bytes .../corpus/bpf_map_pop_elem | 2 + .../corpus/bpf_map_push_elem | Bin 0 -> 14 bytes .../corpus/bpf_map_update_elem | Bin 0 -> 10 bytes .../corpus/bpf_ringbuf_output | 1 + .../core_helper_fuzzer/corpus/bpf_tail_call | Bin 0 -> 9 bytes .../corpus/bpf_trace_printk2 | 1 + .../corpus/bpf_trace_printk3 | 1 + .../corpus/bpf_trace_printk4 | 1 + .../corpus/bpf_trace_printk5 | 1 + .../corpus/bpf_xdp_adjust_head | Bin 0 -> 9 bytes .../core_helper_fuzzer/libfuzz_harness.cpp | 488 ++++++++++++++++++ .../verifier/verifier_fuzzer.vcxproj | 9 + .../verifier/verifier_fuzzer.vcxproj.filters | 5 + 29 files changed, 696 insertions(+), 2 deletions(-) create mode 100644 scripts/create_core_helper_corpus.bat create mode 100644 tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj create mode 100644 tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj.filters create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_csum_diff create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_current_pid_tgid create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_prandom_u32 create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_smp_processor_id create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_boot_ns create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_ns create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_delete_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_lookup_and_delete_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_lookup_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_peek_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_pop_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_push_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_update_elem create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ringbuf_output create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_tail_call create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk2 create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk3 create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk4 create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk5 create mode 100644 tests/libfuzzer/core_helper_fuzzer/corpus/bpf_xdp_adjust_head create mode 100644 tests/libfuzzer/core_helper_fuzzer/libfuzz_harness.cpp diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index a3c637aab1..622ccfc7ba 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -58,7 +58,7 @@ jobs: build_artifact: Build-x64-fuzzer cxx_flags: /fsanitize-coverage=inline-bool-flag /fsanitize-coverage=edge /fsanitize-coverage=trace-cmp /fsanitize-coverage=trace-div /ZH:SHA_256 ld_flags: '"clang_rt.fuzzer_MD-x86_64.lib" "libsancov.lib"' - build_options: /p:Fuzzer='True' /t:tests\libfuzzer\execution_context_fuzzer /t:tests\libfuzzer\bpf2c_fuzzer /t:tests\libfuzzer\verifier_fuzzer + build_options: /p:Fuzzer='True' /t:tests\libfuzzer\execution_context_fuzzer /t:tests\libfuzzer\bpf2c_fuzzer /t:tests\libfuzzer\verifier_fuzzer /t:tests\libfuzzer\core_helper_fuzzer # Run the unit tests in GitHub. unit_tests: @@ -179,6 +179,19 @@ jobs: code_coverage: false gather_dumps: true + core_helper_fuzzer: + needs: libfuzzer + # Always run this job. + if: github.event_name == 'schedule' || github.event_name == 'pull_request' + uses: ./.github/workflows/reusable-test.yml + with: + name: core_helper_fuzzer + test_command: core_helper_fuzzer core_helper_corpus -max_len=139 -runs=2000 -use_value_profile=1 -artifact_prefix=Artifacts\ + build_artifact: Build-x64-fuzzer + environment: windows-2019 + code_coverage: false + gather_dumps: true + # Run Cilium regression tests in GitHub. cilium_tests: needs: regular diff --git a/ebpf-for-windows.sln b/ebpf-for-windows.sln index 02c54a34a2..4e0fa845b1 100644 --- a/ebpf-for-windows.sln +++ b/ebpf-for-windows.sln @@ -160,6 +160,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bpf2c_fuzzer", "tests\libfu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "verifier_fuzzer", "tests\libfuzzer\verifier\verifier_fuzzer.vcxproj", "{DCF12929-B975-4874-A80F-9EAF1CC5A5A0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_helper_fuzzer", "tests\libfuzzer\core_helper_fuzzer\core_helper_fuzzer.vcxproj", "{88A3E85F-669F-4CEA-8207-2E1545528D62}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -1511,6 +1513,26 @@ Global {DCF12929-B975-4874-A80F-9EAF1CC5A5A0}.RelWithDebInfo|x64.Build.0 = Release|x64 {DCF12929-B975-4874-A80F-9EAF1CC5A5A0}.RelWithDebInfo|x86.ActiveCfg = Debug|x64 {DCF12929-B975-4874-A80F-9EAF1CC5A5A0}.RelWithDebInfo|x86.Build.0 = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Debug|ARM.ActiveCfg = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Debug|ARM64.ActiveCfg = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Debug|x64.ActiveCfg = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Debug|x64.Build.0 = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Debug|x86.ActiveCfg = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.MinSizeRel|ARM.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.MinSizeRel|ARM64.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.MinSizeRel|x64.Build.0 = Debug|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.MinSizeRel|x86.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Release|ARM.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Release|ARM64.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Release|x64.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Release|x64.Build.0 = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.Release|x86.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.RelWithDebInfo|ARM.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.RelWithDebInfo|ARM64.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.RelWithDebInfo|x64.Build.0 = Release|x64 + {88A3E85F-669F-4CEA-8207-2E1545528D62}.RelWithDebInfo|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1565,6 +1587,7 @@ Global {6116AE11-5296-4DE9-8A8E-5380B789907E} = {E184CBC2-4B62-499F-8A4A-F15A5A182259} {A0A0D663-DCF7-4BB1-9DDB-7964C3C31603} = {E184CBC2-4B62-499F-8A4A-F15A5A182259} {DCF12929-B975-4874-A80F-9EAF1CC5A5A0} = {E184CBC2-4B62-499F-8A4A-F15A5A182259} + {88A3E85F-669F-4CEA-8207-2E1545528D62} = {E184CBC2-4B62-499F-8A4A-F15A5A182259} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3D5F862D-74C6-4357-9F95-0B152E33B7B8} diff --git a/scripts/create_core_helper_corpus.bat b/scripts/create_core_helper_corpus.bat new file mode 100644 index 0000000000..b1384dbd22 --- /dev/null +++ b/scripts/create_core_helper_corpus.bat @@ -0,0 +1,9 @@ +@echo off +rem Copyright (c) Microsoft Corporation +rem SPDX-License-Identifier: MIT +rem +rem Usage: create_core_helper_corpus.bat + +set SOLUTIONPATH=%1 +set OUTPUTPATH=%2 +xcopy /d /i /y "%SOLUTIONPATH%\tests\libfuzzer\core_helper_fuzzer\corpus" "%OUTPUTPATH%" diff --git a/tests/libfuzzer/README.md b/tests/libfuzzer/README.md index 3f9402b9f9..b46a1146c7 100644 --- a/tests/libfuzzer/README.md +++ b/tests/libfuzzer/README.md @@ -15,7 +15,7 @@ There are now four libFuzzer-based binaries: 1) Copy the libFuzzer binary and existing corpus to a test machine (currently only Windows 10 and Server 2019 are supported). 2) Start the libFuzzer binary, pass the path to the corpus folder, and maximum time to run: * `bpf2c_fuzzer.exe bpf2c_fuzzer_corpus -use_value_profile=1 -max_total_time=1800` - * `core_helper_fuzzer.exe core_helper_fuzzer core_helper_corpus -max_len=139 -runs=3000 -use_value_profile=1` + * `core_helper_fuzzer.exe core_helper_fuzzer core_helper_corpus -max_len=139 -runs=2000 -use_value_profile=1` * `execution_context_fuzzer.exe execution_context_fuzzer_corpus -use_value_profile=1 -max_total_time=1800` * `verifier_fuzzer.exe verifier_corpus -use_value_profile=1 -max_total_time=1800` 3) If the fuzzer hits an issue, it will display the stack trace and create a file containing the input that triggered the crash. diff --git a/tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj b/tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj new file mode 100644 index 0000000000..8389801d78 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj @@ -0,0 +1,102 @@ + + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {88a3e85f-669f-4cea-8207-2e1545528d62} + fuzz2 + 10.0 + core_helper_fuzzer + + + + Application + true + v142 + Unicode + true + + + Application + false + v142 + true + Unicode + true + false + + + + + + + + + + + + + + + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)tests\libfuzzer\include;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;$(SolutionDir)tests\sample;$(SolutionDir)tests\sample\ext\inc;$(SolutionDir)\tests\xdp;$(SolutionDir)tools\encode_program_info;$(SolutionDir)libs\thunk;$(SolutionDir)libs\thunk\mock;$(SolutionDir)\netebpfext;$(SolutionDir)external\catch2\src;$(SolutionDir)external\catch2\build\generated-includes;$(SolutionDir)external\bpftool;%(AdditionalIncludeDirectories) + + + Console + mincore.lib;;%(AdditionalDependencies) + $(VCToolsInstallDir)lib\$(Platform) + + + + + NDEBUG;_CONSOLE;NO_CATCH;%(PreprocessorDefinitions) + $(SolutionDir)tests\libfuzzer\include;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;$(SolutionDir)tests\sample;$(SolutionDir)tests\sample\ext\inc;$(SolutionDir)\tests\xdp;$(SolutionDir)tools\encode_program_info;$(SolutionDir)libs\thunk;$(SolutionDir)libs\thunk\mock;$(SolutionDir)\netebpfext;$(SolutionDir)external\catch2\src;$(SolutionDir)external\catch2\build\generated-includes;$(SolutionDir)external\bpftool;%(AdditionalIncludeDirectories) + + + Console + true + mincore.lib;;%(AdditionalDependencies) + $(VCToolsInstallDir)lib\$(Platform) + + + + + + + + {18127b0d-8381-4afe-9a3a-cf53241992d3} + + + {c26cb6a9-158c-4a9e-a243-755ddd98e5fe} + + + {245f0ec7-1ebc-4d68-8b1f-f758ea9196ae} + + + + + Document + $(OutDir)core_helper_corpus\bpf_tail_call + $(OutDir)core_helper_corpus\bpf_tail_call + $(SolutionDir)scripts\create_core_helper_corpus.bat $(SolutionDir) $(OutDir)core_helper_corpus + $(SolutionDir)scripts\create_core_helper_corpus.bat $(SolutionDir) $(OutDir)core_helper_corpus + + + + + + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj.filters b/tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj.filters new file mode 100644 index 0000000000..73656b2679 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/core_helper_fuzzer.vcxproj.filters @@ -0,0 +1,31 @@ +ο»Ώ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_csum_diff b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_csum_diff new file mode 100644 index 0000000000..a348d6943e --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_csum_diff @@ -0,0 +1,2 @@ + +ͺͺͺͺ»»»»»»»»ΜΜΜΜΜΜΜΜ \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_current_pid_tgid b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_current_pid_tgid new file mode 100644 index 0000000000..54a81dcac6 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_current_pid_tgid @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_prandom_u32 b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_prandom_u32 new file mode 100644 index 0000000000..f8fa5a2354 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_prandom_u32 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_smp_processor_id b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_smp_processor_id new file mode 100644 index 0000000000..5a77f05831 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_get_smp_processor_id @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_boot_ns b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_boot_ns new file mode 100644 index 0000000000..303e398c82 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_boot_ns @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_ns b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_ns new file mode 100644 index 0000000000..501a6bbaf1 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ktime_get_ns @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_delete_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_delete_elem new file mode 100644 index 0000000000000000000000000000000000000000..e5759f2f4aa5946e55c2a592bee45f77dee8d438 GIT binary patch literal 6 LcmZQ(WB>vH0384Y literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_lookup_and_delete_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_lookup_and_delete_elem new file mode 100644 index 0000000000000000000000000000000000000000..187e7df926766a21dc2da3c8c63ba4024031077a GIT binary patch literal 6 NcmZQ!WMp7q0000d00#g7 literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_lookup_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_lookup_elem new file mode 100644 index 0000000000000000000000000000000000000000..52ae05ac17498c5451e7d3da5a0465a74e37fb24 GIT binary patch literal 6 LcmZQ%VgLdF02TlQ literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_peek_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_peek_elem new file mode 100644 index 0000000000000000000000000000000000000000..1faf2d036be1e69c33b3b48ad3de87b7e08bb860 GIT binary patch literal 6 LcmWgQVgLdF0HgpN literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_pop_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_pop_elem new file mode 100644 index 0000000000..964d57c22a --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_pop_elem @@ -0,0 +1,2 @@ + +ͺͺͺͺ \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_push_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_push_elem new file mode 100644 index 0000000000000000000000000000000000000000..d07f3d3ce97cc380a9e1865a5066be14d91b0308 GIT binary patch literal 14 OcmWgOVgQ0wPyhfKSOseU literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_update_elem b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_map_update_elem new file mode 100644 index 0000000000000000000000000000000000000000..4bf898901a8c22d7d124e73f98a17f8da5ae53a9 GIT binary patch literal 10 OcmZQ#WB`IyKmY&+%L1$b literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ringbuf_output b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ringbuf_output new file mode 100644 index 0000000000..2ef545d47f --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_ringbuf_output @@ -0,0 +1 @@ + ͺ»»»» \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_tail_call b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_tail_call new file mode 100644 index 0000000000000000000000000000000000000000..f30386eaabcdb5fee6bf1158f70df6c3175e991a GIT binary patch literal 9 KcmZQ&fC2yjHUI_y literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk2 b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk2 new file mode 100644 index 0000000000..2366e0f6f1 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk2 @@ -0,0 +1 @@ + ͺ \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk3 b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk3 new file mode 100644 index 0000000000..107c7fe19f --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk3 @@ -0,0 +1 @@ + %%%lluͺͺͺͺͺͺͺͺ \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk4 b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk4 new file mode 100644 index 0000000000..99d9c7f4e7 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk4 @@ -0,0 +1 @@ +%%%u%ldͺͺͺͺͺͺͺͺ»»»»»»»» \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk5 b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk5 new file mode 100644 index 0000000000..8b00de145b --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_trace_printk5 @@ -0,0 +1 @@ +%lli%%%lx%dͺͺͺͺͺͺͺͺ»»»»»»»»ΜΜΜΜΜΜΜΜ \ No newline at end of file diff --git a/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_xdp_adjust_head b/tests/libfuzzer/core_helper_fuzzer/corpus/bpf_xdp_adjust_head new file mode 100644 index 0000000000000000000000000000000000000000..d1efa9f696afa2c249858939733240a2a1774fc0 GIT binary patch literal 9 LcmZQzWPktw01*HJ literal 0 HcmV?d00001 diff --git a/tests/libfuzzer/core_helper_fuzzer/libfuzz_harness.cpp b/tests/libfuzzer/core_helper_fuzzer/libfuzz_harness.cpp new file mode 100644 index 0000000000..cac31e7509 --- /dev/null +++ b/tests/libfuzzer/core_helper_fuzzer/libfuzz_harness.cpp @@ -0,0 +1,488 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +#include + +#include +#include +#include +#include + +#define REQUIRE(X) \ + { \ + bool x = (X); \ + UNREFERENCED_PARAMETER(x); \ + } + +#include "ebpf_core.h" +#include "ebpf_handle.h" +#include "ebpf_program.h" +#include "helpers.h" +#include "libfuzzer.h" +#include "platform.h" + +// Currently the only program type with helpers is XDP. Although this test just +// uses the mock helper for XDP, it does result in exercising the core path for +// ids out of range of the core ones. +static std::vector _program_types = {EBPF_PROGRAM_TYPE_XDP}; + +static std::map _map_definitions = { + { + "BPF_MAP_TYPE_HASH", + { + BPF_MAP_TYPE_HASH, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_ARRAY", + { + BPF_MAP_TYPE_ARRAY, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_PROG_ARRAY", + { + BPF_MAP_TYPE_PROG_ARRAY, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_PERCPU_HASH", + { + BPF_MAP_TYPE_PERCPU_HASH, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_PERCPU_ARRAY", + { + BPF_MAP_TYPE_PERCPU_ARRAY, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_HASH_OF_MAPS", + { + BPF_MAP_TYPE_HASH_OF_MAPS, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_ARRAY_OF_MAPS", + { + BPF_MAP_TYPE_ARRAY_OF_MAPS, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_LRU_HASH", + { + BPF_MAP_TYPE_LRU_HASH, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_LPM_TRIE", + { + BPF_MAP_TYPE_LPM_TRIE, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_QUEUE", + { + BPF_MAP_TYPE_QUEUE, + 0, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_LRU_PERCPU_HASH", + { + BPF_MAP_TYPE_LRU_PERCPU_HASH, + 4, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_STACK", + { + BPF_MAP_TYPE_STACK, + 0, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_PERCPU_ARRAY", + { + BPF_MAP_TYPE_PERCPU_ARRAY, + 0, + 4, + 10, + }, + }, + { + "BPF_MAP_TYPE_RINGBUF", + { + BPF_MAP_TYPE_RINGBUF, + 0, + 4, + 64 * 1024, + }, + }, +}; + +void +fuzz_async_completion(void*, size_t, ebpf_result_t){}; + +class fuzz_wrapper +{ + public: + fuzz_wrapper() + { + ebpf_core_initiate(); + const GUID type = EBPF_PROGRAM_TYPE_XDP; + _program_info_provider provider(type); + ebpf_handle_t program_handle; + + std::string program_name = "program name"; + std::string file = "file name"; + std::string section = "section name"; + ebpf_program_parameters_t params{ + type, + type, + {reinterpret_cast(program_name.data()), program_name.size()}, + {reinterpret_cast(file.data()), file.size()}, + {reinterpret_cast(section.data()), section.size()}, + EBPF_CODE_JIT}; + + if (ebpf_program_create_and_initialize(¶ms, &program_handle) == EBPF_SUCCESS) { + handles.push_back(program_handle); + } + for (const auto& [name, def] : _map_definitions) { + ebpf_utf8_string_t utf8_name{reinterpret_cast(const_cast(name.data())), name.size()}; + ebpf_handle_t handle; + if (ebpf_core_create_map(&utf8_name, &def, ebpf_handle_invalid, &handle) == EBPF_SUCCESS) { + handles.push_back(handle); + + ebpf_map_t* map = NULL; + if (ebpf_reference_object_by_handle(handle, EBPF_OBJECT_MAP, (ebpf_core_object_t**)&map) == + EBPF_SUCCESS) { + maps[def.type] = map; + if (def.type == BPF_MAP_TYPE_PROG_ARRAY) { + prog_array_map = map; + } + } + } + } + } + ~fuzz_wrapper() + { + for (auto& [_, map] : maps) { + ebpf_object_release_reference((ebpf_core_object_t*)map); + } + for (auto& handle : handles) { + ebpf_handle_close(handle); + }; + program_information_providers.clear(); + ebpf_core_terminate(); + } + + ebpf_handle_t + get_program_handle() + { + return handles[0]; + } + + _Ret_maybenull_ ebpf_map_t* + get_map(ebpf_map_type_t type) + { + return maps.contains(type) ? maps[type] : nullptr; + } + + _Ret_maybenull_ ebpf_map_t* + get_prog_array_map() + { + return prog_array_map; + } + + private: + std::vector> program_information_providers; + std::vector handles; + std::map maps; + ebpf_map_t* prog_array_map = nullptr; +}; + +_Ret_maybenull_ ebpf_map_definition_in_memory_t* +get_map_definition(ebpf_map_type_t type) +{ + for (auto& [_, m] : _map_definitions) { + if (m.type == type) { + return &m; + } + } + return nullptr; +} + +FUZZ_EXPORT int __cdecl LLVMFuzzerInitialize(int*, char***) { return 0; } + +// Generic helper prototypes. +typedef uint64_t (*function0_t)(); +typedef uint64_t (*function1_t)(uint64_t r1); +typedef uint64_t (*function2_t)(uint64_t r1, uint64_t r2); +typedef uint64_t (*function3_t)(uint64_t r1, uint64_t r2, uint64_t r3); +typedef uint64_t (*function4_t)(uint64_t r1, uint64_t r2, uint64_t r3, uint64_t r4); +typedef uint64_t (*function5_t)(uint64_t r1, uint64_t r2, uint64_t r3, uint64_t r4, uint64_t r5); + +// Consume the next output_size bytes from the input data and save them in the supplied output buffer. +bool +consume_data(const uint8_t** input, size_t* input_size, _Out_writes_(output_size) uint8_t* output, size_t output_size) +{ + if (*input_size < output_size) { + return false; + } + memcpy(output, *input, output_size); + *input += output_size; + *input_size -= output_size; + return true; +} + +// For testing purposes, use up to 64-byte buffers for things like csum diff. +#define MAX_BUFFER_SIZE 64 + +void +fuzz_program( + fuzz_wrapper& fuzz_state, + ebpf_handle_t program_handle, + _In_ ebpf_program_t* program, + _In_reads_(data_left_size) const uint8_t* data_left, + size_t data_left_size) +{ + // Get the set of helper function prototypes. + ebpf_program_info_t* program_info = nullptr; + ebpf_result_t result = ebpf_program_get_program_info(program, &program_info); + if (result != EBPF_SUCCESS) { + return; + } + + // Get helper index. + uint8_t helper_index; + if (!consume_data(&data_left, &data_left_size, &helper_index, sizeof(helper_index)) || + (helper_index >= program_info->count_of_helpers)) { + // No such helper id. + return; + } + ebpf_helper_function_prototype_t* prototype = &program_info->helper_prototype[helper_index]; + + // Get the helper function pointer. + ebpf_helper_id_t helper_function_id = (ebpf_helper_id_t)prototype->helper_id; + uint64_t helper_function_address = 0; + result = + ebpf_core_resolve_helper(program_handle, 1, (const uint32_t*)&helper_function_id, &helper_function_address); + if (result != EBPF_SUCCESS) { + return; + } + + // Declare some memory usable when calling a helper. + uint8_t packet_buffer[MAX_BUFFER_SIZE] = {0}; + std::vector packet{packet_buffer, packet_buffer + sizeof(packet_buffer)}; + xdp_md_helper_t xdp_helper(packet); + char writable_buffer[MAX_BUFFER_SIZE] = {0}; + int readable_buffer_index = 0; + char readable_buffer[2][MAX_BUFFER_SIZE]; + char map_key[MAX_BUFFER_SIZE]; + char map_value[MAX_BUFFER_SIZE]; + ebpf_map_type_t map_type = BPF_MAP_TYPE_UNSPEC; + + // Fill args based on data supplied by the fuzzer. + uint64_t argument[5] = {0}; + int arg_count = 0; + while (arg_count < 5) { + ebpf_argument_type_t type = prototype->arguments[arg_count]; + if (type == EBPF_ARGUMENT_TYPE_DONTCARE) { + break; + } + switch (type) { + case EBPF_ARGUMENT_TYPE_ANYTHING: { + // Fill the argument with supplied data. + if (!consume_data( + &data_left, &data_left_size, (uint8_t*)&argument[arg_count], sizeof(argument[arg_count]))) { + return; + } + break; + } + case EBPF_ARGUMENT_TYPE_CONST_SIZE: { + assert(arg_count > 0); + assert(argument[arg_count - 1] != 0); + if (arg_count == 0 || argument[arg_count - 1] == 0) { + // Should never happen but we need to keep analysis build happy. + return; + } + + // Put the supplied size into the argument. + uint8_t arg_size; + if (!consume_data(&data_left, &data_left_size, (uint8_t*)&arg_size, sizeof(arg_size)) || (arg_size == 0) || + (arg_size > MAX_BUFFER_SIZE)) { + return; + } + argument[arg_count] = arg_size; + + // Put the supplied data into the previous argument. + if (!consume_data(&data_left, &data_left_size, (uint8_t*)argument[arg_count - 1], arg_size)) { + return; + } + break; + } + case EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO: { + assert(arg_count > 0); + assert(argument[arg_count - 1] != 0); + if (arg_count == 0 || argument[arg_count - 1] == 0) { + // Should never happen but we need to keep analysis build happy. + return; + } + + // Put the supplied size into the argument. + uint8_t arg_size; + if (!consume_data(&data_left, &data_left_size, (uint8_t*)&arg_size, sizeof(arg_size)) || + (arg_size > MAX_BUFFER_SIZE)) { + return; + } + argument[arg_count] = arg_size; + if (arg_size == 0) { + // Set the previous argument to NULL. + if (prototype->arguments[arg_count - 1] == EBPF_ARGUMENT_TYPE_PTR_TO_READABLE_MEM_OR_NULL) { + argument[arg_count - 1] = 0; + } + } else { + // Put the supplied data into the previous argument. + if (!consume_data(&data_left, &data_left_size, (uint8_t*)argument[arg_count - 1], arg_size)) { + return; + } + } + break; + } + case EBPF_ARGUMENT_TYPE_PTR_TO_CTX: + // Put the context into the argument. + argument[arg_count] = (uint64_t)&xdp_helper; + break; + case EBPF_ARGUMENT_TYPE_PTR_TO_MAP: { + // Put a map pointer into the argument. + uint8_t index; + if (!consume_data(&data_left, &data_left_size, &index, sizeof(index))) { + return; + } + map_type = (ebpf_map_type_t)index; + argument[arg_count] = (uint64_t)fuzz_state.get_map(map_type); + if (argument[arg_count] == 0) { + return; + } + break; + } + case EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY: { + // Put the supplied data into the argument. + ebpf_map_definition_in_memory_t* definition = get_map_definition(map_type); + if ((definition == nullptr) || + !consume_data(&data_left, &data_left_size, (uint8_t*)&map_key, definition->key_size)) { + return; + } + argument[arg_count] = (uint64_t)map_key; + break; + } + case EBPF_ARGUMENT_TYPE_PTR_TO_MAP_OF_PROGRAMS: + // Put the PROG_ARRAY map pointer into the argument. + argument[arg_count] = (uint64_t)fuzz_state.get_prog_array_map(); + break; + case EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE: { + // Put the supplied data into the argument. + ebpf_map_definition_in_memory_t* definition = get_map_definition(map_type); + if ((definition == nullptr) || + !consume_data(&data_left, &data_left_size, (uint8_t*)&map_value, definition->value_size)) { + return; + } + argument[arg_count] = (uint64_t)map_value; + break; + } + case EBPF_ARGUMENT_TYPE_PTR_TO_READABLE_MEM: + // Put a pointer to the next readable buffer into the argument. + argument[arg_count] = (uint64_t)readable_buffer[readable_buffer_index++]; + break; + case EBPF_ARGUMENT_TYPE_PTR_TO_READABLE_MEM_OR_NULL: + // Put a pointer to the next readable buffer into the argument. + argument[arg_count] = (uint64_t)readable_buffer[readable_buffer_index++]; + break; + case EBPF_ARGUMENT_TYPE_PTR_TO_WRITABLE_MEM: + // Put a pointer to the writable buffer into the argument. + argument[arg_count] = (uint64_t)writable_buffer; + break; + } + arg_count++; + } + if (data_left_size > 0) { + // Fuzzer supplied too much data. + return; + } + + // Call into the helper. + switch (arg_count) { + case 0: + ((function0_t)helper_function_address)(); + break; + case 1: + ((function1_t)helper_function_address)(argument[0]); + break; + case 2: + ((function2_t)helper_function_address)(argument[0], argument[1]); + break; + case 3: + ((function3_t)helper_function_address)(argument[0], argument[1], argument[2]); + break; + case 4: + ((function4_t)helper_function_address)(argument[0], argument[1], argument[2], argument[3]); + break; + case 5: + ((function5_t)helper_function_address)(argument[0], argument[1], argument[2], argument[3], argument[4]); + break; + } +} + +FUZZ_EXPORT int __cdecl LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + // Get the program. + fuzz_wrapper fuzz_state; + ebpf_handle_t program_handle = fuzz_state.get_program_handle(); + ebpf_program_t* program = NULL; + ebpf_result_t result = + ebpf_reference_object_by_handle(program_handle, EBPF_OBJECT_PROGRAM, (ebpf_core_object_t**)&program); + if (result != EBPF_SUCCESS) { + return 0; + } + + fuzz_program(fuzz_state, program_handle, program, data, size); + + ebpf_object_release_reference((ebpf_core_object_t*)program); + + return 0; // Non-zero return values are reserved for future use. +} diff --git a/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj b/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj index 095c64cc72..efd16ef88b 100644 --- a/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj +++ b/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj @@ -110,6 +110,15 @@ {3617528a-cb85-418b-82c1-e9cfc16755f6} + + + Document + $(SolutionDir)scripts\create_verifier_corpus.bat $(SolutionDir) $(OutDir)verifier_corpus + $(SolutionDir)scripts\create_verifier_corpus.bat $(SolutionDir) $(OutDir)verifier_corpus + $(OutDir)verifier_corpus\twomaps.o + $(OutDir)verifier_corpus\twomaps.o + + diff --git a/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj.filters b/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj.filters index 023689b030..abbd81a0ec 100644 --- a/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj.filters +++ b/tests/libfuzzer/verifier/verifier_fuzzer.vcxproj.filters @@ -40,4 +40,9 @@ Header Files + + + Source Files + +