From 766711f62cd0497136e4e6194f901a46b1c4fe43 Mon Sep 17 00:00:00 2001 From: Arthur Chan Date: Tue, 17 Mar 2026 17:56:19 +0000 Subject: [PATCH] OSS-Fuzz: Revamp block_fuzzer and add corpus seed Signed-off-by: Arthur Chan --- tests/oss-fuzz/Makefile.ci.in | 4 + tests/oss-fuzz/block_seed_corpus/block_seed1 | Bin 0 -> 17 bytes tests/oss-fuzz/block_seed_corpus/block_seed2 | Bin 0 -> 17 bytes tests/oss-fuzz/block_seed_corpus/block_seed3 | Bin 0 -> 147 bytes tests/oss-fuzz/block_seed_corpus/block_seed4 | Bin 0 -> 83 bytes tests/oss-fuzz/block_seed_corpus/block_seed5 | Bin 0 -> 17 bytes tests/oss-fuzz/block_target.c | 155 +++++++++---------- 7 files changed, 81 insertions(+), 78 deletions(-) create mode 100644 tests/oss-fuzz/block_seed_corpus/block_seed1 create mode 100644 tests/oss-fuzz/block_seed_corpus/block_seed2 create mode 100644 tests/oss-fuzz/block_seed_corpus/block_seed3 create mode 100644 tests/oss-fuzz/block_seed_corpus/block_seed4 create mode 100644 tests/oss-fuzz/block_seed_corpus/block_seed5 diff --git a/tests/oss-fuzz/Makefile.ci.in b/tests/oss-fuzz/Makefile.ci.in index 97e2f837..063bac46 100644 --- a/tests/oss-fuzz/Makefile.ci.in +++ b/tests/oss-fuzz/Makefile.ci.in @@ -31,6 +31,10 @@ $(OUT)/%.o: %.c %_fuzzer: %_target.o $(LINK.cc) $(CXXFLAGS) $^ $(top_builddir)/.libs/$(libcoap).a $(LDFLAGS) $(LDLIBS) $(DTLS_LIBS) -o $@ + @if [ -d "$(top_srcdir)/tests/oss-fuzz/$(notdir $*)_seed_corpus" ]; then \ + echo "Found seed corpus for $@, creating zip..."; \ + cd $(top_srcdir)/tests/oss-fuzz && zip -rj $@_seed_corpus.zip $(notdir $*)_seed_corpus/; \ + fi check: $(OBJECTS) diff --git a/tests/oss-fuzz/block_seed_corpus/block_seed1 b/tests/oss-fuzz/block_seed_corpus/block_seed1 new file mode 100644 index 0000000000000000000000000000000000000000..3f685bf92b0256b910090771a1afef9b5268fec7 GIT binary patch literal 17 YcmZQzVq|b)6f$9C+LDr3l6a5_02D0)p#T5? literal 0 HcmV?d00001 diff --git a/tests/oss-fuzz/block_seed_corpus/block_seed2 b/tests/oss-fuzz/block_seed_corpus/block_seed2 new file mode 100644 index 0000000000000000000000000000000000000000..8537da54902efdddcefc836e68d11e2fb3dcf702 GIT binary patch literal 17 YcmZQzVsLO`6f$9C+LDr3l6a5_02iJE-~a#s literal 0 HcmV?d00001 diff --git a/tests/oss-fuzz/block_seed_corpus/block_seed3 b/tests/oss-fuzz/block_seed_corpus/block_seed3 new file mode 100644 index 0000000000000000000000000000000000000000..82ca0c06ea9e07cdef402ca12f76303b3bac36c9 GIT binary patch literal 147 dcmZQzVsLO`R(2Is+LDr3l6a9>`oH4<0{{f@CEox5 literal 0 HcmV?d00001 diff --git a/tests/oss-fuzz/block_seed_corpus/block_seed4 b/tests/oss-fuzz/block_seed_corpus/block_seed4 new file mode 100644 index 0000000000000000000000000000000000000000..73cc6e208647988e5c35362ec4090f3dcca5dcb9 GIT binary patch literal 83 dcmZQzVsLO`G6^$w*^-i2l6a9>>Aw?&006Wr7E1sC literal 0 HcmV?d00001 diff --git a/tests/oss-fuzz/block_seed_corpus/block_seed5 b/tests/oss-fuzz/block_seed_corpus/block_seed5 new file mode 100644 index 0000000000000000000000000000000000000000..397e32348aa517529c1519005765816d0d339e8d GIT binary patch literal 17 YcmZQzVsLO`bWIOU+me!4l6Wu#03tI5Pyhe` literal 0 HcmV?d00001 diff --git a/tests/oss-fuzz/block_target.c b/tests/oss-fuzz/block_target.c index 412e080b..a4b53e68 100644 --- a/tests/oss-fuzz/block_target.c +++ b/tests/oss-fuzz/block_target.c @@ -1,104 +1,103 @@ #include "coap3/coap_internal.h" +#include +#include +#include + +/* Resource handler - exercises coap_add_data_large_response() */ +static void +block_handler(coap_resource_t *resource, coap_session_t *session, + const coap_pdu_t *request, const coap_string_t *query, + coap_pdu_t *response) { + (void)query; + size_t len; + const uint8_t *databuf; + + response->code = COAP_RESPONSE_CODE(205); + + if (coap_get_data(request, &len, &databuf) && len > 64) { + /* Large payload - use block transfer API */ + coap_add_data_large_response(resource, session, request, response, + query, 0, -1, 0, len, databuf, + NULL, NULL); + } else if (len > 0) { + coap_add_data(response, len, databuf); + } else { + /* Generate 256-byte response to trigger BLOCK2 */ + static const uint8_t large_data[256] = { + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' + }; + coap_add_data_large_response(resource, session, request, response, + query, 0, -1, 0, sizeof(large_data), large_data, + NULL, NULL); + } +} int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { coap_context_t *ctx = NULL; coap_session_t *session = NULL; - coap_pdu_t *pdu = NULL; + coap_resource_t *resource = NULL; coap_address_t addr; + uint8_t *dgram = NULL; - if (size <= 4) + if (size < 32) return 0; coap_startup(); coap_set_log_level(COAP_LOG_EMERG); ctx = coap_new_context(NULL); - if (!ctx) { + if (!ctx) goto cleanup; + + /* Configure block mode and max block size */ + uint32_t block_mode = ((uint32_t)data[0] << 8) | data[1]; + coap_context_set_block_mode(ctx, block_mode & 0x0F); + + uint16_t max_block = ((uint16_t)data[2] << 8) | data[3]; + if (max_block >= 16 && max_block <= 1024) { + coap_context_set_max_block_size(ctx, max_block); } - uint32_t block_mode = ((uint32_t)data[0] << 24) | - ((uint32_t)data[1] << 16) | - ((uint32_t)data[2] << 8) | - data[3]; - coap_context_set_block_mode(ctx, block_mode); + /* Create resource */ + resource = coap_resource_init(coap_make_str_const("data"), 0); + if (resource) { + coap_register_request_handler(resource, COAP_REQUEST_GET, block_handler); + coap_register_request_handler(resource, COAP_REQUEST_PUT, block_handler); + coap_register_request_handler(resource, COAP_REQUEST_POST, block_handler); + coap_add_resource(ctx, resource); + } + /* Create session */ coap_address_init(&addr); addr.addr.sa.sa_family = AF_INET; session = coap_new_client_session(ctx, NULL, &addr, COAP_PROTO_UDP); - if (!session) { + if (!session) goto cleanup; - } + session->state = COAP_SESSION_STATE_ESTABLISHED; - /* Test 1: Parse input as PDU and test block option extraction */ - pdu = coap_pdu_init(0, 0, 0, size); - if (pdu) { - if (coap_pdu_parse(COAP_PROTO_UDP, data, size, pdu)) { - coap_block_t block; - coap_block_b_t block_b; - coap_opt_iterator_t opt_iter; - coap_opt_t *option; - - /* Test coap_get_block() and coap_write_block_opt() */ - if (coap_get_block(pdu, COAP_OPTION_BLOCK1, &block)) { - coap_write_block_opt(&block, COAP_OPTION_BLOCK1, pdu, size); - coap_add_block(pdu, size, data, block.num, block.szx); - } - if (coap_get_block(pdu, COAP_OPTION_BLOCK2, &block)) { - coap_write_block_opt(&block, COAP_OPTION_BLOCK2, pdu, size); - coap_add_block(pdu, size, data, block.num, block.szx); - } - - /* Test coap_get_block_b() and coap_write_block_b_opt() */ - if (coap_get_block_b(session, pdu, COAP_OPTION_BLOCK1, &block_b)) { - coap_write_block_b_opt(session, &block_b, COAP_OPTION_BLOCK1, pdu, size); - coap_add_block_b_data(pdu, size, data, &block_b); - } - if (coap_get_block_b(session, pdu, COAP_OPTION_BLOCK2, &block_b)) { - coap_write_block_b_opt(session, &block_b, COAP_OPTION_BLOCK2, pdu, size); - coap_add_block_b_data(pdu, size, data, &block_b); - } - if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block_b)) { - coap_write_block_b_opt(session, &block_b, COAP_OPTION_Q_BLOCK1, pdu, size); - coap_add_block_b_data(pdu, size, data, &block_b); - } - if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK2, &block_b)) { - coap_write_block_b_opt(session, &block_b, COAP_OPTION_Q_BLOCK2, pdu, size); - coap_add_block_b_data(pdu, size, data, &block_b); - } - - /* Test coap_opt_block_num() on all block options */ - if (coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL)) { - while ((option = coap_option_next(&opt_iter))) { - if (opt_iter.number == COAP_OPTION_BLOCK1 || - opt_iter.number == COAP_OPTION_BLOCK2 || - opt_iter.number == COAP_OPTION_Q_BLOCK1 || - opt_iter.number == COAP_OPTION_Q_BLOCK2) { - coap_opt_block_num(option); - } - } - } - - /* Test 2: Generate blocked response with fuzzer-controlled parameters */ - coap_pdu_t *response = coap_pdu_init(COAP_MESSAGE_ACK, - COAP_RESPONSE_CODE(205), - 0, 1152); - if (response) { - /* Use fuzzer input to control response parameters */ - uint16_t media_type = ((uint16_t)data[4] << 8) | data[5]; - int maxage = (int)data[6]; - size_t resp_len = (size > 8) ? (size - 8) : 0; - const uint8_t *resp_data = (size > 8) ? &data[8] : data; - - /* Test coap_add_data_blocked_response() */ - coap_add_data_blocked_response(pdu, response, - media_type, maxage, - resp_len, resp_data); - coap_delete_pdu(response); - } - } - coap_delete_pdu(pdu); + /* Process datagram */ + size_t dgram_len = size - 4; + dgram = (uint8_t *)malloc(dgram_len); + if (dgram) { + memcpy(dgram, data + 4, dgram_len); + coap_handle_dgram(ctx, session, dgram, dgram_len); + free(dgram); } cleanup: