Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,16 @@ if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
source_format_enable(0.77)
endif()

if(ENABLE_FUZZ_TARGETS)
set(FUZZER "AFL" CACHE STRING "fuzzer type")
if(FUZZER STREQUAL "LibFuzzer")
if (NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
message(FATAL_ERROR "LibFuzzer works only with clang")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
endif()
endif()

# check regex compatibility
check_include_file("regex.h" LY_HAVE_REGEX_H)
if(LY_HAVE_REGEX_H)
Expand Down Expand Up @@ -498,16 +508,8 @@ endif()
if(ENABLE_TESTS)
enable_testing()
add_subdirectory(tests)
endif()

if(ENABLE_FUZZ_TARGETS)
set(FUZZER "AFL" CACHE STRING "fuzzer type")
if(FUZZER STREQUAL "LibFuzzer")
if (NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
message(FATAL_ERROR "LibFuzzer works only with clang")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
endif()
elseif(ENABLE_FUZZ_TARGETS AND NOT WIN32)
add_subdirectory(tests/fuzz)
endif()

# create coverage target for generating coverage reports
Expand Down
8 changes: 4 additions & 4 deletions tests/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
if(ENABLE_FUZZ_TARGETS)
set(fuzz_targets lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json yang_parse_module)
set(fuzz_targets lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json lyd_parse_lyb lyd_parse_schema_mount_xml yang_parse_module)

if(FUZZER STREQUAL "AFL")
foreach(target_name IN LISTS fuzz_targets)
Expand All @@ -9,15 +9,15 @@ if(ENABLE_FUZZ_TARGETS)
else()
foreach(target_name IN LISTS fuzz_targets)
add_executable(${target_name}_fuzz_harness ${target_name}.c)
set_source_files_properties(${target_name}.c PROPERTIES COMPILE_FLAGS "-fsanitize=fuzzer")
target_link_libraries(${target_name}_fuzz_harness yang "-fsanitize=fuzzer")
set_source_files_properties(${target_name}.c PROPERTIES COMPILE_FLAGS "-fsanitize=fuzzer,address,undefined")
target_link_libraries(${target_name}_fuzz_harness yang "-fsanitize=fuzzer,address,undefined")
endforeach()
endif()
endif()

if(ENABLE_TESTS)
add_executable(fuzz_regression_test fuzz_regression_test.c)
set(fuzz_regression_tests lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json)
set(fuzz_regression_tests lys_parse_mem lyd_parse_mem_xml lyd_parse_mem_json lyd_parse_schema_mount_xml)
foreach(target_name IN LISTS fuzz_regression_tests)
file(COPY ${CMAKE_SOURCE_DIR}/tests/fuzz/corpus/${target_name} DESTINATION ${CMAKE_BINARY_DIR}/tests/fuzz/)
add_executable(regress_fuzz_${target_name} ${target_name}.c main.c)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<root xmlns="urn:tests:fuzz-sm"><lfl xmlns="urn:tests:fuzz-sm-leaf">1</lfl></root>
56 changes: 56 additions & 0 deletions tests/fuzz/lyd_parse_lyb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>

#include "libyang.h"

int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
struct ly_ctx *ctx = NULL;
struct lyd_node *tree = NULL;
FILE *input = NULL;
static bool log = false;
const char *schema =
"module fuzz-lyb {namespace urn:tests:fuzz-lyb;prefix fl;"
"container c {leaf s {type string;} leaf u16 {type uint16;}"
"leaf-list bits {type bits {bit zero; bit one;}}}}";

if (!log) {
ly_log_options(0);
log = true;
}

if (ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx) != LY_SUCCESS) {
return 0;
}

if (lys_parse_mem(ctx, schema, LYS_IN_YANG, NULL) != LY_SUCCESS) {
goto cleanup;
}

input = tmpfile();
if (!input) {
goto cleanup;
}

if (len && (fwrite(buf, 1, len, input) != len)) {
goto cleanup;
}
fflush(input);
if (lseek(fileno(input), 0, SEEK_SET) == -1) {
goto cleanup;
}

lyd_parse_data_fd(ctx, fileno(input), LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree);

cleanup:
lyd_free_all(tree);
if (input) {
fclose(input);
}
ly_ctx_destroy(ctx);
return 0;
}
7 changes: 4 additions & 3 deletions tests/fuzz/lyd_parse_mem_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,22 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)

err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
if (err != LY_SUCCESS) {
fprintf(stderr, "Failed to create context\n");
exit(EXIT_FAILURE);
return 0;
}

lys_parse_mem(ctx, schema_a, LYS_IN_YANG, NULL);
lys_parse_mem(ctx, schema_b, LYS_IN_YANG, NULL);

data = malloc(len + 1);
if (data == NULL) {
return 0;
goto cleanup;
}
memcpy(data, buf, len);
data[len] = 0;

lyd_parse_data_mem(ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree);

cleanup:
lyd_free_all(tree);
ly_ctx_destroy(ctx);

Expand Down
7 changes: 4 additions & 3 deletions tests/fuzz/lyd_parse_mem_xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,22 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)

err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
if (err != LY_SUCCESS) {
fprintf(stderr, "Failed to create context\n");
exit(EXIT_FAILURE);
return 0;
}

lys_parse_mem(ctx, schema_a, LYS_IN_YANG, NULL);
lys_parse_mem(ctx, schema_b, LYS_IN_YANG, NULL);

