Skip to content

VmdkDisk fails to parse descriptor with non-UTF-8 encoding (e.g. GBK), causing mangled extent/disk filenames and FileNotFoundError #90

Description

@yuejiyueren

When parsing an embedded VMDK descriptor, VmdkDisk (in vmdk.py) always decodes the raw descriptor bytes as utf-8, without checking the descriptor's own encoding= attribute first. VMware Workstation running on a Chinese-locale (or other non-UTF‑8 locale) Windows host can write descriptors that declare encoding="GBK". Decoding such a descriptor as utf-8 does not raise an error (errors="replace" is used), but it silently corrupts any non-ASCII characters in the descriptor — including the extent filenames (ddb.filename / RW ... "diskname-sXXX.vmdk" lines).

As a result, the disk/extent filename parsed from the descriptor no longer matches the actual file on disk, and opening the split/multi-extent VMDK fails with a FileNotFoundError, even though the referenced file physically exists (just under its correctly-encoded name).

To Reproduce

  1. Create (or obtain) a split VMDK on a GBK-locale Windows host where the descriptor declares encoding="GBK" and the disk name / extent filenames contain non-ASCII (e.g. Chinese) characters, e.g.:
    # Disk DescriptorFile
    version=1
    encoding="GBK"
    CID=369b13fd
    parentCID=ffffffff
    createType="twoGbMaxExtentSparse"
    ...
    RW 4192256 SPARSE "CentOS 64 副本-s001.vmdk"
    
  2. Open the VMDK via dissect.hypervisor / dissect.target:
    from dissect.target.containers.vmdk import VmdkContainer
    VmdkContainer(path)

Expected behavior

The descriptor should be re-decoded using the encoding declared in its own encoding= attribute (falling back to utf-8 when absent or unsupported), so that extent filenames containing non-ASCII characters are parsed correctly and the referenced extent files can be located and opened.

Actual behavior

Because the descriptor is decoded as utf-8 regardless of the declared encoding, non-ASCII characters in the extent filename are mangled (e.g. 副本 becomes λ), and opening the disk fails:

Traceback (most recent call last):
  File "dissect\target\container.py", line 236, in open
    return container(item, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "dissect\target\helpers\lazy.py", line 68, in __call__
    return self._load()(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "dissect\target\containers\vmdk.py", line 20, in __init__
    self.vmdk = vmdk.VMDK(fh)
                ^^^^^^^^^^^^^
  File "dissect\hypervisor\disk\vmdk.py", line 66, in __init__
    sdisk_fh = path.with_name(extent.filename).open("rb")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pathlib.py", line 1013, in open
FileNotFoundError: [Errno 2] No such file or directory: 'E:\\VM\\Centos_74_3_FZ_TEST\\CentOS 64 λ-s001.vmdk'

Note that CentOS 64 λ-s001.vmdk is the corrupted extent filename produced by decoding GBK-encoded bytes as UTF‑8 with errors="replace"; the actual file on disk has a correctly-encoded (Chinese) name and does exist.

Environment

  • dissect.hypervisor version: (fill in pip show dissect.hypervisor)
  • OS: Windows (VMDK created/exported on a GBK-locale host)
  • Python version: (fill in)

Suggested fix

After the initial best-effort decode of the descriptor, check self.descriptor.attr.get("encoding") and, if it differs from utf-8, re-parse the raw descriptor bytes using that encoding (with a safe fallback to the original utf-8 parse if the declared encoding is invalid/unsupported by Python's codec registry).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions