libucl
libucl copied to clipboard
Bug: AddressSanitizer: heap-buffer-overflow found with Libfuzzer
To be short, I have found several issues using libfuzzer fuzz tools. Here I list some clue about how to preproduce and fix those issues.
Environment
libucl version: Latest commit 3e7f023 System: Ubuntu 22.04.5 LTS (Jammy) Kernel/Release: 22.04
Bug Reproduction
driver code
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
struct ucl_parser *p = ucl_parser_new(
UCL_PARSER_NO_FILEVARS); // 开启更多功能:支持宏等
if (!p) return 0;
if (!ucl_parser_add_chunk(p, (const unsigned char *)data, size)) {
const char *err = ucl_parser_get_error(p); // 保留错误信息供调试
(void)err;
ucl_parser_free(p);
return 0;
}
ucl_object_t *obj = ucl_parser_get_object(p);
if (!obj) {
const char *err = ucl_parser_get_error(p);
(void)err;
ucl_parser_free(p);
return 0;
}
// 🚀 Emit in different formats to hit more code paths
unsigned char *json = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
unsigned char *yaml = ucl_object_emit(obj, UCL_EMIT_YAML);
unsigned char *config = ucl_object_emit(obj, UCL_EMIT_CONFIG);
free(json);
free(yaml);
free(config);
// 🔁 Iterate all elements deeply
ucl_object_iter_t it = NULL;
const ucl_object_t *cur;
while ((cur = ucl_iterate_object(obj, &it, true)) != NULL) {
(void)ucl_object_tostring(cur);
(void)ucl_object_toint(cur);
(void)ucl_object_todouble(cur);
(void)ucl_object_toboolean(cur);
(void)ucl_object_type(cur);
// (void)ucl_object_len(cur);
// 🧪 Validate subobject to itself
(void)ucl_object_validate(cur, cur, NULL);
}
// 🧬 Re-parse emitted JSON to catch serialization bugs
unsigned char *reemit = ucl_object_emit(obj, UCL_EMIT_JSON);
if (reemit) {
struct ucl_parser *p2 = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
if (p2) {
(void)ucl_parser_add_chunk(p2, reemit, strlen((const char *)reemit));
ucl_object_t *reobj = ucl_parser_get_object(p2);
if (reobj) {
ucl_object_unref(reobj);
}
ucl_parser_free(p2);
}
free(reemit);
}
ucl_object_unref(obj);
ucl_parser_free(p);
return 0;
}
compile:
cd .. && rm -rf libucl-0.9.2 && tar -xvf libucl-0.9.2.tar.gz && cd libucl-0.9.2/
LIB_CONFIG_BASE_DIR=$(pwd)
INSTALL_PREFIX="${LIB_CONFIG_BASE_DIR}/libucl_install"
echo "Libconfig will be installed to: ${INSTALL_PREFIX}"
mkdir -p "${INSTALL_PREFIX}"
# if [! -f configure ]; then
./autogen.sh
# fi
echo "Configuring libucl..."
CFLAGS="-g -O1 -fsanitize=address" \
CXXFLAGS="-g -O1 -fsanitize=address" \
./configure --prefix="${INSTALL_PREFIX}" --enable-static=yes --enable-shared=no
make clean && make -j$(nproc) && make install
# CC=$AFL_HOME/afl-clang
# CXX=$AFL_HOME/afl-clang++
cd "../libucl_test"
echo $INSTALL_PREFIX/include
clang++ -g -O1 -fsanitize=address,fuzzer main.cc \
../libucl-0.9.2/libucl_install/lib/libucl.a\
-I$INSTALL_PREFIX/include \
-L$INSTALL_PREFIX/lib \
-o libconfig_fuzzer
# # $AFL_HOME/afl-fuzz -m none -i corpus -o out ./libucl_fuzzer @@
./ucl_libfuzzer ./corpus/ > fuze-0.log 2>&1
[crash.txt](
crash-ca6d7f3f4c77eb59c507be963de3c344261d5c2e.txt
)
Fix Recommondation
crash info
==12111==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020010db2bc at pc 0x000000566155 bp 0x7ffe729b6180 sp 0x7ffe729b6178
READ of size 1 at 0x6020010db2bc thread T0
#0 0x566154 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x566154)
#1 0x5704e1 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x5704e1)
#2 0x56be45 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x56be45)
#3 0x5504c8 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x5504c8)
#4 0x430377 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x430377)
#5 0x43abe4 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x43abe4)
#6 0x43c24f (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x43c24f)
#7 0x42b60c (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x42b60c)
#8 0x41d4f2 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x41d4f2)
#9 0x7fa59ff67c86 (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#10 0x41e549 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x41e549)
0x6020010db2bc is located 0 bytes to the right of 12-byte region [0x6020010db2b0,0x6020010db2bc)
allocated by thread T0 here:
#0 0x54c1d0 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x54c1d0)
#1 0x43028e (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x43028e)
#2 0x43abe4 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x43abe4)
#3 0x43c24f (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x43c24f)
#4 0x42b60c (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x42b60c)
#5 0x41d4f2 (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x41d4f2)
#6 0x7fa59ff67c86 (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/data/tjm/code/fuzz/libucl_test/ucl_libfuzzer+0x566154)
Shadow bytes around the buggy address:
0x0c0480213600: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fa
0x0c0480213610: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
0x0c0480213620: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
0x0c0480213630: fa fa fd fa fa fa fd fd fa fa fd fd fa fa fd fd
0x0c0480213640: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fa
=>0x0c0480213650: fa fa fd fa fa fa 00[04]fa fa 00 fa fa fa 00 04
0x0c0480213660: fa fa 00 01 fa fa 00 01 fa fa 05 fa fa fa 00 fa
0x0c0480213670: fa fa 00 01 fa fa 06 fa fa fa 07 fa fa fa 02 fa
0x0c0480213680: fa fa 04 fa fa fa 02 fa fa fa 02 fa fa fa 02 fa
0x0c0480213690: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04802136a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==12111==ABORTING
MS: 1 CopyPart-; base unit: f3978f4b9b9cf75b371ab53510f8b25c6d0ae567
0x30,0x20,0x34,0xa,0x64,0x20,0x74,0x3b,0x72,0x20,0x30,0x20,
0 4\x0ad t;r 0
artifact_prefix='./'; Test unit written to ./crash-ca6d7f3f4c77eb59c507be963de3c344261d5c2e
Base64: MCA0CmQgdDtyIDAg
how to fix? change libucl-0.9.2/src/ucl_parser.c:1010
case ' ':
while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
p++;
}
if (ucl_lex_is_atom_end(*p))
goto set_obj;
break;
to
case ' ':
while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
p++;
}
if (!p) break;
if (ucl_lex_is_atom_end(*p))
goto set_obj;
break;