Skip to content

Commit

Permalink
feat: add initial fuzzing harness
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher Krah committed May 20, 2024
1 parent 7f34c7c commit c27bb54
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 0 deletions.
70 changes: 70 additions & 0 deletions fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
cmake_minimum_required(VERSION 3.9.5)
project(rplidar_fuzz)

if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif ()

message(STATUS "CXX Compiler: ${CMAKE_CXX_COMPILER}")
message(STATUS "CXX Flags before: ${CMAKE_CXX_FLAGS}")

if (CMAKE_CXX_COMPILER)
# Check if the CXX compiler is afl-clang or afl-clang++
if (CMAKE_CXX_COMPILER MATCHES "afl-clang-fast")
message(STATUS "Using AFL Clang compiler")
# Set flags for AFL
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer,address,undefined -ggdb -O2 -fno-omit-frame-pointer")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -ggdb -O2")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address,undefined -ggdb -O2")
else()
message(STATUS "Using regular Clang/GCC compiler")
# Enable fuzzer and address sanitizers for other compilers
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer,address,undefined -ggdb -O2")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=fuzzer,address,undefined -ggdb -O2")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=fuzzer,address,undefined -ggdb -O2")
endif()

message(STATUS "CXX Flags after: ${CMAKE_CXX_FLAGS}")

# Include directories for the SDK library
include_directories(
../sdk/include
../sdk/src
../sdk/src/arch/linux
../sdk/src/hal)

# Create instrumented SDK library
add_library(rplidar_sdk_instr SHARED
../sdk/src/rplidar_driver.cpp
../sdk/src/arch/linux/net_serial.cpp
../sdk/src/arch/linux/net_socket.cpp
../sdk/src/arch/linux/timer.cpp
../sdk/src/hal/thread.cpp)

target_include_directories(rplidar_sdk_instr
PUBLIC
../sdk/include
../sdk/src
PRIVATE
../sdk/src/arch/linux
../sdk/src/hal)

# Add the fuzz test executable
add_executable(harness harness.cc)

# Link against the instrumented rplidar_sdk library
target_link_libraries(harness rplidar_sdk_instr)

# Set the RPATH to find the SDK library
set_target_properties(harness PROPERTIES INSTALL_RPATH "\$ORIGIN")

# Set the output directory for the instrumented SDK library
set_target_properties(rplidar_sdk_instr PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

# Set the output directory for the fuzz test executable
set_target_properties(harness PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
else()
message(FATAL_ERROR "CMAKE_CXX is not set. Please specify the CXX compiler.")
endif ()
18 changes: 18 additions & 0 deletions fuzz/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
BUILD_DIR := build

.PHONY: all clean fuzz afl

all: fuzz

clean:
rm -rf $(BUILD_DIR)

fuzz: clean
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) && CC=clang CXX=clang++ cmake .. && make
mv $(BUILD_DIR)/harness harness

afl: clean
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) && CC=afl-clang-fast CXX=afl-clang-fast++ cmake .. && make
mv $(BUILD_DIR)/harness harness_afl
168 changes: 168 additions & 0 deletions fuzz/harness.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "sdkcommon.h"

#include "hal/abs_rxtx.h"
#include "hal/event.h"
#include "hal/locker.h"
#include "hal/socket.h"
#include "hal/thread.h"
#include "hal/types.h"
#include "rplidar_cmd.h"
#include "rplidar_driver.h"
#include "sdkcommon.h"

// Is needed for `std::unique_ptr`
#include <iostream>
#include <iterator>
#include <memory>
#include <vector>

#include <cstddef>
#include <cstdint>
#include <fuzzer/FuzzedDataProvider.h>
#include <ostream>
#include <stddef.h>
#include <stdint.h>
#include <string>

#define MAX_ALLOC 1024 * 1000

// extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { return 0; }

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp(data, size);

// Create an instance of the RPlidarDriver
auto driverType = fdp.ConsumeBool()
? rp::standalone::rplidar::DRIVER_TYPE_TCP
: rp::standalone::rplidar::DRIVER_TYPE_SERIALPORT;
auto drv = rp::standalone::rplidar::RPlidarDriver::CreateDriver(driverType);

if (!drv) {
return 0;
}

