diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a478e8cc89..ade7350f5a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -275,7 +275,10 @@ if(BUILD_FUZZ_TESTS) endif() set(FUZZ_TARGETS fuzz_butil fuzz_esp fuzz_hpack fuzz_http - fuzz_hulu fuzz_json fuzz_redis fuzz_shead fuzz_sofa fuzz_uri) + 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) + foreach(target ${FUZZ_TARGETS}) add_executable(${target} fuzzing/${target}.cpp $) diff --git a/test/fuzzing/fuzz_amf.cpp b/test/fuzzing/fuzz_amf.cpp new file mode 100644 index 0000000000..60628ad124 --- /dev/null +++ b/test/fuzzing/fuzz_amf.cpp @@ -0,0 +1,81 @@ +// 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. + +#include "brpc/amf.h" +#include "butil/iobuf.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + uint8_t mode = data[0] % 3; + const uint8_t *payload = data + 1; + size_t payload_size = size - 1; + + butil::IOBuf buf; + buf.append(payload, payload_size); + + switch (mode) { + case 0: { + // Read AMF object + butil::IOBufAsZeroCopyInputStream zc_stream(buf); + brpc::AMFInputStream stream(&zc_stream); + brpc::AMFObject obj; + brpc::ReadAMFObject(&obj, &stream); + break; + } + case 1: { + // Read AMF string + butil::IOBufAsZeroCopyInputStream zc_stream(buf); + brpc::AMFInputStream stream(&zc_stream); + std::string val; + brpc::ReadAMFString(&val, &stream); + break; + } + case 2: { + // Read raw AMF fields by consuming the stream directly + butil::IOBufAsZeroCopyInputStream zc_stream(buf); + brpc::AMFInputStream stream(&zc_stream); + uint8_t marker; + while (stream.good() && stream.cut_u8(&marker) == 1) { + // Try to identify marker type and read value + if (marker == brpc::AMF_MARKER_NUMBER) { + uint64_t num; + stream.cut_u64(&num); + } else if (marker == brpc::AMF_MARKER_BOOLEAN) { + uint8_t b; + stream.cut_u8(&b); + } else if (marker == brpc::AMF_MARKER_STRING) { + uint16_t len; + if (stream.cut_u16(&len) == 2 && len < 1024) { + char tmp[1024]; + stream.cutn(tmp, len); + } + } + } + break; + } + } + + return 0; +} diff --git a/test/fuzzing/fuzz_baidu_rpc.cpp b/test/fuzzing/fuzz_baidu_rpc.cpp new file mode 100644 index 0000000000..027dbbcb47 --- /dev/null +++ b/test/fuzzing/fuzz_baidu_rpc.cpp @@ -0,0 +1,38 @@ +// 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. + +#include "brpc/policy/baidu_rpc_protocol.h" +#include "fuzz_common.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + std::string input(reinterpret_cast(data), size); + butil::IOBuf buf; + buf.append(input); + + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseRpcMessage(&buf, sock, false, NULL); + return 0; +} diff --git a/test/fuzzing/fuzz_common.h b/test/fuzzing/fuzz_common.h new file mode 100644 index 0000000000..1ab6bf3b4b --- /dev/null +++ b/test/fuzzing/fuzz_common.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef BRPC_TEST_FUZZING_FUZZ_COMMON_H +#define BRPC_TEST_FUZZING_FUZZ_COMMON_H + +#include "brpc/socket.h" +#include "butil/endpoint.h" + +// Create a valid Socket for use in fuzz harnesses that need a non-NULL Socket*. +// Returns a raw Socket* that remains valid for the lifetime of the process +// (held by the static SocketUniquePtr). +inline brpc::Socket* get_fuzz_socket() { + static brpc::SocketId sid = 0; + static brpc::SocketUniquePtr sock_ptr; + static bool initialized = false; + + if (!initialized) { + brpc::SocketOptions options; + options.remote_side = butil::EndPoint(butil::IP_ANY, 7777); + if (brpc::Socket::Create(options, &sid) == 0) { + brpc::Socket::Address(sid, &sock_ptr); + } + initialized = true; + } + + return sock_ptr.get(); +} + +#endif // BRPC_TEST_FUZZING_FUZZ_COMMON_H diff --git a/test/fuzzing/fuzz_couchbase.cpp b/test/fuzzing/fuzz_couchbase.cpp new file mode 100644 index 0000000000..11eee84adb --- /dev/null +++ b/test/fuzzing/fuzz_couchbase.cpp @@ -0,0 +1,38 @@ +// 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. + +#include "brpc/policy/couchbase_protocol.h" +#include "fuzz_common.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + std::string input(reinterpret_cast(data), size); + butil::IOBuf buf; + buf.append(input); + + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseCouchbaseMessage(&buf, sock, false, NULL); + return 0; +} diff --git a/test/fuzzing/fuzz_esp.cpp b/test/fuzzing/fuzz_esp.cpp index 462aaf8b55..4f93d635a9 100644 --- a/test/fuzzing/fuzz_esp.cpp +++ b/test/fuzzing/fuzz_esp.cpp @@ -16,6 +16,7 @@ // under the License. #include "brpc/policy/esp_protocol.h" +#include "fuzz_common.h" #define kMinInputLength 5 #define kMaxInputLength 1024 @@ -32,7 +33,8 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) butil::IOBuf buf; buf.append(input); - brpc::policy::ParseEspMessage(&buf, NULL, false, NULL); + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseEspMessage(&buf, sock, false, NULL); return 0; } diff --git a/test/fuzzing/fuzz_http_parser.cpp b/test/fuzzing/fuzz_http_parser.cpp new file mode 100644 index 0000000000..0c6b792c83 --- /dev/null +++ b/test/fuzzing/fuzz_http_parser.cpp @@ -0,0 +1,97 @@ +// 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. + +#include +#include "brpc/details/http_parser.h" +#include "brpc/http_method.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +static int on_url_cb(brpc::http_parser* p, const char* at, size_t length) { return 0; } +static int on_header_field_cb(brpc::http_parser* p, const char* at, size_t length) { return 0; } +static int on_header_value_cb(brpc::http_parser* p, const char* at, size_t length) { return 0; } +static int on_body_cb(brpc::http_parser* p, const char* at, size_t length) { return 0; } +static int on_message_begin_cb(brpc::http_parser* p) { return 0; } +static int on_headers_complete_cb(brpc::http_parser* p) { return 0; } +static int on_message_complete_cb(brpc::http_parser* p) { return 0; } + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + // Use first byte to select mode + uint8_t mode = data[0] % 4; + const uint8_t *payload = data + 1; + size_t payload_size = size - 1; + + switch (mode) { + case 0: { + // Fuzz low-level HTTP request parsing + brpc::http_parser parser; + brpc::http_parser_init(&parser, brpc::HTTP_REQUEST); + brpc::http_parser_settings settings; + memset(&settings, 0, sizeof(settings)); + settings.on_url = on_url_cb; + settings.on_header_field = on_header_field_cb; + settings.on_header_value = on_header_value_cb; + settings.on_body = on_body_cb; + settings.on_message_begin = on_message_begin_cb; + settings.on_headers_complete = on_headers_complete_cb; + settings.on_message_complete = on_message_complete_cb; + brpc::http_parser_execute(&parser, &settings, + reinterpret_cast(payload), payload_size); + break; + } + case 1: { + // Fuzz low-level HTTP response parsing + brpc::http_parser parser; + brpc::http_parser_init(&parser, brpc::HTTP_RESPONSE); + brpc::http_parser_settings settings; + memset(&settings, 0, sizeof(settings)); + settings.on_url = on_url_cb; + settings.on_header_field = on_header_field_cb; + settings.on_header_value = on_header_value_cb; + settings.on_body = on_body_cb; + settings.on_message_begin = on_message_begin_cb; + settings.on_headers_complete = on_headers_complete_cb; + settings.on_message_complete = on_message_complete_cb; + brpc::http_parser_execute(&parser, &settings, + reinterpret_cast(payload), payload_size); + break; + } + case 2: { + // Fuzz URL parsing (not connect) + brpc::http_parser_url u; + brpc::http_parser_parse_url(reinterpret_cast(payload), + payload_size, 0, &u); + break; + } + case 3: { + // Fuzz URL parsing (connect mode) + brpc::http_parser_url u; + brpc::http_parser_parse_url(reinterpret_cast(payload), + payload_size, 1, &u); + break; + } + } + + return 0; +} diff --git a/test/fuzzing/fuzz_hulu.cpp b/test/fuzzing/fuzz_hulu.cpp index f90d7be864..cb81e1414d 100644 --- a/test/fuzzing/fuzz_hulu.cpp +++ b/test/fuzzing/fuzz_hulu.cpp @@ -16,6 +16,7 @@ // under the License. #include "brpc/policy/hulu_pbrpc_protocol.h" +#include "fuzz_common.h" #define kMinInputLength 5 #define kMaxInputLength 1024 @@ -32,7 +33,8 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) butil::IOBuf buf; buf.append(input); - brpc::policy::ParseHuluMessage(&buf, NULL, false, NULL); + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseHuluMessage(&buf, sock, false, NULL); return 0; } diff --git a/test/fuzzing/fuzz_memcache.cpp b/test/fuzzing/fuzz_memcache.cpp new file mode 100644 index 0000000000..e1ef86e626 --- /dev/null +++ b/test/fuzzing/fuzz_memcache.cpp @@ -0,0 +1,38 @@ +// 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. + +#include "brpc/policy/memcache_binary_protocol.h" +#include "fuzz_common.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + std::string input(reinterpret_cast(data), size); + butil::IOBuf buf; + buf.append(input); + + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseMemcacheMessage(&buf, sock, false, NULL); + return 0; +} diff --git a/test/fuzzing/fuzz_mongo.cpp b/test/fuzzing/fuzz_mongo.cpp new file mode 100644 index 0000000000..c78ed96591 --- /dev/null +++ b/test/fuzzing/fuzz_mongo.cpp @@ -0,0 +1,38 @@ +// 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. + +#include "brpc/policy/mongo_protocol.h" +#include "fuzz_common.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + std::string input(reinterpret_cast(data), size); + butil::IOBuf buf; + buf.append(input); + + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseMongoMessage(&buf, sock, false, NULL); + return 0; +} diff --git a/test/fuzzing/fuzz_shead.cpp b/test/fuzzing/fuzz_shead.cpp index 2abf517b8c..e5d574da58 100644 --- a/test/fuzzing/fuzz_shead.cpp +++ b/test/fuzzing/fuzz_shead.cpp @@ -17,6 +17,7 @@ #include "brpc/policy/public_pbrpc_meta.pb.h" #include "brpc/policy/public_pbrpc_protocol.h" #include "brpc/policy/most_common_message.h" +#include "fuzz_common.h" #define kMinInputLength 5 #define kMaxInputLength 1024 @@ -32,7 +33,8 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) butil::IOBuf buf; buf.append(input); - brpc::policy::ParseNsheadMessage(&buf, NULL, false, NULL); + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseNsheadMessage(&buf, sock, false, NULL); return 0; } diff --git a/test/fuzzing/fuzz_sofa.cpp b/test/fuzzing/fuzz_sofa.cpp index e26f6218cb..b393f85270 100644 --- a/test/fuzzing/fuzz_sofa.cpp +++ b/test/fuzzing/fuzz_sofa.cpp @@ -18,6 +18,7 @@ #include "brpc/policy/sofa_pbrpc_meta.pb.h" #include "brpc/policy/sofa_pbrpc_protocol.h" #include "brpc/policy/most_common_message.h" +#include "fuzz_common.h" #define kMinInputLength 5 #define kMaxInputLength 1024 @@ -34,6 +35,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) butil::IOBuf buf; buf.append(input); - brpc::policy::ParseSofaMessage(&buf, NULL, false, NULL); + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseSofaMessage(&buf, sock, false, NULL); return 0; } diff --git a/test/fuzzing/fuzz_streaming.cpp b/test/fuzzing/fuzz_streaming.cpp new file mode 100644 index 0000000000..532bb72550 --- /dev/null +++ b/test/fuzzing/fuzz_streaming.cpp @@ -0,0 +1,38 @@ +// 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. + +#include "brpc/policy/streaming_rpc_protocol.h" +#include "fuzz_common.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + std::string input(reinterpret_cast(data), size); + butil::IOBuf buf; + buf.append(input); + + brpc::Socket* sock = get_fuzz_socket(); + brpc::policy::ParseStreamingMessage(&buf, sock, false, NULL); + return 0; +} diff --git a/test/fuzzing/fuzz_thrift.cpp b/test/fuzzing/fuzz_thrift.cpp new file mode 100644 index 0000000000..c7ecd4323c --- /dev/null +++ b/test/fuzzing/fuzz_thrift.cpp @@ -0,0 +1,36 @@ +// 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. + +#include "brpc/policy/thrift_protocol.h" + +#define kMinInputLength 5 +#define kMaxInputLength 4096 + +extern "C" int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < kMinInputLength || size > kMaxInputLength){ + return 1; + } + + std::string input(reinterpret_cast(data), size); + butil::IOBuf buf; + buf.append(input); + + brpc::policy::ParseThriftMessage(&buf, NULL, false, NULL); + return 0; +} diff --git a/test/fuzzing/oss-fuzz.sh b/test/fuzzing/oss-fuzz.sh index f959b70b74..3f1649e9bb 100644 --- a/test/fuzzing/oss-fuzz.sh +++ b/test/fuzzing/oss-fuzz.sh @@ -34,7 +34,10 @@ cmake \ # https://github.com/google/oss-fuzz/pull/10898 make \ fuzz_butil fuzz_esp fuzz_hpack fuzz_http fuzz_hulu fuzz_json \ - fuzz_redis fuzz_shead fuzz_sofa fuzz_uri --ignore-errors -j$(nproc) + fuzz_redis fuzz_shead fuzz_sofa fuzz_uri \ + fuzz_baidu_rpc fuzz_mongo fuzz_memcache \ + fuzz_couchbase fuzz_streaming fuzz_http_parser \ + fuzz_amf --ignore-errors -j$(nproc) cp test/fuzz_* $OUT/