Skip to content
Open
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
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ if(WITH_FLOATING_POINT AND NOT WITH_FREESTANDING)
option(WITH_CBOR2JSON "Compile code to convert from CBOR to JSON" ON)
option(BUILD_EXAMPLES "Compile the TinyCBOR examples" OFF)
option(BUILD_TOOLS "Compile the TinyCBOR tools" ON)
option(BUILD_FUZZERS "Compile the TinyCBOR fuzzers (see fuzz/README)" OFF)
endif()

# Include additional modules that are used unconditionally
Expand Down Expand Up @@ -217,3 +218,6 @@ endif()
if(BUILD_TOOLS)
add_subdirectory(tools)
endif()
if(BUILD_FUZZERS)
add_subdirectory(fuzz)
endif()
52 changes: 52 additions & 0 deletions fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# /****************************************************************************
# **
# ** Copyright (C) 2026 Topogamer0
# **
# ** Permission is hereby granted, free of charge, to any person obtaining a copy
# ** of this software and associated documentation files (the "Software"), to deal
# ** in the Software without restriction, including without limitation the rights
# ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# ** copies of the Software, and to permit persons to whom the Software is
# ** furnished to do so, subject to the following conditions:
# **
# ** The above copyright notice and this permission notice shall be included in
# ** all copies or substantial portions of the Software.
# **
# ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# ** THE SOFTWARE.
# **
# ****************************************************************************/

include(TinyCBORHelpers)

# The library and the fuzzers must be compiled with the instrumentation the
# fuzzing engine needs (for libFuzzer, -fsanitize=fuzzer-no-link in
# CMAKE_C_FLAGS) and any sanitizers. LIB_FUZZING_ENGINE is what provides
# main(), as in OSS-Fuzz (which sets it in the environment).
if(DEFINED ENV{LIB_FUZZING_ENGINE})
set(LIB_FUZZING_ENGINE "$ENV{LIB_FUZZING_ENGINE}" CACHE STRING "Fuzzing engine to link the fuzzers with")
else()
set(LIB_FUZZING_ENGINE "-fsanitize=fuzzer" CACHE STRING "Fuzzing engine to link the fuzzers with")
if(NOT CMAKE_C_FLAGS MATCHES "-fsanitize=[^ ]*fuzzer")
message(WARNING "CMAKE_C_FLAGS has no -fsanitize=fuzzer-no-link: the fuzzers will not be instrumented")
endif()
endif()

# The fuzzing engines are written in C++
enable_language(CXX)

set(fuzzers encoder parser pretty validate)
if(WITH_CBOR2JSON)
list(APPEND fuzzers tojson)
endif()

foreach(fuzzer ${fuzzers})
tinycbor_add_executable(${fuzzer}_fuzzer ${fuzzer}_fuzzer.c)
target_link_libraries(${fuzzer}_fuzzer ${LIB_FUZZING_ENGINE})
set_target_properties(${fuzzer}_fuzzer PROPERTIES LINKER_LANGUAGE CXX)
endforeach()
40 changes: 40 additions & 0 deletions fuzz/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
TinyCBOR fuzzers
----------------

These are libFuzzer-style fuzzers for TinyCBOR, also used by OSS-Fuzz.

parser_fuzzer parses the input as a sequence of CBOR items, visiting
every item and extracting every value; optionally uses
the reader API (cbor_parser_init_reader)
validate_fuzzer cbor_value_validate() with any combination of flags
tojson_fuzzer cbor_value_to_json_advance() with any combination of flags
pretty_fuzzer cbor_value_to_pretty_advance_flags() and
cbor_value_to_pretty_stream() with any combination of flags
encoder_fuzzer interprets the input as a sequence of encoder commands,
then parses the result back and compares it

For all fuzzers except encoder_fuzzer, the first 4 bytes of the input are a
configuration word (flags, mode) and the rest is the CBOR payload. The seed
corpus in corpus/ uses a zero configuration word followed by the CBOR data
from the unit tests; cbor.dict is a dictionary for those fuzzers.

The assert()s in TinyCBOR check that the API is used correctly, so the
fuzzers must be built without NDEBUG: an assertion failure is a bug in the
fuzzer. The fuzzers also abort if the library contradicts its documented
behaviour (for example, if cbor_value_validate() succeeds but parsing the same
data fails).

To build with Clang and libFuzzer:

cmake -S. -Bbuild -DBUILD_FUZZERS=ON \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_FLAGS="-g -O1 -fsanitize=fuzzer-no-link,address,undefined" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
cmake --build build

LIB_FUZZING_ENGINE selects what to link the fuzzers with (default:
-fsanitize=fuzzer; if set in the environment, as in OSS-Fuzz, that is used).

To run:

build/fuzz/parser_fuzzer -dict=fuzz/cbor.dict new-corpus fuzz/corpus
105 changes: 105 additions & 0 deletions fuzz/cbor.dict
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# /****************************************************************************
# **
# ** Copyright (C) 2026 Topogamer0
# **
# ** Permission is hereby granted, free of charge, to any person obtaining a copy
# ** of this software and associated documentation files (the "Software"), to deal
# ** in the Software without restriction, including without limitation the rights
# ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# ** copies of the Software, and to permit persons to whom the Software is
# ** furnished to do so, subject to the following conditions:
# **
# ** The above copyright notice and this permission notice shall be included in
# ** all copies or substantial portions of the Software.
# **
# ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# ** THE SOFTWARE.
# **
# ****************************************************************************/

# Initial bytes of CBOR items (RFC 8949), for the parsing fuzzers

# major type 0: unsigned integers
"\x00"
"\x17"
"\x18"
"\x19"
"\x1a"
"\x1b"
# major type 1: negative integers
"\x20"
"\x37"
"\x38"
"\x39"
"\x3a"
"\x3b"
# major type 2: byte strings
"\x40"
"\x57"
"\x58"
"\x59"
"\x5a"
"\x5b"
"\x5f"
# major type 3: text strings
"\x60"
"\x77"
"\x78"
"\x79"
"\x7a"
"\x7b"
"\x7f"
# major type 4: arrays
"\x80"
"\x97"
"\x98"
"\x99"
"\x9a"
"\x9b"
"\x9f"
# major type 5: maps
"\xa0"
"\xb7"
"\xb8"
"\xb9"
"\xba"
"\xbb"
"\xbf"
# major type 6: tags
"\xc0"
"\xc1"
"\xc2"
"\xc3"
"\xc4"
"\xc5"
"\xd5"
"\xd6"
"\xd7"
"\xd8"
"\xd9"
"\xda"
"\xdb"
"\xd8\x18"
"\xd8\x20"
"\xd9\xd9\xf7"
# major type 7: simple values and floating point
"\xe0"
"\xf4"
"\xf5"
"\xf6"
"\xf7"
"\xf8"
"\xf9"
"\xfa"
"\xfb"
"\xff"
"\xf9\x7c\x00"
"\xf9\xfc\x00"
"\xf9\x7e\x00"
"\xfa\x7f\xc0\x00\x00"
"\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading