From 677f6b90eacbd68a16d312de26303c4eb7355e0f Mon Sep 17 00:00:00 2001 From: Arthur Chan Date: Tue, 27 Oct 2026 08:39:15 +0000 Subject: [PATCH] OSS-Fuzz: Add new fuzzer targets compression Signed-off-by: Arthur Chan --- test/CMakeLists.txt | 2 +- test/fuzzing/fuzz_compress.cpp | 84 ++++++++++++++++++++++++++++++++++ test/fuzzing/oss-fuzz.sh | 2 +- 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 test/fuzzing/fuzz_compress.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d4348027a3..8a202840c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -345,7 +345,7 @@ if(BUILD_FUZZ_TESTS) fuzz_hulu fuzz_json fuzz_redis fuzz_shead fuzz_sofa fuzz_uri fuzz_baidu_rpc fuzz_mongo fuzz_memcache fuzz_couchbase fuzz_streaming fuzz_http_parser fuzz_amf - fuzz_rtmp) + fuzz_rtmp fuzz_compress) foreach(target ${FUZZ_TARGETS}) diff --git a/test/fuzzing/fuzz_compress.cpp b/test/fuzzing/fuzz_compress.cpp new file mode 100644 index 0000000000..e162796601 --- /dev/null +++ b/test/fuzzing/fuzz_compress.cpp @@ -0,0 +1,84 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to You 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. + +// Fuzz brpc's compression policies on the wire direction that servers are +// attacked through: fuzz bytes are compressed with gzip/zlib (both window +// styles) or snappy, and arbitrary fuzz bytes are also fed straight into the +// decompressors (the hostile-compressed-payload model). + +#include "butil/iobuf.h" +#include "brpc/policy/gzip_compress.h" +#include "brpc/policy/snappy_compress.h" + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 5) { + return 0; + } + + const uint8_t mode = data[0] % 5; + butil::IOBuf in; + in.append(data + 1, size - 1); + butil::IOBuf mid; + butil::IOBuf out; + + brpc::policy::GzipCompressOptions opts; + brpc::policy::GzipCompressOptions zlib_opts; + zlib_opts.format = google::protobuf::io::GzipOutputStream::ZLIB; + brpc::policy::GzipCompressOptions fast_opts; + fast_opts.compression_level = 1; + + switch (mode) { + case 0: { + // gzip round-trip + if (brpc::policy::GzipCompress(in, &mid, &opts)) { + brpc::policy::GzipDecompress(mid, &out); + } + break; + } + case 1: { + // zlib round-trip + if (brpc::policy::GzipCompress(in, &mid, &zlib_opts)) { + brpc::policy::ZlibDecompress(mid, &out); + } + break; + } + case 2: { + // gzip with a different compression level + if (brpc::policy::GzipCompress(in, &mid, &fast_opts)) { + brpc::policy::GzipDecompress(mid, &out); + } + break; + } + case 3: { + // snappy round-trip + if (brpc::policy::SnappyCompress(in, &mid)) { + brpc::policy::SnappyDecompress(mid, &out); + } + break; + } + case 4: { + // hostile compressed payload: feed the raw fuzz bytes to every + // decompressor + brpc::policy::GzipDecompress(in, &out); + out.clear(); + brpc::policy::SnappyDecompress(in, &out); + break; + } + } + return 0; +} diff --git a/test/fuzzing/oss-fuzz.sh b/test/fuzzing/oss-fuzz.sh index b6d556d87c..d1c1459fc5 100644 --- a/test/fuzzing/oss-fuzz.sh +++ b/test/fuzzing/oss-fuzz.sh @@ -37,7 +37,7 @@ make \ fuzz_redis fuzz_shead fuzz_sofa fuzz_uri \ fuzz_baidu_rpc fuzz_mongo fuzz_memcache \ fuzz_couchbase fuzz_streaming fuzz_http_parser \ - fuzz_amf fuzz_rtmp --ignore-errors -j$(nproc) + fuzz_amf fuzz_rtmp fuzz_compress --ignore-errors -j$(nproc) cp test/fuzz_* $OUT/