| Название | libyal (Joachim Metz) libvmdk `396e1873a030ac535bf919f6707d5be57613ae08` Memory corruption |
|---|
| Описание | ## Technical Description
libvmdk is an open-source library to access the VMware Virtual Disk (VMDK) format, used by vmdkmount, pyvmdk and forensic tooling. In narrow-character builds (HAVE_WIDE_SYSTEM_CHARACTER undefined, the default on Linux), `libvmdk_extent_table_get_extent_data_file_path()` in `libvmdk/libvmdk_extent_table.c` heap-allocates `utf8_filename` at line 869 for the extent filename. When the process codepage is non-zero (`libclocale_codepage != 0`, settable via the public API `libvmdk_set_codepage()`), a second buffer `narrow_filename` is allocated independently for the encoding conversion. The success path at lines 1001-1004 frees only `narrow_filename` and returns; `utf8_filename` is never released on that path (it is freed only in the `on_error` handler). The wide-character variant of the same function frees `utf8_filename` before returning (lines 1437-1440), confirming the omission is an oversight.
Extent entries and filenames are fully attacker-controlled through the VMDK descriptor text. Frontends call the exported `libvmdk_handle_open_extent_data_files()` after opening an image (vmdkmount `mount_handle.c:590/931`, pyvmdk `handle.open_extent_data_files()`), which invokes the vulnerable function once per non-ZERO extent. Repeatedly opening a crafted image with many extents grows the heap without bound; long-running mounting/forensic services can be exhausted (denial of service). 500 calls leaked 500 buffers totaling 10500 bytes (21 bytes each, exactly matching the 20-character filename plus NUL). The submission does not assert demonstrated confidentiality disclosure, code execution, or privilege escalation.
## Proof of Concept
PoC archive: `poc/01_memory_leak_poc.zip`
PoC URL: https://github.com/user-attachments/files/33394147/01_memory_leak_poc.zip (attached to issue #39; SHA-256 verified identical to the local copy on 2026-10-14)
Contents: `poc2_many_extents.vmdk` (8462-byte descriptor file with 200 `RW 4192256 SPARSE "nonexistent_xxx.vmdk"` entries), the generator script `gen_poc2_descriptor.py`, the driver `poc2_leak_driver.c`, and the expected output.
Command (libvmdk commit 396e187, Ubuntu 24.04, gcc 13.3.0, ASan/LSan):
```bash
python3 gen_poc2_descriptor.py poc2_many_extents.vmdk 200
gcc -g -O1 -fsanitize=address -I ~/build/libvmdk-verify/include \
poc2_leak_driver.c -o drv \
-L ~/build/libvmdk-verify/libvmdk/.libs -lvmdk
LD_LIBRARY_PATH=~/build/libvmdk-verify/libvmdk/.libs \
ASAN_OPTIONS=detect_leaks=1 ./drv poc2_many_extents.vmdk 500
# the driver first calls libvmdk_set_codepage(1252) to activate the leak branch,
# then loops 500x: initialize -> open -> open_extent_data_files -> free
```
Observed sanitizer result:
```text
Direct leak of 10500 byte(s) in 500 object(s) allocated from:
#1 in libvmdk_extent_table_get_extent_data_file_path .../libvmdk/libvmdk_extent_table.c:869
#2 in libvmdk_handle_open_extent_data_files .../libvmdk/libvmdk_handle.c:1304
#3 in main poc2_leak_driver.c:47
SUMMARY: AddressSanitizer: 11111 byte(s) leaked in 509 allocation(s).
```
## Root Cause
The success path assumes single-buffer ownership. In the `libclocale_codepage == 0` branch the function transfers ownership (`narrow_filename = (char *) utf8_filename; utf8_filename = NULL;`, lines 898-903), so the single `memory_free(narrow_filename)` before `return(1)` is correct. In the non-zero codepage branch both buffers exist independently, but the success path frees only `narrow_filename`; there is no corresponding free (or NULL-guarded free) for `utf8_filename`. The `on_error` handler frees both, and the wide-character variant frees `utf8_filename` mid-function, so the narrow success path is the only path that abandons the allocation.
## Countermeasure
As of 2026-10-14 the vulnerability is unfixed and upstream issue #39 is still open. Environments that cannot wait for an upstream fix should:
- Avoid processing untrusted VMDK files with non-zero codepage on narrow builds, or run with codepage 0 (UTF-8).
- Apply per-process memory limits, timeouts, and crash isolation for automated pipelines; recycle the process after each image.
- Run parsing components sandboxed and with low privileges.
Suggested fix direction: free `utf8_filename` before `return(1)` in the narrow success path, mirroring lines 1437-1440 of the wide variant; since the `codepage == 0` branch sets the pointer to NULL, a NULL-guarded free keeps both paths correct.
This entry should be updated with the fix commit and fixed release once the maintainer merges a patch. |
|---|
| Источник | ⚠️ https://github.com/libyal/libvmdk/issues/39 |
|---|
| Пользователь | fczhang (UID 97720) |
|---|
| Представление | 13.10.2026 18:37 (23 дни назад) |
|---|
| Модерация | 05.11.2026 19:11 (23 days later) |
|---|
| Статус | принято |
|---|
| Запись VulDB | 431574 [libyal libvmdk до 3fdd7839758e9f44ef95e1dfccde8552b860a4fc Extent Data File libvmdk_extent_table.c libvmdk_extent_table_get_extent_data_file_path повреждение памяти] |
|---|
| Баллы | 20 |
|---|