An automatic fuzzing tool for ROS 2 C++ projects. The tool comprises two different commands: auto_detector and ros2_fuzzer.
Install the ros_automatic_fuzzer folder with pip:
pip3 install -e ros2_automatic_fuzzerAlternatively, start the start.sh command, which spawn a Docker container with both the examples and the tool.
- Navigate to your ROS working space.
- Run
auto_detector. This generates afuzz.yamlfile withTODOgaps. - Fill the missing
TODOs in thefuzz.yamlfile and complete it. - Run
ros2_fuzzerand follow the instructions. - Add the generated fuzzers to their CMakeLists.txt.
- Make a clean build with the
CCandCXXenvironment variables pointing to AFL. - Run the AFL fuzzers.
Check the following sections for detailed instructions for each step.
The auto_detector command generates a YAML file called fuzz.yaml which contains descriptions for three types of artifacts: topics, services, and action servers. The detection process relies on regular expressions in C++, and therefore it is not bullet-proof.
Optional arguments:
--path PATH. The path where to search for ROS artifacts. By default it is the working directory.
Optional flags:
-for--overwriteto force overwriting the file.-vor--verboseto increase the output verbosity.
Typical bash invocation:
auto_detectorThe fuzz.yaml file contains descriptions for topics, services, and action servers. Some of the fields can be automatically extracted in the previous step thanks to the auto_detector command, but others must be manually introduced. There may be TODO blanks that must be filled.
The format is simple: there are three optional categories: topics, services and actions. Each of those is a dictionary, with the keys being the name of the artifact. Each artifact contains the following descriptors:
headers_file(compulsory). A string pointing to thehppfile where the type of the artifact is defined (the topic type, the service type, or the action type). Sometimes it can be directly inferred.source(compulsory). A relative path to thefuzz.yamlfile where the artifact to be fuzzed is located. It must be a C++ source code file.type(compulsory). The type of the fuzzed artifact. It must conform to theros2 interface showsyntax. That is, with::as a separator and providing the full type. Correct examples areexample_interfaces::srv::AddTwoIntsandstd_msgs::msg::String, but notexample_interfaces/srv/AddTwoIntsnorString.parameters(optional). A list with all the parameters of the artifact. It can be inferred with theauto_detectorcommand.
Follows a concrete example. You can also check the syntax that is followed in the YAML schema, which all fuzz.yaml files must conform to.
topics:
minimal_topic:
headers_file: std_msgs/msg/string.hpp
source: src/publisher_subscriber_example/src/publisher_member_function.cpp
type: std_msgs::msg::String
parameters: []
topic:
headers_file: std_msgs/msg/string.hpp
source: src/parameters_example_package/src/fuzz_target.cpp
type: std_msgs::msg::String
parameters: []
services:
add_two_ints:
headers_file: example_interfaces/srv/add_two_ints.hpp
node_name: minimal_subscriber
source: src/parameters_example_package/src/add_two_ints_server.cpp
type: example_interfaces::srv::AddTwoInts
parameters: []
add_three_ints:
headers_file: tutorial_interfaces/srv/add_three_ints.hpp
source: src/client_service_example/src/add_three_ints_server.cpp
type: tutorial_interfaces::srv::AddThreeInts
parameters: []It consumes the fuzz.yaml file to generate C++ fuzzers for the selected artifacts. It allows generating fuzzers for all or some of them. Simply follow the steps on the screen. It may require calling ros2 interface show, and thus sourcing the ROS setup bash (with . install/setup.bash) may be required.
Optional arguments:
--path PATH. The path where to search for afuzz.yamlfile. By default it is on the working directory.
Optional flags:
-vor--verboseto increase the output verbosity.
Typical bash invocation:
ros2_fuzzerThe ros2_fuzzer command generates files of the *_generated.cpp form, which have to be linked to their CMakeList.txt files to be compiled.
For example, for the following fuzz.yaml file:
services:
add_three_ints:
headers_file: tutorial_interfaces/srv/add_three_ints.hpp
source: src/client_service_example/src/add_three_ints_server.cpp
type: tutorial_interfaces::srv::AddThreeInts
parameters: []The following code can be added into its CMakeLists.txt file (the generated_fuzzer keyword can be changed):
add_executable(generated_fuzzer src/add_three_ints_server_generated.cpp)
ament_target_dependencies(generated_fuzzer rclcpp tutorial_interfaces)
install(TARGETS generated_fuzzer DESTINATION lib/${PROJECT_NAME})To fuzz your C++ artifacts, it is necessary to recompile the projects so that they include instrumentalization annotations on the byte code to be used in the fuzzing search. We have decided to use AFL, an state-of-the-art fuzzer backed by Google.
If you haven't done so, you can install AFL with
apt install aflTo use it, set the CC and CXX environment variables to point to AFL and build the projects. We add the --cmake-clean-cache flag to prevent stale build files. Of course, you can use a more sofisticated way to build your projects, but make sure that the AFL's instrumentalization takes place.
export CC=afl-gcc
export CXX=afl-g++
colcon build --cmake-clean-cacheNavigate to install/<package>/lib/<package>/, where <package> is the name of your ROS package (or wherever the installation files are placed) and start the fuzzing search.
The command requires an inputs/ folder, with some files with content. You can use random values extracted from /dev/urandom, for instance:
mkdir inputs
head -c 50 /dev/urandom > inputs/input0.txtNow execute the afl-fuzz command (from AFL). Use the name of the executable found in that folder (try an ls) as the last parameter. The example shown in step #5 would be fuzzed with the following command:
afl-fuzz -i inputs/ -o outputs/ -m none -- ./generated_fuzzerYou should just change the generated_fuzzer execution file to yours to make AFL work.
Supported by ROSIN - ROS-Industrial Quality-Assured Robot Software Components. More information: rosin-project.eu
This project has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement no. 732287.