Description
Description
When converting a double value larger than INT_MAX
to an integer using the Blackboard system, the program encounters undefined behavior, leading to a SIGILL (illegal instruction). This occurs in the checkTruncation
function when attempting to validate numeric conversions.
The function attempts to detect truncation by converting back and forth between types, but does so without first checking if the value is within the target type's limits, leading to undefined behavior.
Found in commit: 48f6c5b
Bug Class
Integer/Type Conversion Vulnerability - Undefined Behavior
Impact
Program crash (SIGILL) when converting large floating-point values to integers
Potential security implications in parsing untrusted data
Can affect any system using the Blackboard for numeric type conversions
Reproducer
BT::Blackboard::Ptr bb = BT::Blackboard::create();
bb->set("test", 2.7249173913590775e+38); // Any double > INT_MAX
bb->get<int>("test"); // Triggers SIGILL
Root Cause
In convert_impl.hpp:91:
BehaviorTree.CPP/include/behaviortree_cpp/utils/convert_impl.hpp
Lines 88 to 95 in 48f6c5b
The issue occurs because static_cast<To>(from)
is undefined behavior when from exceeds the limits of To. This undefined value is then used in another cast and comparison operation.
Stack trace
#0 checkTruncation<double, int> (from=2.7249173913590775e+38)
#1 convertNumber<double, int>
#2 BT::Any::convert<int>
#3 BT::Any::tryCast<int>
#4 BT::Any::cast<int>
#5 BT::Blackboard::get<int>
Proposed Fix
Replace the current implementation with a bounds check before attempting the conversion:
template <typename From, typename To>
inline void checkTruncation(const From& from)
{
// First check numeric limits
if (from > static_cast<From>(std::numeric_limits<To>::max()) ||
from < static_cast<From>(std::numeric_limits<To>::min())) {
throw std::runtime_error("Value outside numeric limits");
}
// Now safe to do the truncation check
To as_target = static_cast<To>(from);
From back_to_source = static_cast<From>(as_target);
if(from != back_to_source) {
throw std::runtime_error("Floating point truncated");
}
}
Additional Notes
This was found via fuzzing with AFL++. The crash is reproducible in both Debug and Release builds.