0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-26 23:01:04 +08:00

Merge pull request #3894 from bluca/fuzzers

Problems: sub/cancel broken with CURVE, fuzzers need corpora and better unit testing
This commit is contained in:
Doron Somech 2020-05-04 14:43:47 +03:00 committed by GitHub
commit 309d1f1cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 294 additions and 39 deletions

View File

@ -1176,6 +1176,33 @@ endif
FUZZINGdir = ${prefix}/${FUZZING_INSTALLDIR}
FUZZING_PROGRAMS = ${fuzzer_apps}
FUZZING_DATA = tests/fuzzer_corpora/endpoint.dict tests/fuzzer_corpora/zmtp.dict \
tests/fuzzer_corpora/test_bind_curve_fuzzer.txt tests/fuzzer_corpora/test_bind_null_fuzzer.txt \
tests/fuzzer_corpora/test_connect_curve_fuzzer.txt tests/fuzzer_corpora/test_connect_null_fuzzer.txt
install-data-hook:
$(LN_S) -r -f $(DESTDIR)/$(FUZZINGdir)/endpoint.dict $(DESTDIR)/$(FUZZINGdir)/test_bind_fuzzer.dict
$(LN_S) -r -f $(DESTDIR)/$(FUZZINGdir)/endpoint.dict $(DESTDIR)/$(FUZZINGdir)/test_connect_fuzzer.dict
$(LN_S) -r -f $(DESTDIR)/$(FUZZINGdir)/zmtp.dict $(DESTDIR)/$(FUZZINGdir)/test_bind_curve_fuzzer.dict
$(LN_S) -r -f $(DESTDIR)/$(FUZZINGdir)/zmtp.dict $(DESTDIR)/$(FUZZINGdir)/test_bind_null_fuzzer.dict
$(LN_S) -r -f $(DESTDIR)/$(FUZZINGdir)/zmtp.dict $(DESTDIR)/$(FUZZINGdir)/test_connect_curve_fuzzer.dict
$(LN_S) -r -f $(DESTDIR)/$(FUZZINGdir)/zmtp.dict $(DESTDIR)/$(FUZZINGdir)/test_connect_null_fuzzer.dict
$(shell cat $(DESTDIR)/$(FUZZINGdir)/test_bind_curve_fuzzer.txt | perl -e 'print pack "H*", <STDIN>' > $(DESTDIR)/$(FUZZINGdir)/test_bind_curve_fuzzer.seed; \
export fn=$$(cat $(DESTDIR)/$(FUZZINGdir)/test_bind_curve_fuzzer.seed | sha1sum | awk '{print $$1}'); \
mv $(DESTDIR)/$(FUZZINGdir)/test_bind_curve_fuzzer.seed $(DESTDIR)/$(FUZZINGdir)/$$fn; \
zip -j -m --quiet $(DESTDIR)/$(FUZZINGdir)/test_bind_curve_fuzzer_seed_corpus.zip $(DESTDIR)/$(FUZZINGdir)/$$fn)
$(shell cat $(DESTDIR)/$(FUZZINGdir)/test_bind_null_fuzzer.txt | perl -e 'print pack "H*", <STDIN>' > $(DESTDIR)/$(FUZZINGdir)/test_bind_null_fuzzer.seed; \
export fn=$$(cat $(DESTDIR)/$(FUZZINGdir)/test_bind_null_fuzzer.seed | sha1sum | awk '{print $$1}'); \
mv $(DESTDIR)/$(FUZZINGdir)/test_bind_null_fuzzer.seed $(DESTDIR)/$(FUZZINGdir)/$$fn; \
zip -j -m --quiet $(DESTDIR)/$(FUZZINGdir)/test_bind_null_fuzzer_seed_corpus.zip $(DESTDIR)/$(FUZZINGdir)/$$fn)
$(shell cat $(DESTDIR)/$(FUZZINGdir)/test_connect_curve_fuzzer.txt | perl -e 'print pack "H*", <STDIN>' > $(DESTDIR)/$(FUZZINGdir)/test_connect_curve_fuzzer.seed; \
export fn=$$(cat $(DESTDIR)/$(FUZZINGdir)/test_connect_curve_fuzzer.seed | sha1sum | awk '{print $$1}'); \
mv $(DESTDIR)/$(FUZZINGdir)/test_connect_curve_fuzzer.seed $(DESTDIR)/$(FUZZINGdir)/$$fn; \
zip -j -m --quiet $(DESTDIR)/$(FUZZINGdir)/test_connect_curve_fuzzer_seed_corpus.zip $(DESTDIR)/$(FUZZINGdir)/$$fn)
$(shell cat $(DESTDIR)/$(FUZZINGdir)/test_connect_null_fuzzer.txt | perl -e 'print pack "H*", <STDIN>' > $(DESTDIR)/$(FUZZINGdir)/test_connect_null_fuzzer.seed; \
export fn=$$(cat $(DESTDIR)/$(FUZZINGdir)/test_connect_null_fuzzer.seed | sha1sum | awk '{print $$1}'); \
mv $(DESTDIR)/$(FUZZINGdir)/test_connect_null_fuzzer.seed $(DESTDIR)/$(FUZZINGdir)/$$fn; \
zip -j -m --quiet $(DESTDIR)/$(FUZZINGdir)/test_connect_null_fuzzer_seed_corpus.zip $(DESTDIR)/$(FUZZINGdir)/$$fn)
rm -f $(DESTDIR)/$(FUZZINGdir)/*.txt
else
test_apps += tests/test_bind_null_fuzzer \
tests/test_connect_null_fuzzer \

View File

@ -41,10 +41,14 @@
#include "secure_allocator.hpp"
zmq::curve_client_t::curve_client_t (session_base_t *session_,
const options_t &options_) :
const options_t &options_,
const bool downgrade_sub_) :
mechanism_base_t (session_, options_),
curve_mechanism_base_t (
session_, options_, "CurveZMQMESSAGEC", "CurveZMQMESSAGES"),
curve_mechanism_base_t (session_,
options_,
"CurveZMQMESSAGEC",
"CurveZMQMESSAGES",
downgrade_sub_),
_state (send_hello),
_tools (options_.curve_public_key,
options_.curve_secret_key,

View File

@ -44,7 +44,9 @@ class session_base_t;
class curve_client_t ZMQ_FINAL : public curve_mechanism_base_t
{
public:
curve_client_t (session_base_t *session_, const options_t &options_);
curve_client_t (session_base_t *session_,
const options_t &options_,
const bool downgrade_sub_);
~curve_client_t () ZMQ_FINAL;
// mechanism implementation

View File

@ -49,9 +49,11 @@ zmq::curve_mechanism_base_t::curve_mechanism_base_t (
session_base_t *session_,
const options_t &options_,
const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_) :
const char *decode_nonce_prefix_,
const bool downgrade_sub_) :
mechanism_base_t (session_, options_),
curve_encoding_t (encode_nonce_prefix_, decode_nonce_prefix_)
curve_encoding_t (
encode_nonce_prefix_, decode_nonce_prefix_, downgrade_sub_)
{
}
@ -77,11 +79,13 @@ int zmq::curve_mechanism_base_t::decode (msg_t *msg_)
}
zmq::curve_encoding_t::curve_encoding_t (const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_) :
const char *decode_nonce_prefix_,
const bool downgrade_sub_) :
_encode_nonce_prefix (encode_nonce_prefix_),
_decode_nonce_prefix (decode_nonce_prefix_),
_cn_nonce (1),
_cn_peer_nonce (1)
_cn_peer_nonce (1),
_downgrade_sub (downgrade_sub_)
{
}
@ -133,15 +137,26 @@ int zmq::curve_encoding_t::check_validity (msg_t *msg_, int *error_event_code_)
int zmq::curve_encoding_t::encode (msg_t *msg_)
{
size_t sub_cancel_len = 0;
uint8_t message_nonce[crypto_box_NONCEBYTES];
memcpy (message_nonce, _encode_nonce_prefix, nonce_prefix_len);
put_uint64 (message_nonce + nonce_prefix_len, get_and_inc_nonce ());
if (msg_->is_subscribe () || msg_->is_cancel ()) {
if (_downgrade_sub)
sub_cancel_len = 1;
else
sub_cancel_len = msg_->is_cancel ()
? zmq::msg_t::cancel_cmd_name_size
: zmq::msg_t::sub_cmd_name_size;
}
#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
const size_t mlen = flags_len + msg_->size ();
const size_t mlen = flags_len + sub_cancel_len + msg_->size ();
std::vector<uint8_t> message_plaintext (mlen);
#else
const size_t mlen = crypto_box_ZEROBYTES + flags_len + msg_->size ();
const size_t mlen =
crypto_box_ZEROBYTES + flags_len + sub_cancel_len + msg_->size ();
std::vector<uint8_t> message_plaintext_with_zerobytes (mlen);
uint8_t *const message_plaintext =
&message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
@ -153,10 +168,27 @@ int zmq::curve_encoding_t::encode (msg_t *msg_)
const uint8_t flags = msg_->flags () & flag_mask;
message_plaintext[0] = flags;
// For backward compatibility subscribe/cancel command messages are not stored with
// the message flags, and are encoded in the encoder, so that messages for < 3.0 peers
// can be encoded in the "old" 0/1 way rather than as commands.
if (sub_cancel_len == 1)
message_plaintext[flags_len] = msg_->is_subscribe () ? 1 : 0;
else if (sub_cancel_len == zmq::msg_t::sub_cmd_name_size) {
message_plaintext[0] |= zmq::msg_t::command;
memcpy (&message_plaintext[flags_len], zmq::sub_cmd_name,
zmq::msg_t::sub_cmd_name_size);
} else if (sub_cancel_len == zmq::msg_t::cancel_cmd_name_size) {
message_plaintext[0] |= zmq::msg_t::command;
memcpy (&message_plaintext[flags_len], zmq::cancel_cmd_name,
zmq::msg_t::cancel_cmd_name_size);
}
// this is copying the data from insecure memory, so there is no point in
// using secure_allocator_t for message_plaintext
if (msg_->size () > 0)
memcpy (&message_plaintext[flags_len], msg_->data (), msg_->size ());
memcpy (&message_plaintext[flags_len + sub_cancel_len], msg_->data (),
msg_->size ());
#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
msg_t msg_box;

View File

@ -56,7 +56,8 @@ class curve_encoding_t
{
public:
curve_encoding_t (const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_);
const char *decode_nonce_prefix_,
const bool downgrade_sub_);
int encode (msg_t *msg_);
int decode (msg_t *msg_, int *error_event_code_);
@ -81,6 +82,8 @@ class curve_encoding_t
// Intermediary buffer used to speed up boxing and unboxing.
uint8_t _cn_precom[crypto_box_BEFORENMBYTES];
const bool _downgrade_sub;
ZMQ_NON_COPYABLE_NOR_MOVABLE (curve_encoding_t)
};
@ -91,7 +94,8 @@ class curve_mechanism_base_t : public virtual mechanism_base_t,
curve_mechanism_base_t (session_base_t *session_,
const options_t &options_,
const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_);
const char *decode_nonce_prefix_,
const bool downgrade_sub_);
// mechanism implementation
int encode (msg_t *msg_) ZMQ_OVERRIDE;

View File

@ -41,12 +41,16 @@
zmq::curve_server_t::curve_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_) :
const options_t &options_,
const bool downgrade_sub_) :
mechanism_base_t (session_, options_),
zap_client_common_handshake_t (
session_, peer_address_, options_, sending_ready),
curve_mechanism_base_t (
session_, options_, "CurveZMQMESSAGES", "CurveZMQMESSAGEC")
curve_mechanism_base_t (session_,
options_,
"CurveZMQMESSAGES",
"CurveZMQMESSAGEC",
downgrade_sub_)
{
int rc;
// Fetch our secret key from socket options

View File

@ -48,7 +48,8 @@ class curve_server_t ZMQ_FINAL : public zap_client_common_handshake_t,
public:
curve_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_);
const options_t &options_,
const bool downgrade_sub_);
~curve_server_t ();
// mechanism implementation

View File

@ -268,10 +268,10 @@ bool zmq::ws_engine_t::select_protocol (const char *protocol_)
&& strcmp ("ZWS2.0/CURVE", protocol_) == 0) {
if (_options.as_server)
_mechanism = new (std::nothrow)
curve_server_t (session (), _peer_address, _options);
curve_server_t (session (), _peer_address, _options, false);
else
_mechanism =
new (std::nothrow) curve_client_t (session (), _options);
new (std::nothrow) curve_client_t (session (), _options, false);
alloc_assert (_mechanism);
return true;
}

View File

@ -347,7 +347,7 @@ bool zmq::zmtp_engine_t::handshake_v2_0 ()
return true;
}
bool zmq::zmtp_engine_t::handshake_v3_x ()
bool zmq::zmtp_engine_t::handshake_v3_x (const bool downgrade_sub_)
{
if (_options.mechanism == ZMQ_NULL
&& memcmp (_greeting_recv + 12, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
@ -374,11 +374,11 @@ bool zmq::zmtp_engine_t::handshake_v3_x ()
"CURVE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20)
== 0) {
if (_options.as_server)
_mechanism = new (std::nothrow)
curve_server_t (session (), _peer_address, _options);
_mechanism = new (std::nothrow) curve_server_t (
session (), _peer_address, _options, downgrade_sub_);
else
_mechanism =
new (std::nothrow) curve_client_t (session (), _options);
_mechanism = new (std::nothrow)
curve_client_t (session (), _options, downgrade_sub_);
alloc_assert (_mechanism);
}
#endif
@ -418,7 +418,7 @@ bool zmq::zmtp_engine_t::handshake_v3_0 ()
_options.in_batch_size, _options.maxmsgsize, _options.zero_copy);
alloc_assert (_decoder);
return zmq::zmtp_engine_t::handshake_v3_x ();
return zmq::zmtp_engine_t::handshake_v3_x (true);
}
bool zmq::zmtp_engine_t::handshake_v3_1 ()
@ -430,7 +430,7 @@ bool zmq::zmtp_engine_t::handshake_v3_1 ()
_options.in_batch_size, _options.maxmsgsize, _options.zero_copy);
alloc_assert (_decoder);
return zmq::zmtp_engine_t::handshake_v3_x ();
return zmq::zmtp_engine_t::handshake_v3_x (false);
}
int zmq::zmtp_engine_t::routing_id_msg (msg_t *msg_)

View File

@ -92,7 +92,7 @@ class zmtp_engine_t ZMQ_FINAL : public stream_engine_base_t
bool handshake_v1_0_unversioned ();
bool handshake_v1_0 ();
bool handshake_v2_0 ();
bool handshake_v3_x ();
bool handshake_v3_x (bool downgrade_sub);
bool handshake_v3_0 ();
bool handshake_v3_1 ();

View File

@ -0,0 +1,4 @@
ipc="ipc://"
inproc="inproc://"
tcp="tcp://"
udp="udp://"

View File

@ -0,0 +1 @@
ff00000000000000017f03014355525645000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c80548454c4c4f0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a5af606a040b3eb749b38aad3c43ea22f18b1659de5c3db1996b6f880d48e30e000000000000000108706d93931262db2e66acd402ecbe67b85aba0e696fe5d5ada13b14d2ab50917301acbb09f29f85b24c470915951d1ce2973288aca89cda8c484389bba97271a0ded05860f152a5c757b7bdd5849fa206000000000000011408494e495449415445e3d3dd23298ecbdc31d3b471a56f9235701b35296117c8f798a4013f1d3a11d4c4c254b1785ad9cc6f3e01b9387f95468fabe11bd45d73704a9653165e045c2a2baa48130e8d9d9745975fc7600c23679cc044b396a4a7f91c946acf744d072a00000000000000020e56c8aebfb1f9f33f989e76c2cebbe45e0fef500717436e64b53da90ac7d2af3ca8ebd5edbdfb896ed18126d2a4c2836861a935e089503cc5efbfc166b94e504a0cfff64c0410689fd669aa4c1b041cadb21910fe7af4323258461960d969d8c481b47959430732bdb6126d62ddf801b3db7d32c146e5b10bc83cd503fd75badad67e6370c7adb2996a3242b0210e82ef1947ab563a5333a60aaeae9fc7c968c6264a002b074d4553534147450000000000000003cc90b40b5bc78bcb00f8ad69dc162c4b387cf8b9ab2d334455b3a9

View File

@ -0,0 +1 @@
ff00000000000000017f03014e554c4c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004190552454144590b536f636b65742d5479706500000003535542040a09535542534352494245

View File

@ -0,0 +1 @@
ff00000000000000017f03014355525645000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004a80757454c434f4d45b82e58be6c89e876fd91e236488b8d4bb37846d2cd38e739264ea8ff66ca06f5930d70920b8429505844f064be5d8c977078b8dd135e340cd8c7f276293ebf9c45bd6b240c0d9c15b8fde2defb11f4f49c864695f07c3456e855dd7eef6ee371dbda86b05f3db853781ce741ecacffcc50a7a8176ec8ebd3c2692beb79977b143f90c77a13eee6ed5282ee27ad45f36fd08a31ecd205dfa9e7b6887fe2ea1ccc0432055245414459000000000000000171f53d3270589095cd304baeedfe0a326ed8488d0173dded2dca5b996d0d31e6469d5f4e0026074d4553534147450000000000000002fbb1f34c99e8d2f5a2cb37dfb01b0a74f2d1c0439f5c0026074d455353414745000000000000000388166e23cf25cda98b8b3f635039b468bb222cbfec30

View File

@ -0,0 +1 @@
ff00000000000000017f03014e554c4c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a0552454144590b536f636b65742d547970650000000458505542000568656c6c6f0005776f726c64

View File

@ -0,0 +1,45 @@
# ZMTP magic binary streams
# 1.0 https://rfc.zeromq.org/spec/13/
# 2.0 https://rfc.zeromq.org/spec/15/
# 3.1 https://rfc.zeromq.org/spec/37/
# curve https://rfc.zeromq.org/spec/26/
signature="\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x7F"
signature_v1="\x01\x00"
version_v2="\x01"
version_v3="\x03\x00"
version_v3_1="\x03\x01"
mechanism_null="\x4E\x55\x4C\x4C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
mechanism_curve="\x43\x55\x52\x56\x45\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
short_command="\x04"
long_command="\x06"
ready="\x05\x52\x45\x41\x44\x59"
error="\x05\x45\x52\x52\x4F\x52"
identity="\x08\x49\x64\x65\x6E\x74\x69\x74\x79"
socket_type="\x0B\x53\x6F\x63\x6B\x65\x74\x2D\x54\x79\x70\x65"
dealer="\x06\x44\x45\x41\x4C\x45\x52"
router="\x06\x52\x4F\x55\x54\x45\x52"
pub="\x03\x50\x55\x42"
sub="\x03\x53\x55\x42"
xpub="\x04\x58\x50\x55\x42"
xsub="\x04\x58\x53\x55\x42"
req="\x03\x52\x45\x51"
rep="\x03\x52\x45\x50"
push="\x04\x50\x55\x53\x48"
pull="\x04\x50\x55\x4C\x4C"
pair="\x04\x50\x41\x49\x52"
client="\x05\x43\x4C\x49\x45\x4E\x54"
server="\x05\x53\x45\x52\x56\x45\x52"
radio="\x05\x52\x41\x44\x49\x4F"
dish="\x04\x44\x49\x53\x48"
scatter="\x06\x53\x43\x41\x54\x54\x45\x52"
gather="\x06\x47\x41\x54\x48\x45\x52"
subscribe="\x09\x53\x55\x42\x53\x43\x52\x49\x42\x45"
cancel="\x06\x43\x41\x4E\x43\x45\x4C"
join="\x04\x4A\x4F\x49\x4E"
leave="\x05\x43\x41\x4E\x43\x45\x4C"
ping="\x04\x50\x49\x4E\x47"
pong="\x04\x50\x4F\x4E\x47"
hello="\x05\x48\x45\x4C\x4C\x4F\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
welcome="\x07\x57\x45\x4C\x43\x4F\x4D\x45"
initiate="\x08\x49\x4E\x49\x54\x49\x41\x54\x45"
message="\x07\x4D\x45\x53\x53\x41\x47\x45"

View File

@ -50,6 +50,22 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
my_endpoint);
fd_t client = connect_socket (my_endpoint);
// If there is not enough data for a full greeting, just send what we can
// Otherwise send greeting first, as expected by the protocol
uint8_t buf[64];
if (size >= 64) {
send (client, (void *) data, 64, MSG_NOSIGNAL);
data += 64;
size -= 64;
}
recv (client, buf, 64, 0);
if (size >= 202) {
send (client, (void *) data, 202, MSG_NOSIGNAL);
data += 202;
size -= 202;
}
recv (client, buf, 64, MSG_DONTWAIT);
msleep (250);
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
sent = send (client, (const char *) data, size, MSG_NOSIGNAL);
@ -66,8 +82,16 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
#ifndef ZMQ_USE_FUZZING_ENGINE
void test_bind_curve_fuzzer ()
{
TEST_ASSERT_SUCCESS_ERRNO (LLVMFuzzerTestOneInput (
zmtp_greeting_curve, sizeof (zmtp_greeting_curve)));
uint8_t *data;
size_t len;
if (fuzzer_corpus_encode ("tests/fuzzer_corpora/test_bind_curve_fuzzer.txt",
&data, &len)
!= 0)
exit (77);
TEST_ASSERT_SUCCESS_ERRNO (LLVMFuzzerTestOneInput (data, len));
free (data);
}
int main (int argc, char **argv)

View File

@ -44,6 +44,16 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
fd_t client = connect_socket (my_endpoint);
// If there is not enough data for a full greeting, just send what we can
// Otherwise send greeting first, as expected by the protocol
uint8_t buf[64];
if (size >= 64) {
send (client, (void *) data, 64, MSG_NOSIGNAL);
data += 64;
size -= 64;
}
recv (client, buf, 64, 0);
msleep (250);
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
sent = send (client, (const char *) data, size, MSG_NOSIGNAL);
@ -60,8 +70,16 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
#ifndef ZMQ_USE_FUZZING_ENGINE
void test_bind_null_fuzzer ()
{
TEST_ASSERT_SUCCESS_ERRNO (
LLVMFuzzerTestOneInput (zmtp_greeting_null, sizeof (zmtp_greeting_null)));
uint8_t *data;
size_t len;
if (fuzzer_corpus_encode ("tests/fuzzer_corpora/test_bind_null_fuzzer.txt",
&data, &len)
!= 0)
exit (77);
TEST_ASSERT_SUCCESS_ERRNO (LLVMFuzzerTestOneInput (data, len));
free (data);
}
int main (int argc, char **argv)

View File

@ -51,11 +51,28 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
fd_t server_accept =
TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));
// If there is not enough data for a full greeting, just send what we can
// Otherwise send greeting first, as expected by the protocol
uint8_t buf[64];
if (size >= 64) {
send (server_accept, (void *) data, 64, MSG_NOSIGNAL);
data += 64;
size -= 64;
}
recv (server_accept, buf, 64, 0);
msleep (250);
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);
recv (server_accept, buf, 64, MSG_DONTWAIT);
msleep (250);
zmq_msg_t msg;
zmq_msg_init (&msg);
while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT))
zmq_msg_close (&msg);
close (server_accept);
close (server);
@ -69,8 +86,16 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
#ifndef ZMQ_USE_FUZZING_ENGINE
void test_connect_curve_fuzzer ()
{
TEST_ASSERT_SUCCESS_ERRNO (LLVMFuzzerTestOneInput (
zmtp_greeting_curve, sizeof (zmtp_greeting_curve)));
uint8_t *data;
size_t len;
if (fuzzer_corpus_encode (
"tests/fuzzer_corpora/test_connect_curve_fuzzer.txt", &data, &len)
!= 0)
exit (77);
TEST_ASSERT_SUCCESS_ERRNO (LLVMFuzzerTestOneInput (data, len));
free (data);
}
int main (int argc, char **argv)

View File

@ -42,16 +42,33 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
char my_endpoint[MAX_SOCKET_STRING];
fd_t server = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint);
void *client = test_context_socket (ZMQ_PUB);
void *client = test_context_socket (ZMQ_SUB);
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_SUBSCRIBE, "", 0));
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
fd_t server_accept =
TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));
// If there is not enough data for a full greeting, just send what we can
// Otherwise send greeting first, as expected by the protocol
uint8_t buf[64];
if (size >= 64) {
send (server_accept, (void *) data, 64, MSG_NOSIGNAL);
data += 64;
size -= 64;
}
recv (server_accept, buf, 64, 0);
msleep (250);
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);
msleep (250);
zmq_msg_t msg;
zmq_msg_init (&msg);
while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT))
zmq_msg_close (&msg);
close (server_accept);
close (server);
@ -64,13 +81,21 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
#ifndef ZMQ_USE_FUZZING_ENGINE
void test_connect_null_fuzzer ()
{
TEST_ASSERT_SUCCESS_ERRNO (
LLVMFuzzerTestOneInput (zmtp_greeting_null, sizeof (zmtp_greeting_null)));
uint8_t *data;
size_t len;
if (fuzzer_corpus_encode (
"tests/fuzzer_corpora/test_connect_null_fuzzer.txt", &data, &len)
!= 0)
exit (77);
TEST_ASSERT_SUCCESS_ERRNO (LLVMFuzzerTestOneInput (data, len));
free (data);
}
int main (int argc, char **argv)
{
setup_test_environment ();
setup_test_environment (0);
UNITY_BEGIN ();
RUN_TEST (test_connect_null_fuzzer);

View File

@ -522,3 +522,34 @@ bool strneq (const char *lhs_, const char *rhs_)
{
return strcmp (lhs_, rhs_) != 0;
}
int fuzzer_corpus_encode (const char *filename, uint8_t **data, size_t *len)
{
TEST_ASSERT_NOT_NULL (filename);
TEST_ASSERT_NOT_NULL (data);
TEST_ASSERT_NOT_NULL (len);
FILE *f = fopen (filename, "r");
if (!f)
return -1;
fseek (f, 0, SEEK_END);
size_t text_len = ftell (f);
fseek (f, 0, SEEK_SET);
char *buf = (char *) malloc (text_len);
TEST_ASSERT_NOT_NULL (buf);
size_t read = fread (buf, 1, text_len, f);
fclose (f);
TEST_ASSERT_EQUAL_INT (read, text_len);
// Convert to binary format, corpus is stored in ascii (hex)
*len = text_len / 2;
*data = (unsigned char *) malloc (*len);
TEST_ASSERT_NOT_NULL (*data);
const char *pos = buf;
for (size_t count = 0; count < *len; ++count, pos += 2) {
char tmp[3] = {pos[0], pos[1], 0};
(*data)[count] = (uint8_t) strtol (tmp, NULL, 16);
}
free (buf);
return 0;
}

View File

@ -44,6 +44,7 @@
#else
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#endif
// This defines the settle time used in tests; raise this if we
@ -227,4 +228,6 @@ fd_t bind_socket_resolve_port (const char *address_,
const int af_ = AF_INET,
const int protocol_ = IPPROTO_TCP);
int fuzzer_corpus_encode (const char *filename, uint8_t **data, size_t *len);
#endif

View File

@ -48,9 +48,11 @@ void test_roundtrip (zmq::msg_t *msg_)
+ msg_->size ());
zmq::curve_encoding_t encoding_client ("CurveZMQMESSAGEC",
"CurveZMQMESSAGES");
"CurveZMQMESSAGES",
false);
zmq::curve_encoding_t encoding_server ("CurveZMQMESSAGES",
"CurveZMQMESSAGEC");
"CurveZMQMESSAGEC",
false);
uint8_t client_public[32];
uint8_t client_secret[32];