From aa7cb6a3350e4961ac603e47f7ed61fd99802bf1 Mon Sep 17 00:00:00 2001 From: Samuel Lijin Date: Fri, 25 Oct 2019 00:48:14 -0700 Subject: [PATCH] Fuzz message/stream compression and decompression Google had a company-wide FuzzIt hackathon recently, so I went digging in gRPC and found this, which means I probably don't know what I'm doing :) --- test/core/compression/BUILD | 45 ++++++++++++++ .../compression/message_compress_fuzzer.cc | 58 +++++++++++++++++++ .../compression/message_decompress_fuzzer.cc | 58 +++++++++++++++++++ .../compression/stream_compression_fuzzer.cc | 54 +++++++++++++++++ .../stream_decompression_fuzzer.cc | 55 ++++++++++++++++++ 5 files changed, 270 insertions(+) create mode 100644 test/core/compression/message_compress_fuzzer.cc create mode 100644 test/core/compression/message_decompress_fuzzer.cc create mode 100644 test/core/compression/stream_compression_fuzzer.cc create mode 100644 test/core/compression/stream_decompression_fuzzer.cc diff --git a/test/core/compression/BUILD b/test/core/compression/BUILD index 5fb097519a7..81666f8e556 100644 --- a/test/core/compression/BUILD +++ b/test/core/compression/BUILD @@ -13,6 +13,7 @@ # limitations under the License. load("//bazel:grpc_build_system.bzl", "grpc_cc_binary", "grpc_cc_library", "grpc_cc_test", "grpc_package") +load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") grpc_package(name = "test/core/compression") @@ -42,6 +43,28 @@ grpc_cc_test( ], ) +grpc_fuzzer( + name = "message_compress_fuzzer", + srcs = ["message_compress_fuzzer.cc"], + corpus = "message_compress_corpus", + tags = ["no_windows"], + deps = [ + "//:grpc", + "//test/core/util:grpc_test_util", + ], +) + +grpc_fuzzer( + name = "message_decompress_fuzzer", + srcs = ["message_decompress_fuzzer.cc"], + corpus = "message_decompress_corpus", + tags = ["no_windows"], + deps = [ + "//:grpc", + "//test/core/util:grpc_test_util", + ], +) + grpc_cc_test( name = "message_compress_test", srcs = ["message_compress_test.cc"], @@ -54,6 +77,28 @@ grpc_cc_test( ], ) +grpc_fuzzer( + name = "stream_compression_fuzzer", + srcs = ["stream_compression_fuzzer.cc"], + corpus = "stream_compression_corpus", + tags = ["no_windows"], + deps = [ + "//:grpc", + "//test/core/util:grpc_test_util", + ], +) + +grpc_fuzzer( + name = "stream_decompression_fuzzer", + srcs = ["stream_decompression_fuzzer.cc"], + corpus = "stream_decompression_corpus", + tags = ["no_windows"], + deps = [ + "//:grpc", + "//test/core/util:grpc_test_util", + ], +) + grpc_cc_test( name = "stream_compression_test", srcs = ["stream_compression_test.cc"], diff --git a/test/core/compression/message_compress_fuzzer.cc b/test/core/compression/message_compress_fuzzer.cc new file mode 100644 index 00000000000..1ea0853d2a3 --- /dev/null +++ b/test/core/compression/message_compress_fuzzer.cc @@ -0,0 +1,58 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "src/core/lib/compression/message_compress.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "test/core/util/memory_counters.h" + +bool squelch = true; +bool leak_check = true; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < 1) return 0; + + // Instead of rolling something complicated to convert a uint8_t to the enum, + // just bail out if it isn't trivially convertible. + if (data[0] >= GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT) return 0; + const auto compression_algorithm = + static_cast(data[0]); + + grpc_core::testing::LeakDetector leak_detector(true); + grpc_init(); + grpc_test_only_control_plane_credentials_force_init(); + grpc_slice_buffer input_buffer; + grpc_slice_buffer_init(&input_buffer); + grpc_slice_buffer_add(&input_buffer, + grpc_slice_from_copied_buffer( + reinterpret_cast(data + 1), size - 1)); + grpc_slice_buffer output_buffer; + grpc_slice_buffer_init(&output_buffer); + + grpc_msg_compress(compression_algorithm, &input_buffer, &output_buffer); + + grpc_slice_buffer_destroy(&input_buffer); + grpc_slice_buffer_destroy(&output_buffer); + grpc_test_only_control_plane_credentials_destroy(); + grpc_shutdown_blocking(); + return 0; +} diff --git a/test/core/compression/message_decompress_fuzzer.cc b/test/core/compression/message_decompress_fuzzer.cc new file mode 100644 index 00000000000..c600a740782 --- /dev/null +++ b/test/core/compression/message_decompress_fuzzer.cc @@ -0,0 +1,58 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "src/core/lib/compression/message_compress.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "test/core/util/memory_counters.h" + +bool squelch = true; +bool leak_check = true; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < 1) return 0; + + // Instead of rolling something complicated to convert a uint8_t to the enum, + // just bail out if it isn't trivially convertible. + if (data[0] >= GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT) return 0; + const auto compression_algorithm = + static_cast(data[0]); + + grpc_core::testing::LeakDetector leak_detector(true); + grpc_init(); + grpc_test_only_control_plane_credentials_force_init(); + grpc_slice_buffer input_buffer; + grpc_slice_buffer_init(&input_buffer); + grpc_slice_buffer_add(&input_buffer, + grpc_slice_from_copied_buffer( + reinterpret_cast(data + 1), size - 1)); + grpc_slice_buffer output_buffer; + grpc_slice_buffer_init(&output_buffer); + + grpc_msg_decompress(compression_algorithm, &input_buffer, &output_buffer); + + grpc_slice_buffer_destroy(&input_buffer); + grpc_slice_buffer_destroy(&output_buffer); + grpc_test_only_control_plane_credentials_destroy(); + grpc_shutdown_blocking(); + return 0; +} diff --git a/test/core/compression/stream_compression_fuzzer.cc b/test/core/compression/stream_compression_fuzzer.cc new file mode 100644 index 00000000000..c147aa5bfd6 --- /dev/null +++ b/test/core/compression/stream_compression_fuzzer.cc @@ -0,0 +1,54 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "src/core/lib/compression/stream_compression.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "test/core/util/memory_counters.h" + +bool squelch = true; +bool leak_check = true; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + grpc_core::testing::LeakDetector leak_detector(true); + grpc_init(); + grpc_test_only_control_plane_credentials_force_init(); + auto* context = grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_GZIP_COMPRESS); + grpc_slice_buffer input_buffer; + grpc_slice_buffer_init(&input_buffer); + grpc_slice_buffer_add( + &input_buffer, + grpc_slice_from_copied_buffer(reinterpret_cast(data), size)); + grpc_slice_buffer output_buffer; + grpc_slice_buffer_init(&output_buffer); + + grpc_stream_compress(context, &input_buffer, &output_buffer, nullptr, + SIZE_MAX, GRPC_STREAM_COMPRESSION_FLUSH_SYNC); + + grpc_stream_compression_context_destroy(context); + grpc_slice_buffer_destroy(&input_buffer); + grpc_slice_buffer_destroy(&output_buffer); + grpc_test_only_control_plane_credentials_destroy(); + grpc_shutdown_blocking(); + return 0; +} diff --git a/test/core/compression/stream_decompression_fuzzer.cc b/test/core/compression/stream_decompression_fuzzer.cc new file mode 100644 index 00000000000..e460e6db25f --- /dev/null +++ b/test/core/compression/stream_decompression_fuzzer.cc @@ -0,0 +1,55 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "src/core/lib/compression/stream_compression.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "test/core/util/memory_counters.h" + +bool squelch = true; +bool leak_check = true; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + grpc_core::testing::LeakDetector leak_detector(true); + grpc_init(); + grpc_test_only_control_plane_credentials_force_init(); + auto* context = grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS); + grpc_slice_buffer input_buffer; + grpc_slice_buffer_init(&input_buffer); + grpc_slice_buffer_add( + &input_buffer, + grpc_slice_from_copied_buffer(reinterpret_cast(data), size)); + grpc_slice_buffer output_buffer; + grpc_slice_buffer_init(&output_buffer); + bool end_of_context; + + grpc_stream_decompress(context, &input_buffer, &output_buffer, nullptr, + SIZE_MAX, &end_of_context); + + grpc_stream_compression_context_destroy(context); + grpc_slice_buffer_destroy(&input_buffer); + grpc_slice_buffer_destroy(&output_buffer); + grpc_test_only_control_plane_credentials_destroy(); + grpc_shutdown_blocking(); + return 0; +}