diff options
-rwxr-xr-x | projects/libzmq/build.sh | 4 | ||||
-rw-r--r-- | projects/libzmq/decode_fuzzer.cc | 9 | ||||
-rw-r--r-- | projects/libzmq/project.yaml | 3 | ||||
-rw-r--r-- | projects/libzmq/socket_bind_fuzzer.cc | 74 | ||||
-rw-r--r-- | projects/libzmq/socket_connect_fuzzer.cc | 77 |
5 files changed, 164 insertions, 3 deletions
diff --git a/projects/libzmq/build.sh b/projects/libzmq/build.sh index be98e338..db574888 100755 --- a/projects/libzmq/build.sh +++ b/projects/libzmq/build.sh @@ -17,8 +17,8 @@ # build project cd $SRC/libzmq -./autogen.sh --disable-shared -./configure +./autogen.sh +./configure --disable-shared --disable-perf --disable-curve-keygen make -j$(nproc) V=1 # build fuzzers diff --git a/projects/libzmq/decode_fuzzer.cc b/projects/libzmq/decode_fuzzer.cc index cedf8ee6..ef3f86a6 100644 --- a/projects/libzmq/decode_fuzzer.cc +++ b/projects/libzmq/decode_fuzzer.cc @@ -21,8 +21,15 @@ #include "include/zmq.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint8_t secret_key[32]; + uint8_t *secret_key; + // As per API definition, input must be divisible by 5, so truncate it if it's not + size -= size % 5; + // As per API definition, the destination must be at least 0.8 times the input data + secret_key = (uint8_t *)malloc(size * 4 / 5); + if (!secret_key) + return -1; std::string z85_secret_key(reinterpret_cast<const char *>(data), size); zmq_z85_decode(secret_key, z85_secret_key.c_str()); + free(secret_key); return 0; } diff --git a/projects/libzmq/project.yaml b/projects/libzmq/project.yaml index 42dad7fb..59b178c3 100644 --- a/projects/libzmq/project.yaml +++ b/projects/libzmq/project.yaml @@ -1,6 +1,9 @@ homepage: "https://github.com/zeromq/libzmq" language: c++ primary_contact: "bluca@debian.org" +auto_ccs: + - "luca.boccassi@gmail.com" + - "somdoron@gmail.com" sanitizers: - address - memory diff --git a/projects/libzmq/socket_bind_fuzzer.cc b/projects/libzmq/socket_bind_fuzzer.cc new file mode 100644 index 00000000..c47ba17d --- /dev/null +++ b/projects/libzmq/socket_bind_fuzzer.cc @@ -0,0 +1,74 @@ +// Copyright 2020 Luca Boccassi <bluca@debian.org> +// +// 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 <fuzzer/FuzzedDataProvider.h> + +#include <cstddef> +#include <cstdint> +#include <string> +#include <assert.h> +#include <arpa/inet.h> +#include <unistd.h> + +#include "include/zmq.h" + +// Test that the ZMTP engine handles invalid handshake when binding +// https://rfc.zeromq.org/spec/37/ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + void *server, *ctx; + struct sockaddr_in ip4addr; + char endpoint[32]; + size_t endpoint_len = 32, sent_bytes; + unsigned short port; + int client, rc, linger = 0; + + ctx = zmq_ctx_new (); + assert(ctx); + server = zmq_socket(ctx, ZMQ_PUB); + assert(server); + rc = zmq_setsockopt (server, ZMQ_LINGER, &linger, sizeof(linger)); + assert(rc == 0); + rc = zmq_bind(server, "tcp://127.0.0.1:*"); + assert(rc == 0); + rc = zmq_getsockopt(server, ZMQ_LAST_ENDPOINT, endpoint, &endpoint_len); + assert(rc == 0); + rc = sscanf(endpoint, "tcp://127.0.0.1:%hu", &port); + assert(rc == 1); + + ip4addr.sin_family = AF_INET; + ip4addr.sin_port = htons(port); + inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr); + client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert(client >= 0); + rc = connect(client, reinterpret_cast<struct sockaddr *> (&ip4addr), sizeof(ip4addr)); + assert(rc >= 0); + + // Send as many bytes as possible, and then let the background I/O thread + // have some time to handle them. + // We should at least be able to send 33 bytes, which is the very first + // part of the ZMTP 3.x handshake. Otherwise something is not quite right + // in the localhost connection we set up. + sent_bytes = write(client, (const char *)data, size); + assert(size < 33 || sent_bytes >= 33); + usleep (static_cast<useconds_t> (250) * 1000); + + close(client); + + rc = zmq_close(server); + assert(rc == 0); + rc = zmq_ctx_term(ctx); + assert(rc == 0); + + return 0; +} diff --git a/projects/libzmq/socket_connect_fuzzer.cc b/projects/libzmq/socket_connect_fuzzer.cc new file mode 100644 index 00000000..ee586fb3 --- /dev/null +++ b/projects/libzmq/socket_connect_fuzzer.cc @@ -0,0 +1,77 @@ +// Copyright 2020 Luca Boccassi <bluca@debian.org> +// +// 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 <fuzzer/FuzzedDataProvider.h> + +#include <cstddef> +#include <cstdint> +#include <string> +#include <assert.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "include/zmq.h" + +// Test that the ZMTP engine handles invalid handshake when connecting +// https://rfc.zeromq.org/spec/37/ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + void *client, *ctx; + struct sockaddr_in ip4addr; + socklen_t ip4addr_len = sizeof(ip4addr); + char endpoint[32]; + size_t sent_bytes; + int server, server_accept, rc; + + ip4addr.sin_family = AF_INET; + ip4addr.sin_port = 0; + inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr); + server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert(server >= 0); + rc = bind(server, reinterpret_cast<struct sockaddr *> (&ip4addr), sizeof(ip4addr)); + assert(rc >= 0); + rc = listen (server, SOMAXCONN); + assert(rc == 0); + rc = getsockname (server, (struct sockaddr *) &ip4addr, &ip4addr_len); + assert(rc == 0); + sprintf(endpoint, "tcp://127.0.0.1:%u", ntohs(ip4addr.sin_port)); + + ctx = zmq_ctx_new (); + assert(ctx); + client = zmq_socket(ctx, ZMQ_SUB); + assert(client); + rc = zmq_connect(client, endpoint); + assert(rc == 0); + + // Send as many bytes as possible, and then let the background I/O thread + // have some time to handle them. + // We should at least be able to send 33 bytes, which is the very first + // part of the ZMTP 3.x handshake. Otherwise something is not quite right + // in the localhost connection we set up. + server_accept = accept(server, NULL, NULL); + sent_bytes = write(server_accept, (const char *)data, size); + assert(size < 33 || sent_bytes >= 33); + usleep (static_cast<useconds_t> (250) * 1000); + + close(server_accept); + close(server); + + rc = zmq_close(client); + assert(rc == 0); + rc = zmq_ctx_term(ctx); + assert(rc == 0); + + return 0; +} |