From 0c7332b2baf559835d31174ae7dfc452b35d3568 Mon Sep 17 00:00:00 2001 From: Alastair Donaldson Date: Tue, 20 Jul 2021 20:56:30 +0000 Subject: [PATCH] SPIR-V Tools fuzzer: check binary size Adds assertions to check that the SPIR-V Tools fuzzer is not inadvertently applied to SPIR-V binaries of an invalid size, which guards against the fuzzer being run in a misconfigured fashion. The CL also moves a memcpy that populates a SPIR-V binary buffer so that the memcpy only happens when the input really is SPIR-V. This avoids frequent redundant memory copies when fuzzing WGSL. Change-Id: Iafccaa107ff34941d8878ed5be72a2e6d38d0f49 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58386 Auto-Submit: Alastair Donaldson Reviewed-by: Ben Clayton Kokoro: Kokoro Commit-Queue: Alastair Donaldson --- fuzzers/tint_common_fuzzer.cc | 12 +++++++++--- fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc | 9 +++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/fuzzers/tint_common_fuzzer.cc b/fuzzers/tint_common_fuzzer.cc index 153cf8f917..88f0107dcf 100644 --- a/fuzzers/tint_common_fuzzer.cc +++ b/fuzzers/tint_common_fuzzer.cc @@ -187,7 +187,6 @@ int CommonFuzzer::Run(const uint8_t* data, size_t size) { #if TINT_BUILD_SPV_READER std::vector spirv_input(size / sizeof(uint32_t)); - std::memcpy(spirv_input.data(), data, spirv_input.size() * sizeof(uint32_t)); #endif // TINT_BUILD_SPV_READER @@ -202,9 +201,16 @@ int CommonFuzzer::Run(const uint8_t* data, size_t size) { #endif // TINT_BUILD_WGSL_READER #if TINT_BUILD_SPV_READER case InputFormat::kSpv: { - if (!spirv_input.empty()) { - program = reader::spirv::Parse(spirv_input); + // `spirv_input` has been initialized with the capacity to store `size / + // sizeof(uint32_t)` uint32_t values. If `size` is not a multiple of + // sizeof(uint32_t) then not all of `data` can be copied into + // `spirv_input`, and any trailing bytes are discarded. + const size_t adjusted_size = (size / sizeof(uint32_t)) * sizeof(uint32_t); + std::memcpy(spirv_input.data(), data, adjusted_size); + if (spirv_input.empty()) { + return 0; } + program = reader::spirv::Parse(spirv_input); break; } #endif // TINT_BUILD_SPV_READER diff --git a/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc b/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc index c1b3d64017..29af73b16c 100644 --- a/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc +++ b/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -99,6 +100,10 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned seed) { + assert((size % 4) == 0 && + "A valid SPIR-V binary's size must be a multiple of 4, and the " + "SPIR-V Tools fuzzer should only work with valid binaries."); + std::vector binary(size / sizeof(uint32_t)); std::memcpy(binary.data(), data, size); @@ -169,6 +174,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } + assert((size % 4) == 0 && + "A valid SPIR-V binary's size is a multiple of 4 bytes, and the " + "SPIR-V Tools fuzzer should only work with valid binaries."); + CommonFuzzer spv_to_wgsl(InputFormat::kSpv, OutputFormat::kWGSL); spv_to_wgsl.EnableInspector(); spv_to_wgsl.Run(data, size);