Closed MarkLee131 closed 2 months ago
I don't know which fuzzer/FuzzedDataProvider.h
you used. I will assume https://github.com/llvm/llvm-project/blob/7868033d2e846fa30c20455ca819fad29d9d795e/compiler-rt/include/fuzzer/FuzzedDataProvider.h
Let us look at what provider.ConsumeBytes<uint8_t>(nb);
actually does: https://github.com/llvm/llvm-project/blob/7868033d2e846fa30c20455ca819fad29d9d795e/compiler-rt/include/fuzzer/FuzzedDataProvider.h#L103-L111
Notice the min
in there. It might return less data than what you asked for. That means that the following line is incorrect since it tells libmodbus "you might read nb
bits of data" and does not handle the case when the buffer is smaller than nb
:
int ret = modbus_write_bits(ctx, addr, nb, bits.data());
bits
could contain less than nb
bytes of data. In which case you get the read buffer overflow that your fuzzer found.
Please fix this to
int ret = modbus_write_bits(ctx, addr, bits.size(), bits.data());
(Technically, I guess this should be bits.size() * 8
since the buffer you call bits
actually contains bytes, but that issue is unrelated to whether your fuzzing driver is actually correct. It would just be less effective due to this.)
Also, for the future, I suggest that you try to understand your fuzzing results before humillating yourself.
libmodbus version
libmodbus 3.1.10
OS and/or distribution
Linux, Ubuntu 20.04
Environment
amd64
Description
A heap-buffer-overflow was discovered in the
modbus_write_bits
function. This issue can be triggered when the function is fed with specially crafted input, which leads to out-of-bounds read and can potentially cause a crash or other unintended behaviors.Actual behavior if applicable
The function
modbus_write_bits
exhibits undefined behavior and crashes when processing certain inputs where the nb (number of bits) parameter leads to an out-of-bounds read of the input buffer. This is evident from the ASan reports indicating a heap-buffer-overflow.Expected behavior or suggestion
The function should safely handle all input ranges and sizes without causing buffer overflows.
Steps to reproduce the behavior (commands or source code)
DEDUP_TOKEN: modbus_write_bits--LLVMFuzzerTestOneInput--fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) [1m[32m0x60200000b571 is located 0 bytes to the right of 1-byte region [0x60200000b570,0x60200000b571) [1m[0m[1m[35mallocated by thread T0 here:[1m[0m
0 0x569ead in operator new(unsigned long) /src/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:95:3
DEDUP_TOKEN: operator new(unsigned long)--libcpp_operator_new-- libcpp_allocate
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/libmodbus/src/modbus.c:1461:17 in modbus_write_bits
Shadow bytes around the buggy address:
0x0c047fff9650: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[35mfd[1m[0m
0x0c047fff9660: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[35mfd[1m[0m
0x0c047fff9670: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m
0x0c047fff9680: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m
0x0c047fff9690: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m
=>0x0c047fff96a0: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[35mfd[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[0m00[1m[0m [1m[0m01[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m[[1m[0m01[1m[0m][1m[31mfa[1m[0m
0x0c047fff96b0: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m
0x0c047fff96c0: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m
0x0c047fff96d0: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m
0x0c047fff96e0: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m
0x0c047fff96f0: [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m [1m[31mfa[1m[0m
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: [1m[0m00[1m[0m
Partially addressable: [1m[0m01[1m[0m [1m[0m02[1m[0m [1m[0m03[1m[0m [1m[0m04[1m[0m [1m[0m05[1m[0m [1m[0m06[1m[0m [1m[0m07[1m[0m
Heap left redzone: [1m[31mfa[1m[0m
Freed heap region: [1m[35mfd[1m[0m
Stack left redzone: [1m[31mf1[1m[0m
Stack mid redzone: [1m[31mf2[1m[0m
Stack right redzone: [1m[31mf3[1m[0m
Stack after return: [1m[35mf5[1m[0m
Stack use after scope: [1m[35mf8[1m[0m
Global redzone: [1m[31mf9[1m[0m
Global init order: [1m[36mf6[1m[0m
Poisoned by user: [1m[34mf7[1m[0m
Container overflow: [1m[34mfc[1m[0m
Array cookie: [1m[31mac[1m[0m
Intra object redzone: [1m[33mbb[1m[0m
ASan internal: [1m[33mfe[1m[0m
Left alloca redzone: [1m[34mca[1m[0m
Right alloca redzone: [1m[34mcb[1m[0m
==13==ABORTING
MS: 2 ChangeBit-ChangeBit-; base unit: c68bed0f37ab64033b5e4e6c6e801a00b8c8f87c
0x0,0x1,0x2,0x0,0x80,0x4,0x1,0x1,0x2a,
\000\001\002\000\200\004\001\001*
artifact_prefix='./'; Test unit written to ./crash-05ddbd1d0695e401044d58f3388298c1138958d4
Base64: AAECAIAEAQEq
stat::number_of_executed_units: 1401
stat::average_exec_per_sec: 700
stat::new_units_added: 17
stat::slowest_unit_time_sec: 0
stat::peak_rss_mb: 32
./tests/unit-test-server echo "AAECAIAEAQEq" | base64 -d | nc 127.0.0.1 1502
Client connection accepted from 127.0.0.1. Waiting for an indication... ERROR Connection timed out: select
<00><01><02><00><80><04><01><01><2A>Quit the loop: Connection timed out ``` - The crashed line is at: https://github.com/stephane/libmodbus/blob/5c14f13944ec7394a61a7680dcb462056c4321e3/src/modbus.c#L1461