Skip to content

Security Issue: Use of Uninitialized Memory in libucl #346

@Kaldreic

Description

@Kaldreic

Summary

Feeding a crafted input to ucl_add_string_fuzzer causes libucl to read uninitialized memory in the hash table implementation and then crash with a NULL pointer dereference in ucl_hash_destroy() while freeing the parser state.

Environment

  • Tooling: valgrind --tool=memcheck --track-origins=yes
  • Target: ucl_add_string_fuzzer
  • OS: Ubuntu 20.04.6 LTS focal x86_64
  • libucl version: v0.9.2 (a6b5cac1121103984ee2035081b7467725d68ed7)

Reproducer

Artifacts:

  • Fuzzer binary (ucl_add_string_fuzzer)
  • Single testcase

Repro with OSS-Fuzz helpers:

git clone https://github.com/google/oss-fuzz.git
cd oss-fuzz

python3 infra/helper.py build_image libucl
python3 infra/helper.py build_fuzzers --sanitizer=none libucl
python3 infra/helper.py shell libucl

apt update && apt install -y valgrind
ulimit -n 65535
valgrind --tool=memcheck --track-origins=yes /out/ucl_add_string_fuzzer /path/to/poc

Valgrind Trace (top frames):

==170== Use of uninitialised value of size 8
==170==    at 0x215E8C: ucl_hash_destroy (in /out/ucl_add_string_fuzzer)
==170==    by 0x2058E2: ucl_object_free_internal (in /out/ucl_add_string_fuzzer)
==170==    by 0x2069BA: ucl_parser_free (in /out/ucl_add_string_fuzzer)
==170==    by 0x200341: ucl_state_machine (in /out/ucl_add_string_fuzzer)
==170==    by 0x1FCCE9: ucl_parser_add_chunk_full (in /out/ucl_add_string_fuzzer)
==170==  Uninitialised value was created by a heap allocation at 0x483B723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)

UBSan Trace:

ERROR: SEGV on address 0x0 (READ)
#0 ucl_hash_destroy           /src/libucl/src/ucl_hash.c:272:29
#1 ucl_object_free_internal   /src/libucl/src/ucl_util.c:278
#2 ucl_parser_free            /src/libucl/src/ucl_util.c:646
#3 ucl_state_machine          /src/libucl/src/ucl_parser.c:2664
#4 ucl_parser_add_chunk_full  /src/libucl/src/ucl_parser.c:3062

Likely root cause (from symptoms):

  • During insertion, kh_resize_ucl_hash_node() reallocs internal arrays but does not fully initialize new slots / flags, or error/partial-insert paths leave the table in an inconsistent state.
  • On teardown, ucl_hash_destroy() iterates the table using slot flags that contain uninitialized bytes, treats garbage as “occupied”, and accesses entry fields (or frees them), leading to a read from NULL (and potentially other invalid pointers).

Impact

  • Denial of service via crash in consumers that parse untrusted UCL input.
  • Depending on allocator state, teardown could attempt to free/walk garbage pointers (risking invalid free). No controlled memory corruption demonstrated here.

Additional testcase — same root cause via a different path

I’m attaching a second PoC (archive1.zip) that hits the same underlying defect (uninitialized slot/flag state leading to NULL/garbage deref in ucl_hash_destroy) but via a slightly different mutation path.

Credit: Aldo Ristori

archive0.zip
archive1.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions