Fuzz: Add fuzzers to allow packet handling to get greater coverage

This commit is contained in:
Roger A. Light
2024-11-20 11:02:39 +00:00
parent b9e1c5e64c
commit 02442238cb
10 changed files with 432 additions and 66 deletions
+6
View File
@@ -53,6 +53,11 @@ fuzzing/apps/db_dump/db_dump_fuzz_load_client_stats
fuzzing/apps/db_dump/db_dump_fuzz_load_stats
fuzzing/apps/mosquitto_passwd/mosquitto_passwd_fuzz_load
fuzzing/broker/broker_fuzz_acl_file
fuzzing/broker/broker_fuzz_handle_auth
fuzzing/broker/broker_fuzz_handle_connect
fuzzing/broker/broker_fuzz_handle_publish
fuzzing/broker/broker_fuzz_handle_subscribe
fuzzing/broker/broker_fuzz_handle_unsubscribe
fuzzing/broker/broker_fuzz_initial_packet
fuzzing/broker/broker_fuzz_initial_packet_with_init
fuzzing/broker/broker_fuzz_password_file
@@ -62,6 +67,7 @@ fuzzing/broker/broker_fuzz_read_handle
fuzzing/broker/broker_fuzz_second_packet
fuzzing/broker/broker_fuzz_second_packet_with_init
fuzzing/broker/broker_fuzz_test_config
fuzzing/corpora/broker/*
fuzzing/corpora/broker_packet_seed_corpus.zip
fuzzing/corpora/client/*
+18 -4
View File
@@ -19,7 +19,21 @@ LOCAL_CXXFLAGS+=-g -Wall -Werror -pthread
LOCAL_LDFLAGS+=
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/src/mosquitto_broker.a -lssl -lcrypto -lcjson -lm ${R}/libcommon/libmosquitto_common.a -Wl,-Bdynamic -Wl,-Bstatic -largon2 -Wl,-Bdynamic
all: $(FUZZERS)
PACKET_FUZZERS:= \
broker_fuzz_handle_auth \
broker_fuzz_handle_connect \
broker_fuzz_handle_publish \
broker_fuzz_handle_subscribe \
broker_fuzz_handle_unsubscribe
all: $(FUZZERS) $(PACKET_FUZZERS)
${PACKET_FUZZERS} : %: %.cpp fuzz_packet_read_base.o ${R}/src/mosquitto_broker.a
$(CXX) $(LOCAL_CXXFLAGS) $(LOCAL_CPPFLAGS) $(LOCAL_LDFLAGS) -o $@ $< fuzz_packet_read_base.o $(LOCAL_LIBADD)
install $@ ${OUT}/$@
fuzz_packet_read_base.o : fuzz_packet_read_base.c
$(CC) $(LOCAL_CXXFLAGS) $(LOCAL_CPPFLAGS) -c -o $@ $<
broker_fuzz_acl_file : broker_fuzz_acl_file.cpp ${R}/src/mosquitto_broker.a
$(CXX) $(LOCAL_CXXFLAGS) $(LOCAL_CPPFLAGS) $(LOCAL_LDFLAGS) -o $@ $< $(LOCAL_LIBADD)
@@ -42,8 +56,8 @@ broker_fuzz_queue_msg : broker_fuzz_queue_msg.cpp ${R}/src/mosquitto_broker.a
install $@ ${OUT}/$@
cp ${R}/fuzzing/corpora/broker_queue_msg_seed_corpus.zip ${OUT}/$@_seed_corpus.zip
broker_fuzz_read_handle : broker_fuzz_read_handle.cpp ${R}/src/mosquitto_broker.a
$(CXX) $(LOCAL_CXXFLAGS) $(LOCAL_CPPFLAGS) $(LOCAL_LDFLAGS) -o $@ $< $(LOCAL_LIBADD)
broker_fuzz_read_handle : broker_fuzz_read_handle.cpp fuzz_packet_read_base.o ${R}/src/mosquitto_broker.a
$(CXX) $(LOCAL_CXXFLAGS) $(LOCAL_CPPFLAGS) $(LOCAL_LDFLAGS) -o $@ $^ $(LOCAL_LIBADD)
install $@ ${OUT}/$@
cp ${R}/fuzzing/corpora/broker_packet_seed_corpus.zip ${OUT}/$@_seed_corpus.zip
@@ -54,4 +68,4 @@ broker_fuzz_test_config : broker_fuzz_test_config.cpp ${R}/src/mosquitto_broker.
cp ${R}/fuzzing/corpora/broker_conf.dict ${OUT}/$@.dict
clean:
rm -f *.o $(FUZZERS)
rm -f *.o $(FUZZERS) $(PACKET_FUZZERS)
@@ -0,0 +1,38 @@
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "fuzz_packet_read_base.h"
extern "C" int fuzz_packet_read_init(struct mosquitto *context)
{
context->protocol = mosq_p_mqtt5;
context->auth_method = strdup("FUZZ");
return !context->auth_method;
}
extern "C" void fuzz_packet_read_cleanup(struct mosquitto *context)
{
free(context->auth_method);
context->auth_method = NULL;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
int rc = fuzz_packet_read_base(data, size, handle__auth);
return rc;
}
@@ -0,0 +1,59 @@
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "fuzz_packet_read_base.h"
extern "C" int fuzz_basic_auth(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_basic_auth *ed = (struct mosquitto_evt_basic_auth *)event_data;
/* This is a check that is ultimately determined by the fuzz input data, so
* the fuzzer can discover how to access both the fail/success cases.
*/
if(ed->client->id && (ed->client->id[0]%2 == 0)){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
}
}
extern "C" int fuzz_packet_read_init(struct mosquitto *context)
{
context->listener->security_options->pid = (mosquitto_plugin_id_t *)calloc(1, sizeof(mosquitto_plugin_id_t));
if(!context->listener->security_options->pid){
return 1;
}
mosquitto_callback_register(context->listener->security_options->pid,
MOSQ_EVT_BASIC_AUTH, fuzz_basic_auth, NULL, NULL);
return 0;
}
extern "C" void fuzz_packet_read_cleanup(struct mosquitto *context)
{
mosquitto_callback_unregister(context->listener->security_options->pid,
MOSQ_EVT_BASIC_AUTH, fuzz_basic_auth, NULL);
free(context->listener->security_options->pid);
context->listener->security_options->pid = NULL;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
return fuzz_packet_read_base(data, size, handle__connect);
}
@@ -0,0 +1,59 @@
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "fuzz_packet_read_base.h"
extern "C" int fuzz_acl_check(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_acl_check *ed = (struct mosquitto_evt_acl_check *)event_data;
/* This is a check that is ultimately determined by the fuzz input data, so
* the fuzzer can discover how to access both the fail/success cases.
*/
if(ed->topic && (ed->topic[0]%2 == 0)){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
}
}
extern "C" int fuzz_packet_read_init(struct mosquitto *context)
{
context->listener->security_options->pid = (mosquitto_plugin_id_t *)calloc(1, sizeof(mosquitto_plugin_id_t));
if(!context->listener->security_options->pid){
return 1;
}
mosquitto_callback_register(context->listener->security_options->pid,
MOSQ_EVT_ACL_CHECK, fuzz_acl_check, NULL, NULL);
return 0;
}
extern "C" void fuzz_packet_read_cleanup(struct mosquitto *context)
{
mosquitto_callback_unregister(context->listener->security_options->pid,
MOSQ_EVT_ACL_CHECK, fuzz_acl_check, NULL);
free(context->listener->security_options->pid);
context->listener->security_options->pid = NULL;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
return fuzz_packet_read_base(data, size, handle__publish);
}
@@ -0,0 +1,59 @@
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "fuzz_packet_read_base.h"
extern "C" int fuzz_acl_check(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_acl_check *ed = (struct mosquitto_evt_acl_check *)event_data;
/* This is a check that is ultimately determined by the fuzz input data, so
* the fuzzer can discover how to access both the fail/success cases.
*/
if(ed->topic && (ed->topic[0]%2 == 0)){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
}
}
extern "C" int fuzz_packet_read_init(struct mosquitto *context)
{
context->listener->security_options->pid = (mosquitto_plugin_id_t *)calloc(1, sizeof(mosquitto_plugin_id_t));
if(!context->listener->security_options->pid){
return 1;
}
mosquitto_callback_register(context->listener->security_options->pid,
MOSQ_EVT_ACL_CHECK, fuzz_acl_check, NULL, NULL);
return 0;
}
extern "C" void fuzz_packet_read_cleanup(struct mosquitto *context)
{
mosquitto_callback_unregister(context->listener->security_options->pid,
MOSQ_EVT_ACL_CHECK, fuzz_acl_check, NULL);
free(context->listener->security_options->pid);
context->listener->security_options->pid = NULL;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
return fuzz_packet_read_base(data, size, handle__subscribe);
}
@@ -0,0 +1,59 @@
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "fuzz_packet_read_base.h"
extern "C" int fuzz_acl_check(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_acl_check *ed = (struct mosquitto_evt_acl_check *)event_data;
/* This is a check that is ultimately determined by the fuzz input data, so
* the fuzzer can discover how to access both the fail/success cases.
*/
if(ed->topic && (ed->topic[0]%2 == 0)){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
}
}
extern "C" int fuzz_packet_read_init(struct mosquitto *context)
{
context->listener->security_options->pid = (mosquitto_plugin_id_t *)calloc(1, sizeof(mosquitto_plugin_id_t));
if(!context->listener->security_options->pid){
return 1;
}
mosquitto_callback_register(context->listener->security_options->pid,
MOSQ_EVT_ACL_CHECK, fuzz_acl_check, NULL, NULL);
return 0;
}
extern "C" void fuzz_packet_read_cleanup(struct mosquitto *context)
{
mosquitto_callback_unregister(context->listener->security_options->pid,
MOSQ_EVT_ACL_CHECK, fuzz_acl_check, NULL);
free(context->listener->security_options->pid);
context->listener->security_options->pid = NULL;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
return fuzz_packet_read_base(data, size, handle__unsubscribe);
}
+8 -62
View File
@@ -16,72 +16,18 @@ Contributors:
Roger Light - initial implementation and documentation.
*/
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include "fuzz_packet_read_base.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "mosquitto_broker_internal.h"
#include "mosquitto_internal.h"
#ifdef __cplusplus
extern "C" int fuzz_packet_read_init(struct mosquitto *context)
{
return 0;
}
#endif
#define kMinInputLength 3
#define kMaxInputLength 268435455U
extern "C" void fuzz_packet_read_cleanup(struct mosquitto *context)
{
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
struct mosquitto *context = NULL;
uint8_t *data_heap;
struct mosquitto__listener listener;
struct mosquitto__security_options secopts;
struct mosquitto__bridge bridge;
if(size < kMinInputLength || size > kMaxInputLength){
return 0;
}
db.config = (struct mosquitto__config *)calloc(1, sizeof(struct mosquitto__config));
log__init(db.config);
memset(&listener, 0, sizeof(listener));
memset(&bridge, 0, sizeof(bridge));
memset(&secopts, 0, sizeof(secopts));
context = context__init();
if(!context) return 1;
listener.security_options = &secopts;
context->listener = &listener;
context->bridge = &bridge;
context->state = (enum mosquitto_client_state )data[0];
context->protocol = (enum mosquitto__protocol )data[1];
size -= 2;
data_heap = (uint8_t *)malloc(size);
if(!data_heap) return 1;
memcpy(data_heap, &data[2], size);
context->in_packet.command = data_heap[0];
context->in_packet.payload = (uint8_t *)data_heap;
context->in_packet.packet_length = (uint32_t )size; /* Safe cast, because we've already limited the size */
context->in_packet.remaining_length = (uint32_t )(size-1);
context->in_packet.pos = 1;
handle__packet(context);
context->bridge = NULL;
context__cleanup(context, true);
free(db.config);
return 0;
return fuzz_packet_read_base(data, size, handle__packet);
}
+85
View File
@@ -0,0 +1,85 @@
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "fuzz_packet_read_base.h"
#include "mosquitto_broker_internal.h"
#include "mosquitto_internal.h"
#define kMinInputLength 3
#define kMaxInputLength 268435455U
int fuzz_packet_read_base(const uint8_t *data, size_t size, int (*packet_func)(struct mosquitto *))
{
struct mosquitto *context = NULL;
uint8_t *data_heap;
struct mosquitto__listener listener;
struct mosquitto__security_options secopts;
struct mosquitto__bridge bridge;
if(size < kMinInputLength || size > kMaxInputLength){
return 0;
}
db.config = (struct mosquitto__config *)calloc(1, sizeof(struct mosquitto__config));
log__init(db.config);
memset(&listener, 0, sizeof(listener));
memset(&bridge, 0, sizeof(bridge));
memset(&secopts, 0, sizeof(secopts));
context = context__init();
if(!context) return 1;
listener.security_options = &secopts;
context->listener = &listener;
context->bridge = &bridge;
context->state = (enum mosquitto_client_state )data[0];
context->protocol = (enum mosquitto__protocol )data[1];
size -= 2;
data_heap = (uint8_t *)malloc(size);
if(!data_heap) return 1;
memcpy(data_heap, &data[2], size);
context->in_packet.command = data_heap[0];
context->in_packet.payload = (uint8_t *)data_heap;
context->in_packet.packet_length = (uint32_t )size; /* Safe cast, because we've already limited the size */
context->in_packet.remaining_length = (uint32_t )(size-1);
context->in_packet.pos = 1;
if(fuzz_packet_read_init(context)){
return 1;
}
packet_func(context);
fuzz_packet_read_cleanup(context);
context->bridge = NULL;
context__cleanup(context, true);
free(db.config);
return 0;
}
#ifdef __cplusplus
}
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef FUZZ_PACKET_READ_BASE_H
/*
Copyright (c) 2023 Cedalo GmbH
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "mosquitto_broker_internal.h"
#include "mosquitto_internal.h"
#include "read_handle.h"
#define kMinInputLength 3
#define kMaxInputLength 268435455U
int fuzz_packet_read_base(const uint8_t *data, size_t size, int (*packet_func)(struct mosquitto *));
int fuzz_packet_read_init(struct mosquitto *context);
void fuzz_packet_read_cleanup(struct mosquitto *context);
#ifdef __cplusplus
}
#endif
#endif