data = malloc(len + 1);
if (data == NULL) {
return 0;
goto cleanup;
}
memcpy(data, buf, len);
data[len] = 0;

lyd_parse_data_mem(ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree);

cleanup:
lyd_free_all(tree);
ly_ctx_destroy(ctx);

Expand Down
170 changes: 170 additions & 0 deletions tests/fuzz/lyd_parse_schema_mount_xml.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>

#include "libyang.h"

static const char mounted_module[] =
"module fuzz-sm-leaf {"
"namespace \"urn:tests:fuzz-sm-leaf\";"
"prefix fsl;"
"leaf lfl {type uint16;}"
"leaf txt {type string;}"
"}";

static const char mount_module[] =
"module fuzz-sm {"
"yang-version 1.1;"
"namespace \"urn:tests:fuzz-sm\";"
"prefix fsm;"
"import ietf-yang-schema-mount {prefix sm;}"
"container root {sm:mount-point \"root\";}"
"}";

static const char ext_data_xml[] =
"<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
"<module-set><name>fuzz-set</name><module><name>fuzz-sm-leaf</name>"
"<namespace>urn:tests:fuzz-sm-leaf</namespace></module></module-set>"
"<content-id>1</content-id></yang-library>"
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
"<module-set-id>1</module-set-id></modules-state>"
"<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
"<mount-point><module>fuzz-sm</module><label>root</label><inline/></mount-point>"
"</schema-mounts>";

static const char mount_module_dir_template[] = "/tmp/libyang-sm-fuzz.XXXXXX";
static char mount_module_dir[sizeof mount_module_dir_template];
static ly_bool mount_module_dir_ready;

static void
remove_mount_module_dir(void)
{
char path[sizeof mount_module_dir + sizeof "/fuzz-sm-leaf.yang"];

if (!mount_module_dir_ready) {
return;
}

snprintf(path, sizeof path, "%s/fuzz-sm-leaf.yang", mount_module_dir);
unlink(path);
rmdir(mount_module_dir);
mount_module_dir[0] = 0;
mount_module_dir_ready = 0;
}

static LY_ERR
prepare_mount_module_dir(void)
{
char path[sizeof mount_module_dir + sizeof "/fuzz-sm-leaf.yang"];
FILE *f;

if (mount_module_dir_ready) {
return LY_SUCCESS;
}

memcpy(mount_module_dir, mount_module_dir_template, sizeof mount_module_dir);
if (!mkdtemp(mount_module_dir)) {
mount_module_dir[0] = 0;
return LY_ESYS;
}
mount_module_dir_ready = 1;
atexit(remove_mount_module_dir);

snprintf(path, sizeof path, "%s/fuzz-sm-leaf.yang", mount_module_dir);
f = fopen(path, "w");
if (!f) {
remove_mount_module_dir();
return LY_ESYS;
}

if (fputs(mounted_module, f) == EOF) {
fclose(f);
remove_mount_module_dir();
return LY_ESYS;
}
if (fclose(f) == EOF) {
remove_mount_module_dir();
return LY_ESYS;
}

return LY_SUCCESS;
}

static LY_ERR
fuzz_ext_data_clb(const struct lysc_ext_instance *ext, const struct lyd_node *parent, void *user_data,
void **ext_data, ly_bool *ext_data_free)
{
struct lyd_node *data = NULL;
static ly_bool recursive_call;
LY_ERR ret = LY_SUCCESS;

(void)ext;
(void)parent;

*ext_data = NULL;
*ext_data_free = 0;

if (recursive_call) {
return LY_SUCCESS;
}

recursive_call = 1;
ret = lyd_parse_data_mem(user_data, ext_data_xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &data);
recursive_call = 0;
if (ret) {
lyd_free_all(data);
return ret;
}

*ext_data = data;
*ext_data_free = 1;
return LY_SUCCESS;
}

int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
struct ly_ctx *ctx = NULL;
struct lyd_node *tree = NULL;
char *data = NULL;
static bool log = false;

if (!log) {
ly_log_options(0);
log = true;
}

if (prepare_mount_module_dir() != LY_SUCCESS) {
return 0;
}

if (ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx) != LY_SUCCESS) {
return 0;
}
if (ly_ctx_set_searchdir(ctx, mount_module_dir) != LY_SUCCESS) {
goto cleanup;
}
if (lys_parse_mem(ctx, mount_module, LYS_IN_YANG, NULL) != LY_SUCCESS) {
goto cleanup;
}

ly_ctx_set_ext_data_clb(ctx, fuzz_ext_data_clb, ctx);

data = malloc(len + 1);
if (!data) {
goto cleanup;
}
memcpy(data, buf, len);
data[len] = 0;

lyd_parse_data_mem(ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, &tree);

cleanup:
lyd_free_all(tree);
free(data);
ly_ctx_destroy(ctx);
return 0;
}
4 changes: 2 additions & 2 deletions tests/fuzz/lys_parse_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)

err = ly_ctx_new(LY_SRC_DIR "/modules", 0, &ctx);
if (err != LY_SUCCESS) {
fprintf(stderr, "Failed to create context\n");
exit(EXIT_FAILURE);
return 0;
}

data = malloc(len + 1);
if (data == NULL) {
ly_ctx_destroy(ctx);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/fuzz/yang_parse_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)

data = malloc(len + 1);
if (data == NULL) {
fprintf(stderr, "Out of memory\n");
ly_ctx_destroy(ctx);
return 0;
}
memcpy(data, buf, len);
Expand Down
Loading