diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 412c51bc..cf41d602 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -89,4 +89,11 @@ add_executable(fuzz_evm_payload ../src/evm_parser.c ) target_compile_definitions(fuzz_evm_payload PRIVATE NO_BOLOS_SDK=1) -target_link_libraries(fuzz_evm_payload mock_bolos) \ No newline at end of file +target_link_libraries(fuzz_evm_payload mock_bolos) + +add_executable(fuzz_swap_token_utils + fuzzer_swap_token_utils.c + ../src/swap/swap_token_utils.c +) +target_compile_definitions(fuzz_swap_token_utils PRIVATE NO_BOLOS_SDK=1) +target_link_libraries(fuzz_swap_token_utils mock_bolos) \ No newline at end of file diff --git a/fuzzing/fuzzer_swap_token_utils.c b/fuzzing/fuzzer_swap_token_utils.c new file mode 100644 index 00000000..c0cbeda0 --- /dev/null +++ b/fuzzing/fuzzer_swap_token_utils.c @@ -0,0 +1,67 @@ +#include +#include +#include + +#include "swap/swap_token_utils.h" + +#define MAX_ASSET_LEN 16 +#define MAX_OUT_LEN 64 +#define MAX_STR_LEN 16 + +static size_t min_size(size_t a, size_t b) { + return (a < b) ? a : b; +} + +static uint64_t load_u64_be(const uint8_t *data, size_t len) { + uint64_t v = 0; + for (size_t i = 0; i < len; i++) { + v = (v << 8) | data[i]; + } + return v; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (data == NULL || size == 0) return 0; + + size_t offset = 0; + uint8_t flags = data[offset++]; + + uint8_t decimals = (offset < size) ? data[offset++] : 0; + + size_t amount_len = min_size(8, size - offset); + uint64_t amount = load_u64_be(data + offset, amount_len); + offset += amount_len; + + uint8_t out_len_hint = (offset < size) ? data[offset++] : 0; + size_t out_len = out_len_hint % (MAX_OUT_LEN + 1); + + const char *asset = NULL; + char asset_buf[MAX_ASSET_LEN + 1]; + if ((flags & 0x1) && offset < size) { + size_t asset_len = data[offset++] % (MAX_ASSET_LEN + 1); + size_t avail = size - offset; + if (asset_len > avail) asset_len = avail; + memcpy(asset_buf, data + offset, asset_len); + asset_buf[asset_len] = '\0'; + asset = asset_buf; + offset += asset_len; + } + + char out_buf[MAX_OUT_LEN + 1]; + memset(out_buf, 0, sizeof(out_buf)); + (void)print_token_amount(amount, asset, decimals, out_buf, out_len); + + uint8_t str_buf[MAX_STR_LEN]; + size_t str_len = min_size(MAX_STR_LEN, size - offset); + memset(str_buf, 0, sizeof(str_buf)); + if (str_len > 0) { + memcpy(str_buf, data + offset, str_len); + } + + uint64_t parsed = 0; + size_t len_hint = data[0] % (MAX_STR_LEN + 1); + (void)swap_str_to_u64(str_buf, len_hint, &parsed); + (void)swap_str_to_u64(str_buf, MAX_STR_LEN, &parsed); + + return 0; +} \ No newline at end of file diff --git a/fuzzing/run_fuzzing.sh b/fuzzing/run_fuzzing.sh index ea55c275..b59d4328 100755 --- a/fuzzing/run_fuzzing.sh +++ b/fuzzing/run_fuzzing.sh @@ -61,7 +61,8 @@ setup_directories() { # Create corpus directories for each fuzzer mkdir -p "$CORPUS_DIR/proto_varlen_parser" mkdir -p "$CORPUS_DIR/evm_payload" - + mkdir -p "$CORPUS_DIR/swap_token_utils" + print_status "Directories created" } @@ -94,6 +95,9 @@ generate_corpus() { # ERC20 transfer selector only printf "\xA9\x05\x9C\xBB" > "$CORPUS_DIR/evm_payload/selector.bin" # Full calldata: selector + 32-byte address word + 32-byte amount word + # swap_token_utils seeds + printf "\x01\x08\x00\x00\x00\x00\x00\x00\x00\x01\x20\x04HBAR" > "$CORPUS_DIR/swap_token_utils/hbar_valid.bin" + printf "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x10" > "$CORPUS_DIR/swap_token_utils/max_valid.bin" ( printf "\xA9\x05\x9C\xBB" # address word: 12 zero pad + 20 0x11 bytes @@ -156,7 +160,7 @@ run_fuzzer() { run_all_fuzzers() { print_status "Starting fuzzing campaign..." - local fuzzers=("proto_varlen_parser" "evm_payload") + local fuzzers=("proto_varlen_parser" "evm_payload" "swap_token_utils") for fuzzer in "${fuzzers[@]}"; do run_fuzzer "$fuzzer" "$FUZZ_TIME"