diff --git a/cmake/fuzzing_build.cmake b/cmake/fuzzing_build.cmake index 354287121..7bd2ec5d5 100644 --- a/cmake/fuzzing_build.cmake +++ b/cmake/fuzzing_build.cmake @@ -106,7 +106,7 @@ endfunction() # Function to add fuzzing targets - compatible with both local and OSS-Fuzz builds function(add_fuzzing_targets) - set(FUZZERS bt_fuzzer script_fuzzer bb_fuzzer bt_tree_exec_fuzzer) + set(FUZZERS bt_fuzzer script_fuzzer bb_fuzzer bt_tree_exec_fuzzer bt_convert_fuzzer) foreach(fuzzer ${FUZZERS}) add_executable(${fuzzer} fuzzing/${fuzzer}.cpp) diff --git a/fuzzing/bt_convert_fuzzer.cpp b/fuzzing/bt_convert_fuzzer.cpp new file mode 100644 index 000000000..01b115a53 --- /dev/null +++ b/fuzzing/bt_convert_fuzzer.cpp @@ -0,0 +1,112 @@ +// Fuzz target: bt_convert_fuzzer +// +// Threat model: every XML attribute, script literal and blackboard value that +// enters a BehaviorTree.CPP application passes through BT::convertFromString +// (port parsing). These string->type conversions are the numeric- and +// string-parsing funnel for untrusted data (attacker-supplied XML documents, +// Groot files, scripting expressions). +// +// Strategy: convertFromString over the full builtin type matrix with a +// fuzzed string (numerics incl. int8..64/uint8..64/float/double overflow and +// underflow, bool, enums NodeStatus/NodeType/PortDirection, split containers +// vector, SharedQueue). +// +// All thrown BT exceptions (RuntimeError/LogicError on invalid input) are +// expected and caught; the point is exercising the conversion code paths, not +// crashing on them. +// +// Expected bug classes: integer/float overflow and truncation handling, +// out-of-bounds reads in split-string parsing, enum parsing mismatches. + +#include "behaviortree_cpp/basic_types.h" +#include "behaviortree_cpp/decorators/loop_node.h" + +#include +#include + +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + if(size < 8) + { + return 0; + } + FuzzedDataProvider fdp(data, size); + + const std::string text = fdp.ConsumeRandomLengthString(); + const BT::StringView sv(text); + + try + { + switch(fdp.ConsumeIntegralInRange(0, 19)) + { + case 0: + (void)BT::convertFromString(sv); + break; + case 1: + (void)BT::convertFromString(sv); + break; + case 2: + (void)BT::convertFromString(sv); + break; + case 3: + (void)BT::convertFromString(sv); + break; + case 4: + (void)BT::convertFromString(sv); + break; + case 5: + (void)BT::convertFromString(sv); + break; + case 6: + (void)BT::convertFromString(sv); + break; + case 7: + (void)BT::convertFromString(sv); + break; + case 8: + (void)BT::convertFromString(sv); + break; + case 9: + (void)BT::convertFromString(sv); + break; + case 10: + (void)BT::convertFromString(sv); + break; + case 11: + (void)BT::convertFromString(sv); + break; + case 12: + (void)BT::convertFromString(sv); + break; + case 13: + (void)BT::convertFromString(sv); + break; + case 14: + (void)BT::convertFromString(sv); + break; + case 15: + (void)BT::convertFromString>(sv); + break; + case 16: + (void)BT::convertFromString>(sv); + break; + case 17: + (void)BT::convertFromString>(sv); + break; + case 18: + (void)BT::convertFromString>(sv); + break; + default: + (void)BT::convertFromString>(sv); + break; + } + } + catch(const std::exception&) + { + // invalid numeric/enum input raises RuntimeError: expected + } + + return 0; +} diff --git a/fuzzing/corpus/bt_convert_fuzzer/bool-yes b/fuzzing/corpus/bt_convert_fuzzer/bool-yes new file mode 100644 index 000000000..e433dab88 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/bool-yes differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/double-nan b/fuzzing/corpus/bt_convert_fuzzer/double-nan new file mode 100644 index 000000000..7c4a54e40 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/double-nan differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/enum-nodetype b/fuzzing/corpus/bt_convert_fuzzer/enum-nodetype new file mode 100644 index 000000000..e2a72a170 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/enum-nodetype differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/enum-status b/fuzzing/corpus/bt_convert_fuzzer/enum-status new file mode 100644 index 000000000..8da63d33c Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/enum-status differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/float-overflow b/fuzzing/corpus/bt_convert_fuzzer/float-overflow new file mode 100644 index 000000000..cd90582b2 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/float-overflow differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/int-max b/fuzzing/corpus/bt_convert_fuzzer/int-max new file mode 100644 index 000000000..21e6b0689 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/int-max differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/int-underflow b/fuzzing/corpus/bt_convert_fuzzer/int-underflow new file mode 100644 index 000000000..461be1bad Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/int-underflow differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/junk-mixed b/fuzzing/corpus/bt_convert_fuzzer/junk-mixed new file mode 100644 index 000000000..f01c25001 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/junk-mixed differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/queue-int b/fuzzing/corpus/bt_convert_fuzzer/queue-int new file mode 100644 index 000000000..9c0cbaac6 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/queue-int differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/uint-max b/fuzzing/corpus/bt_convert_fuzzer/uint-max new file mode 100644 index 000000000..cf8762053 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/uint-max differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/vec-bool b/fuzzing/corpus/bt_convert_fuzzer/vec-bool new file mode 100644 index 000000000..31d85e669 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/vec-bool differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/vec-double b/fuzzing/corpus/bt_convert_fuzzer/vec-double new file mode 100644 index 000000000..8a228aab9 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/vec-double differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/vec-int b/fuzzing/corpus/bt_convert_fuzzer/vec-int new file mode 100644 index 000000000..81af62b80 Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/vec-int differ diff --git a/fuzzing/corpus/bt_convert_fuzzer/vec-str b/fuzzing/corpus/bt_convert_fuzzer/vec-str new file mode 100644 index 000000000..ce9ab17fb Binary files /dev/null and b/fuzzing/corpus/bt_convert_fuzzer/vec-str differ diff --git a/fuzzing/dictionaries/bt_convert_fuzzer.dict b/fuzzing/dictionaries/bt_convert_fuzzer.dict new file mode 100644 index 000000000..4abcc6d60 --- /dev/null +++ b/fuzzing/dictionaries/bt_convert_fuzzer.dict @@ -0,0 +1,50 @@ +# Dictionary for bt_convert_fuzzer: numeric forms, enum names, separators. +"9223372036854775807" +"-9223372036854775808" +"18446744073709551615" +"0" +"-1" +"+1" +"007" +"0x1F" +"0b101" +"1e10" +"1E-10" +"1e999" +"-1e999" +"nan" +"inf" +"-inf" +"3.14159" +".5" +"5." +"1.0e-400" +"true" +"false" +"TRUE" +"False" +"1;2;3" +"-4;5;6" +"1.5;2.5" +"a;b;c" +"true;false" +"SUCCESS" +"FAILURE" +"RUNNING" +"SKIPPED" +"IDLE" +"Action" +"Condition" +"Control" +"Decorator" +"SubTree" +"UNDEFINED" +"INPUT" +"OUTPUT" +"BIDIRECTIONAL" +" " +" 42 " +";;" +"--7" +"12abc" +"1;2;3;"