add fuzzer and cram based unit tests

For improved QA etc.

Signed-off-by: Petr Štetiar <ynezz@true.cz>
This commit is contained in:
Petr Štetiar 2019-12-12 23:24:15 +01:00
parent c413be9b37
commit 08f17c87a0
26 changed files with 198 additions and 0 deletions

View file

@ -41,6 +41,15 @@ TARGET_LINK_LIBRARIES(ubus ${ubox_library})
find_library(json NAMES json-c json)
MACRO(ADD_UNIT_TEST_SAN name output_name)
ADD_EXECUTABLE(${name}-san ${name}.c)
TARGET_COMPILE_OPTIONS(${name}-san PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined,address,leak -fno-sanitize-recover=all)
TARGET_LINK_OPTIONS(${name}-san PRIVATE -fsanitize=undefined,address,leak)
TARGET_LINK_LIBRARIES(${name}-san ubus ubusd_library ${ubox_library} ${blob_library} ${json})
TARGET_INCLUDE_DIRECTORIES(${name}-san PRIVATE ${PROJECT_SOURCE_DIR})
SET_TARGET_PROPERTIES(${name}-san PROPERTIES OUTPUT_NAME ${output_name})
ENDMACRO(ADD_UNIT_TEST_SAN)
ADD_LIBRARY(ubusd_library STATIC ubusd.c ubusd_proto.c ubusd_id.c ubusd_obj.c ubusd_event.c ubusd_acl.c ubusd_monitor.c)
ADD_EXECUTABLE(ubusd ubusd_main.c)
TARGET_LINK_LIBRARIES(ubusd ubusd_library ${ubox_library} ${blob_library} ${json})
@ -52,6 +61,13 @@ TARGET_LINK_LIBRARIES(cli ubus ${ubox_library} ${blob_library} ${json})
ADD_SUBDIRECTORY(lua)
ADD_SUBDIRECTORY(examples)
IF(UNIT_TESTING)
ENABLE_TESTING()
ADD_SUBDIRECTORY(tests)
ADD_UNIT_TEST_SAN(cli ubus-san)
ADD_UNIT_TEST_SAN(ubusd_main ubusd-san)
ENDIF()
INSTALL(TARGETS ubus cli
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib

18
tests/CMakeLists.txt Normal file
View file

@ -0,0 +1,18 @@
ADD_SUBDIRECTORY(cram)
MACRO(ADD_UNIT_TEST name)
ADD_EXECUTABLE(${name} ${name}.c)
TARGET_LINK_LIBRARIES(${name} ubox blobmsg_json json_script ${json})
TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR})
ENDMACRO(ADD_UNIT_TEST)
FILE(GLOB test_cases "test-*.c")
FOREACH(test_case ${test_cases})
GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE)
ADD_UNIT_TEST(${test_case})
ADD_UNIT_TEST_SAN(${test_case})
ENDFOREACH(test_case)
IF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
ADD_SUBDIRECTORY(fuzz)
ENDIF()

22
tests/cram/CMakeLists.txt Normal file
View file

@ -0,0 +1,22 @@
FIND_PACKAGE(PythonInterp 3 REQUIRED)
FILE(GLOB test_cases "test_*.t")
SET(PYTHON_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/.venv")
SET(PYTHON_VENV_PIP "${PYTHON_VENV_DIR}/bin/pip")
SET(PYTHON_VENV_CRAM "${PYTHON_VENV_DIR}/bin/cram")
ADD_CUSTOM_COMMAND(
OUTPUT ${PYTHON_VENV_CRAM}
COMMAND ${PYTHON_EXECUTABLE} -m venv ${PYTHON_VENV_DIR}
COMMAND ${PYTHON_VENV_PIP} install cram
)
ADD_CUSTOM_TARGET(prepare-cram-venv ALL DEPENDS ${PYTHON_VENV_CRAM})
ADD_TEST(
NAME cram
COMMAND ${PYTHON_VENV_CRAM} ${test_cases}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
SET_PROPERTY(TEST cram APPEND PROPERTY ENVIRONMENT "UBUS=$<TARGET_FILE:ubus>")
SET_PROPERTY(TEST cram APPEND PROPERTY ENVIRONMENT "TEST_BIN_DIR=$<TARGET_FILE_DIR:ubus>")

58
tests/cram/test_ubus.t Normal file
View file

@ -0,0 +1,58 @@
set environment for convenience:
$ [ -n "$TEST_BIN_DIR" ] && export PATH="$TEST_BIN_DIR:$PATH"
$ alias ubus='valgrind --quiet --leak-check=full ubus'
check usage:
$ ubus
Usage: ubus [<options>] <command> [arguments...]
Options:
-s <socket>:\t\tSet the unix domain socket to connect to (esc)
-t <timeout>:\t\tSet the timeout (in seconds) for a command to complete (esc)
-S:\t\t\tUse simplified output (for scripts) (esc)
-v:\t\t\tMore verbose output (esc)
-m <type>:\t\t(for monitor): include a specific message type (esc)
\t\t\t(can be used more than once) (esc)
-M <r|t>\t\t(for monitor): only capture received or transmitted traffic (esc)
Commands:
- list [<path>]\t\t\tList objects (esc)
- call <path> <method> [<message>]\tCall an object method (esc)
- listen [<path>...]\t\t\tListen for events (esc)
- send <type> [<message>]\t\tSend an event (esc)
- wait_for <object> [<object>...]\tWait for multiple objects to appear on ubus (esc)
- monitor\t\t\t\tMonitor ubus traffic (esc)
[1]
$ ubus-san
Usage: ubus-san [<options>] <command> [arguments...]
Options:
-s <socket>:\t\tSet the unix domain socket to connect to (esc)
-t <timeout>:\t\tSet the timeout (in seconds) for a command to complete (esc)
-S:\t\t\tUse simplified output (for scripts) (esc)
-v:\t\t\tMore verbose output (esc)
-m <type>:\t\t(for monitor): include a specific message type (esc)
\t\t\t(can be used more than once) (esc)
-M <r|t>\t\t(for monitor): only capture received or transmitted traffic (esc)
Commands:
- list [<path>]\t\t\tList objects (esc)
- call <path> <method> [<message>]\tCall an object method (esc)
- listen [<path>...]\t\t\tListen for events (esc)
- send <type> [<message>]\t\tSend an event (esc)
- wait_for <object> [<object>...]\tWait for multiple objects to appear on ubus (esc)
- monitor\t\t\t\tMonitor ubus traffic (esc)
[1]
check monitor command:
$ ubus monitor
Failed to connect to ubus
[255]
$ ubus-san monitor
Failed to connect to ubus
[255]

24
tests/cram/test_ubusd.t Normal file
View file

@ -0,0 +1,24 @@
set environment for convenience:
$ [ -n "$TEST_BIN_DIR" ] && export PATH="$TEST_BIN_DIR:$PATH"
$ alias ubusd='valgrind --quiet --leak-check=full ubusd'
check usage:
$ ubusd -h
ubusd: invalid option -- 'h'
Usage: ubusd [<options>]
Options:
-A <path>:\t\tSet the path to ACL files (esc)
-s <socket>:\t\tSet the unix domain socket to listen on (esc)
[1]
$ ubusd-san -h
ubusd-san: invalid option -- 'h'
Usage: ubusd-san [<options>]
Options:
-A <path>:\t\tSet the path to ACL files (esc)
-s <socket>:\t\tSet the unix domain socket to listen on (esc)
[1]

18
tests/fuzz/CMakeLists.txt Normal file
View file

@ -0,0 +1,18 @@
FILE(GLOB test_cases "test-*.c")
MACRO(ADD_FUZZER_TEST name)
ADD_EXECUTABLE(${name} ${name}.c)
TARGET_COMPILE_OPTIONS(${name} PRIVATE -g -O1 -fno-omit-frame-pointer -fsanitize=fuzzer,address,leak,undefined)
TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR})
TARGET_LINK_OPTIONS(${name} PRIVATE -stdlib=libc++ -fsanitize=fuzzer,address,leak,undefined)
TARGET_LINK_LIBRARIES(${name} ubus ubusd_library ${ubox_library} ${blob_library} ${json})
ADD_TEST(
NAME ${name}
COMMAND ${name} -max_len=256 -timeout=10 -max_total_time=300 ${CMAKE_CURRENT_SOURCE_DIR}/corpus
)
ENDMACRO(ADD_FUZZER_TEST)
FOREACH(test_case ${test_cases})
GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE)
ADD_FUZZER_TEST(${test_case})
ENDFOREACH(test_case)

View file

@ -0,0 +1 @@
6

View file

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

40
tests/fuzz/test-fuzz.c Normal file
View file

@ -0,0 +1,40 @@
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <libubox/blob.h>
#include <libubox/blobmsg.h>
#include "ubusmsg.h"
#include "libubus.h"
#include "libubus-internal.h"
static void _ubus_validate_hdr(const uint8_t *data, size_t size)
{
if (size > sizeof(struct ubus_msghdr))
return;
ubus_validate_hdr((struct ubus_msghdr *) data);
}
static void _ubus_parse_msg(const uint8_t *data, size_t size)
{
struct blob_attr *attr = (struct blob_attr *) data;
if (size < sizeof(struct blob_attr *))
return;
if (blob_pad_len(attr) > UBUS_MAX_MSGLEN)
return;
ubus_parse_msg(attr);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
_ubus_validate_hdr(data, size);
_ubus_parse_msg(data, size);
return 0;
}