// Connect to the RPLIDAR device
if (fdp.remaining_bytes() >= 2) {
if (driverType == rp::standalone::rplidar::DRIVER_TYPE_SERIALPORT) {
std::string portPath = fdp.ConsumeRandomLengthString(256);
uint32_t baudrate = fdp.ConsumeIntegral<uint32_t>();
drv->connect(portPath.c_str(), baudrate);
} else {
std::string ip = fdp.ConsumeRandomLengthString(15);
uint32_t port = fdp.ConsumeIntegral<uint32_t>();

// Check if _binded_socket is null before calling connect
// if (static_cast<rp::standalone::rplidar::RPlidarDriver *>(drv)
// ->_channel._binded_socket == nullptr) {
// return -1;
//}

drv->connect(ip.c_str(), port);
}
}
// Check if the device is connected
drv->isConnected();

// Reset the device
if (fdp.ConsumeBool()) {
drv->reset();
}

// Get all supported scan modes
if (fdp.ConsumeBool()) {
std::vector<rp::standalone::rplidar::RplidarScanMode> outModes;
drv->getAllSupportedScanModes(outModes);
}

// Get typical scan mode
if (fdp.ConsumeBool()) {
uint16_t outMode;
drv->getTypicalScanMode(outMode);
}

// Start scan
if (fdp.ConsumeBool()) {
bool force = fdp.ConsumeBool();
bool useTypicalScan = fdp.ConsumeBool();
rp::standalone::rplidar::RplidarScanMode outUsedScanMode;
drv->startScan(force, useTypicalScan, 0, &outUsedScanMode);
}

// Start scan express
if (fdp.ConsumeBool()) {
bool force = fdp.ConsumeBool();
uint16_t scanMode = fdp.ConsumeIntegral<uint16_t>();
rp::standalone::rplidar::RplidarScanMode outUsedScanMode;
drv->startScanExpress(force, scanMode, 0, &outUsedScanMode);
}

// Get health status
if (fdp.ConsumeBool()) {
rplidar_response_device_health_t health;
drv->getHealth(health);
}

// Get device info
if (fdp.ConsumeBool()) {
rplidar_response_device_info_t info;
drv->getDeviceInfo(info);
}

// Set motor PWM
if (fdp.ConsumeBool()) {
uint16_t pwm = fdp.ConsumeIntegral<uint16_t>();
drv->setMotorPWM(pwm);
}

// Start motor
if (fdp.ConsumeBool()) {
drv->startMotor();
}

// Stop motor
if (fdp.ConsumeBool()) {
drv->stopMotor();
}

// Check motor control support
if (fdp.ConsumeBool()) {
bool support;
drv->checkMotorCtrlSupport(support);
}

// Get scan data
if (fdp.ConsumeBool()) {
// FIXME: Gotta wait for https://github.com/google/sanitizers/issues/1720
// size_t count = fdp.ConsumeIntegral<size_t>();
size_t count = fdp.ConsumeIntegralInRange<size_t>(0, MAX_ALLOC);

auto nodebuffer = std::unique_ptr<rplidar_response_measurement_node_hq_t[]>(
new rplidar_response_measurement_node_hq_t[count]);
auto timeout = static_cast<uint32_t>(fdp.ConsumeIntegral<uint16_t>());
drv->grabScanDataHq(nodebuffer.get(), count, timeout);
}

// Ascend scan data
if (fdp.ConsumeBool()) {
// FIXME: same as above
// size_t count = fdp.ConsumeIntegral<size_t>();
size_t count = fdp.ConsumeIntegralInRange<size_t>(0, MAX_ALLOC);
auto nodebuffer = std::unique_ptr<rplidar_response_measurement_node_hq_t[]>(
new rplidar_response_measurement_node_hq_t[count]);
drv->ascendScanData(nodebuffer.get(), count);
}

// Get scan data with interval
if (fdp.ConsumeBool()) {
// FIXME: same as above
// size_t count = fdp.ConsumeIntegral<size_t>();
size_t count = fdp.ConsumeIntegralInRange<size_t>(0, MAX_ALLOC);
auto nodebuffer = std::unique_ptr<rplidar_response_measurement_node_hq_t[]>(
new rplidar_response_measurement_node_hq_t[count]);
drv->getScanDataWithIntervalHq(nodebuffer.get(), count);
}
// Dispose of the driver
rp::standalone::rplidar::RPlidarDriver::DisposeDriver(drv);

return 0;
}

0 comments on commit c27bb54

Please sign in to comment.