Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gardena/lw/fuzzing #720

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions .cmake-format
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,16 @@ with section("format"):
with section("markup"):
# What character to use for bulleted lists
bullet_char = '-'

additional_commands = {
"add_fuzzing_test": {
"kwargs": {
"TARGET_NAME": '*',
"SOURCE_FILES": '*',
"COMPILE_DEFINITIONS": '*',
"CORPUS_DIRS": '*',
"MAX_LEN": '*',
"CRASH_FILES_DIR": '*',
}
}
}
3 changes: 1 addition & 2 deletions core/registration.c
Original file line number Diff line number Diff line change
Expand Up @@ -1604,8 +1604,7 @@ static int prv_getId(uint8_t * data,
}
// Ignore any unrecognized attribute
}
if (data[limit] == REG_ATTR_SEPARATOR)
{
if (limit < length && data[limit] == REG_ATTR_SEPARATOR) {
limit += 1;
}
data += limit;
Expand Down
3 changes: 3 additions & 0 deletions core/uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ static int prv_parseNumber(uint8_t * uriString,
{
result *= 10;
result += uriString[*headP] - '0';
if (result > LWM2M_MAX_ID) {
return -1;
}
}
else
{
Expand Down
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ endif()

# Add our unit tests to the "test" target
add_test(NAME lwm2munittests_test COMMAND lwm2munittests)

add_subdirectory(fuzzing)
8 changes: 8 additions & 0 deletions tests/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.13)

project(fuzzing_tests C)

include(Fuzzing.cmake)

add_subdirectory(coap_parse_message)
add_subdirectory(registration_handleRequest)
81 changes: 81 additions & 0 deletions tests/fuzzing/Fuzzing.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(FUZZING_MAX_TOTAL_TIME
180
CACHE STRING "Maximal time (seconds) to run one fuzzing test"
)

add_custom_target(run_all_fuzzing_tests COMMENT "Run all fuzzing tests")
add_custom_target(run_all_fuzzing_reg_tests COMMENT "Run all fuzzing regression tests")

# ! add_fuzzing_test : Add a fuzzing test that uses `libfuzzer`
# ~~~
# TARGET_NAME: The name of the test
# SOURCE_FILES: A list with all source files needed for the test
# COMPILE_DEFINITIONS (optional): Compile definitions for the target
# CORPUS_DIRS (optional): A list with directories containing corpora for initializing the test runs
# MAX_LEN (optional): Maximum size (bytes) of generated test input
# CRASH_FILES_DIR (optional): Directory containing crash files for regression tests
# ~~~
function(add_fuzzing_test)

set(oneValueArgs TARGET_NAME MAX_LEN CRASH_FILES_DIR)
set(multiValueArgs SOURCE_FILES CORPUS_DIRS COMPILE_DEFINITIONS)
cmake_parse_arguments(FUZZING "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

add_executable(${FUZZING_TARGET_NAME})
target_sources(${FUZZING_TARGET_NAME} PRIVATE ${FUZZING_SOURCE_FILES})
target_compile_definitions(${FUZZING_TARGET_NAME} PRIVATE ${FUZZING_COMPILE_DEFINITIONS})

target_include_directories(
${FUZZING_TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/coap ${CMAKE_SOURCE_DIR}/core
${CMAKE_SOURCE_DIR}/include
)

target_compile_options(
${FUZZING_TARGET_NAME} PRIVATE -O1 -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=all
)
target_link_options(
${FUZZING_TARGET_NAME} PRIVATE -O1 -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=all
)

set(max_len 65535)
if(FUZZING_MAX_LEN)
set(max_len ${FUZZING_MAX_LEN})
endif()

set(run_target run_${FUZZING_TARGET_NAME}_fuzzing)
add_custom_target(
${run_target}
COMMAND ${FUZZING_TARGET_NAME} -max_total_time=${FUZZING_MAX_TOTAL_TIME} -max_len=${max_len}
-artifact_prefix=${CMAKE_CURRENT_LIST_DIR}/ ${FUZZING_CORPUS_DIRS}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
COMMENT "Run a fuzzing test"
)
add_dependencies(${run_target} ${FUZZING_TARGET_NAME})
add_dependencies(run_all_fuzzing_tests ${run_target})

if(FUZZING_CRASH_FILES_DIR)
set(reg_test_target run_${FUZZING_TARGET_NAME}_fuzzing_reg_test)
file(
GLOB_RECURSE CRASH_FILES
LIST_DIRECTORIES false
CONFIGURE_DEPENDS "${FUZZING_CRASH_FILES_DIR}/*"
)
add_custom_target(
${reg_test_target}
COMMAND ${FUZZING_TARGET_NAME} -artifact_prefix=${CMAKE_CURRENT_LIST_DIR}/ ${CRASH_FILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
COMMENT "Run fuzzing regression test"
)
add_dependencies(${reg_test_target} ${FUZZING_TARGET_NAME})
add_dependencies(run_all_fuzzing_reg_tests ${reg_test_target})

endif()
endfunction()
else()
# ! add_fuzzing_test : Dummy function that does nothing. This is needed when not compiling with `clang` and
# therefore `libfuzzer` is not available.
function(add_fuzzing_test)
# do nothing if we are not using clang
endfunction()
endif()
5 changes: 5 additions & 0 deletions tests/fuzzing/coap_parse_message/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_fuzzing_test(
TARGET_NAME fuz_coap_parse_message
SOURCE_FILES fuz_coap_parse_message.c ${CMAKE_SOURCE_DIR}/coap/er-coap-13/er-coap-13.c
${CMAKE_SOURCE_DIR}/examples/shared/platform.c
)
38 changes: 38 additions & 0 deletions tests/fuzzing/coap_parse_message/fuz_coap_parse_message.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*******************************************************************************
*
* Copyright (c) 2023 GARDENA GmbH
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Lukas Woodtli, GARDENA GmbH - Please refer to git log
*
*******************************************************************************/

#include "er-coap-13/er-coap-13.h"

#include <stdint.h>
#include <string.h>

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (0 >= size || size > UINT16_MAX) {
return 0;
}

uint8_t non_const_data[size];
memcpy(non_const_data, data, size);

coap_packet_t coap_pkt;
memset(&coap_pkt, 0, sizeof(coap_packet_t));
coap_parse_message(&coap_pkt, non_const_data, (uint16_t)size);
coap_free_header(&coap_pkt);

return 0;
}
18 changes: 18 additions & 0 deletions tests/fuzzing/registration_handleRequest/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
add_fuzzing_test(
TARGET_NAME fuz_registration_handleRequest
SOURCE_FILES
fuz_registration_handleRequest.c
${CMAKE_SOURCE_DIR}/core/registration.c
${CMAKE_SOURCE_DIR}/core/list.c
${CMAKE_SOURCE_DIR}/core/utils.c
${CMAKE_SOURCE_DIR}/core/uri.c
${CMAKE_SOURCE_DIR}/core/observe.c
${CMAKE_SOURCE_DIR}/core/liblwm2m.c
${CMAKE_SOURCE_DIR}/core/packet.c
${CMAKE_SOURCE_DIR}/coap/er-coap-13/er-coap-13.c
${CMAKE_SOURCE_DIR}/coap/block.c
${CMAKE_SOURCE_DIR}/coap/transaction.c
${CMAKE_SOURCE_DIR}/examples/shared/platform.c
COMPILE_DEFINITIONS LWM2M_SERVER_MODE LWM2M_COAP_DEFAULT_BLOCK_SIZE=64
CRASH_FILES_DIR crash_files/
)
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
</37777777777>/>/
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
*
* Copyright (c) 2023 GARDENA GmbH
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Lukas Woodtli, GARDENA GmbH - Please refer to git log
*
*******************************************************************************/

#include "er-coap-13/er-coap-13.h"

#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "internals.h"
#include "liblwm2m.h"

bool lwm2m_session_is_equal(void *session1, void *session2, void *userData) {
(void)userData;

return (session1 == session2);
}

uint8_t lwm2m_buffer_send(void *sessionH, uint8_t *buffer, size_t length, void *userdata) {
(void)sessionH;
(void)buffer;
(void)length;
(void)userdata;

return COAP_NO_ERROR;
}

static void init_test_packet(coap_packet_t *message, const char *registration_message, uint8_t *payload,
const size_t payload_len) {

memset(message, 0, sizeof(coap_packet_t));
message->code = COAP_POST;
coap_set_header_uri_query(message, "lwm2m=1.1&ep=abc");

memcpy(payload, registration_message, payload_len);
message->payload = payload;
message->payload_len = payload_len;

message->content_type = (coap_content_type_t)LWM2M_CONTENT_LINK;
}

void init_uri(lwm2m_uri_t *const uri) {
memset(uri, 0, sizeof(*uri));
uri->objectId = LWM2M_MAX_ID;
}

static int call_test_function(const char *reg_msg, const size_t reg_msg_len) {
int ret;

uint8_t user_data[1] = {0};
lwm2m_context_t *context = lwm2m_init(user_data);

lwm2m_uri_t uri;
init_uri(&uri);
coap_packet_t message;

uint8_t payload[reg_msg_len == 0 ? 1 : reg_msg_len];
init_test_packet(&message, reg_msg, payload, reg_msg_len);

coap_packet_t response;
memset(&response, 0, sizeof(coap_packet_t));

ret = registration_handleRequest(context, &uri, NULL, &message, &response);

free_multi_option(message.uri_query);
free_multi_option(response.location_path);

lwm2m_close(context);

return ret;
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {

call_test_function((const char *)data, size);

return 0;
}