Mounten eines vmdk-Laufwerks im Linux Host – IV – guestmount, virt-filesystems, qemu-img

In den vorhergehenden Beiträgen dieser Serie

Mounten eines vmdk Laufwerks im Linux Host – I – vmware-mount
Mounten eines vmdk-Laufwerks im Linux Host – II – Einschub, Spezifikation, Begriffe
Mounten eines vmdk-Laufwerks im Linux Host – III – qemu-nbd, loop-devices, kpartx

hatten wir gesehen, dass der Zugang zu komplexen vmdk-Images mit Snapshots, Extents und Base-Disk Files eine Kontrolle über das vmdk-Format und die zugehörige Block-Adressierung erfordert. Die notwendigen Informationen sind ggf. über mehrere Files in unterschiedlichen Ästen des Filesystems eines Hosts verteilt; eine Verwendung unter Linux erfordert daher einen zwischengeschalteten Layer:

  • Das Tool “vmware-mount” produziert vor dem automatischen Mounten auf ein Zielverzeichnis aus den verstreuten Dateien des vmdk-Images zunächst ein zusammenhängendes “flat”- oder “raw”-File. Die darin beherbergten Partitionen/Filesysteme können wir dabei zur Not auch selbst mit fdisk/parted erkennen und als Loop-Devices mounten. Dabei sind Offset-Angaben zu beachten.
  • Das Tool “qemu-nbd” interpretiert komplexe vmdk-Images ebenfalls korrekt und bietet dem User über ein Kernelmodul einen Block-Layer an: das Disk-Image wird als Ganzes als Block-Device angeboten. Zudem werden enthaltene Filesysteme automatisch erkannt und ebenfalls als Block-Devices angeboten, wenn das Modul entsprechend parametriert wurde. Die im Block-Device der gesamten Disk enthaltenen Filesysteme können alternativ aber auch über Loop-Devices angesprochen werden.

Wir hatten zudem erkannt, dass man beim Einsatz der bisher besprochenen Tools bzgl. der resultierenden Zugriffsrechte aufpassen muss:

Ein automatisches Mounten mit vmware-mount geht mit Zugriffsrechten viel zu freizügig um. Eigene Mount-Befehle sind dagegen mit entsprechenden Optionen zu berechtigten Usern und Zugriffsmasken zu versehen – soweit möglich.

Wir stellen nun ein Tool vor, dass Sicherheitsaspekte beim Mounten von Disk-Images auf Hosts von Haus aus noch etwas ernster nimmt und FUSE nutzt, um Filesysteme von Disk-Image-Dateien unter Linux in handlicher Weise bereit zu stellen: guestmount.

Flankierend betrachten wir in diesem Artikel zudem zwei Tools, die es einem erlauben, die Snapshot- und Extent-Verteilung eines vmdk-Images sowie die enthaltenen Filesysteme vorab auch ohne Mount-Prozess zu ermitteln: qemu-img und virt-filesystems. Für den Einstieg in forensische Arbeiten mit unbekannten, komplexen vmdk-Images sind diese Kommandos zusammen mit Zeitstempelinformationen durchaus wertvoll.

Vorsicht bei Experimenten

Auch im Falle von “guestmount” gilt: Konkurrierende Schreibzugriffe auf das Disk-Image sind zu vermeiden. Das bedeutet, dass die virtuelle (VMware-, QEMU-, Virtualbox-) Maschine, die das vmdk-Image normalerweise als Disk nutzt, abgeschaltet sein muss. Zur Sicherheit Kopien der Disk-Images anlegen und ggf. nur “read only” mounten.

Notwendige Pakete

“guestmount” nutzt die libguestfs-Bibliothek. Das Kommando gehört zu einem ganzen Set von Tools, die seit 2009 für Virtualisierung (im Besonderen mit QEMU) entwickelt und optimiert wurden. Siehe hierzu die ganz unten angegebenen Links. Unter Opensuse benötigt man für “libguestfs” die Pakete libguestfs0, guestfs-tools,
guestfs-data und ggf. perl-Sys-Guestfs. Installieren sollte man in jedem Fall auch “qemu-tools“.

Unter Debian/Kali gibt es ebenfalls eine ganze Reihe von Paketen (s. den Link unten); das Notwendigste wird aber im Zuge der Installation von “libguestfs-tools” bereitgestellt. Das zudem nützliche Paket “qemu-utils” hatten wir schon im letzten Artikel erwähnt.

Interessant ist (unter Opensuse) im Besonderen das Paket guestfs-data: Die Beschreibung dieses RPM-Pakets zeigt, dass es eine minimale virtuelle Maschine (nach dem Supermin-Muster) beinhaltet, die offenbar von libguestfs-Anwendungen verwendet wird – wie wir sehen werden, auch von “guestmount”.

Bevor man “guestmount” einzusetzt, lohnt es sich, zunächst ein paar Informationen über das vmdk-Image und enthaltene Filesysteme zu sammeln.

Beschaffen von Infos zu Snapshots, Extents in vmdk-Disk-Image

Ein wichtiges Tool, um sich Informationen zur Datei-Struktur (Snapshot- und Extent-Files) von Disk-Images für virtuelle Maschinen zu verschaffen, ist “qemu-img“. Ein Auszug aus der man-Seite besagt:

qemu-img allows you to create, convert and modify images offline. It can handle all image formats supported by QEMU. .... The following commands are supported: ....
...
info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename
....
snapshot [--object objectdef] [--image-opts] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename
...
	snapshot is the name of the snapshot to create, apply or delete
...
    	-l  lists all snapshots in the given image
...
info [-f fmt] [--output=ofmt] [--backing-chain] filename
           Give information about the disk image filename. Use it in particular to know the size reserved on disk which can be different from the displayed size. If VM snapshots are stored in the disk image, they are displayed too. The command can output in the format ofmt           which is either "human" or "json".

           If a disk image has a backing file chain, information about each disk image in the chain can be recursively enumerated by using the option "--backing-chain".
....

 
Ähnliche Informationen gibt uns auch “qemu-img -h”. Der Wiki-Link zu “Qemu/Images” unten bestätigt, dass “qemu-img” die vmdk-Formate 3,4 und 6 unterstützt.

Der Ausdruck “backing-chain” erinnert den aufmerksamen Leser natürlich sofort an die “Link-Kette” für vmdk-Snapshots, die wir im zweiten Artikel dieser Serie angesprochen hatten.
Wer meinen letzten Artikel gelesen hat, weiß, dass ich ein vmdk-Test-Image habe, das drei Snapshots aufweist und dessen Base-Disk-File in einem anderen Verzeichnis liegt als die Dateien zu den Snapshots. Damit wollen wir “qemu-img” mal testen. (Ich mache das nachfolgend als User root; erforderlich ist das bei hinreichenden Zugriffsrechten auf die Image-Dateien aber keinesfalls.)

mytux:/vmw/Win7Test # qemu-img info Win7_x64_ssdx-000003.vmdk
image: Win7_x64_ssdx-000003.vmdk
file format: vmdk
virtual size: 4.0G (4294967296 bytes)
disk size: 24M
cluster_size: 65536
backing file: Win7_x64_ssdx-000002.vmdk
Format specific information:
    cid: 4245824591
    parent cid: 1112365808
    create type: twoGbMaxExtentSparse
    extents:
        [0]:
            virtual size: 4261412864
            filename: Win7_x64_ssdx-000003-s001.vmdk
            cluster size: 65536
            format: SPARSE
        [1]:
            virtual size: 33554432
            filename: Win7_x64_ssdx-000003-s002.vmdk
            cluster size: 65536
            format: SPARSE

Wir sehen hier offenbar den Beginn der Snapshot-Historie: Der dritte VMware-Snapshot “Win7_x64_ssdx-000003.vmdk”, der bislang offenbar nur geringe Veränderungen aufnehmen musste, setzt auf auf einem “backing file” auf: Win7_x64_ssdx-000002.vmdk. Wir sehen damit allerdings noch nicht die gesamte Snapshot-Historie (s.u.).

Dafür erkennen wir aber, dass der Inhalt pro Snapshot über 2 sparse Extents verteilt ist. Die zugehörige CID-Information ist – wie wir aus dem 2-ten Artikel der Serie wissen – im Deskriptor-File des Snapshots beinhaltet. Insgesamt gilt, dass “qemu-img” im Fall von vmdk_Images im Wesentlichen den Inhalt der Deskriptor-Dateien darstellt.

Übersicht über die gesamte Backing-Chain
Wollen wir die gesamte Backing-Chain – also im Fall von vmdk-Images die vollständige Snapshot-Historie – sehen, müssen wir beim Kommando zusätzlich eine Unteroption “- -backing-chain” angeben:

mytux:/vmw/Win7Test # qemu-img info --backing-chain Win7_x64_ssdx-000003.vmdk
image: Win7_x64_ssdx-000003.vmdk
file format: vmdk
virtual size: 4.0G (4294967296 bytes)
disk size: 24M
cluster_size: 65536
backing file: Win7_x64_ssdx-000002.vmdk
Format specific information:
    cid: 4245824591
    parent cid: 1112365808
    create type: twoGbMaxExtentSparse
    extents:
        [0]:
            virtual size: 4261412864
            filename: Win7_x64_ssdx-000003-s001.vmdk
            cluster size: 65536
            format: SPARSE
        [1]:
            virtual size: 33554432
            filename: Win7_x64_ssdx-000003-s002.vmdk
            cluster size: 65536
            format: SPARSE

image: Win7_x64_ssdx-000002.vmdk
file format: vmdk
virtual size: 4.0G (4294967296 bytes)
disk size: 1.1M
cluster_size: 65536
backing file: Win7_x64_ssdx-000001.vmdk
Format specific information:
    cid: 1112365808
    parent cid: 3509963510
    create type: twoGbMaxExtentSparse
    extents:
        [0]:
            virtual size: 4261412864
            filename: Win7_x64_ssdx-000002-s001.vmdk
            cluster size: 65536
            format: SPARSE
        [1]:
            virtual size: 33554432
            filename: Win7_x64_ssdx-000002-s002.vmdk
            cluster size: 65536
            format: SPARSE

image: Win7_x64_ssdx-000001.vmdk
file format: vmdk
virtual size: 4.0G (4294967296 bytes)
disk size: 1.0M
cluster_size: 65536
backing file: /vmw/Win7/Win7_x64_ssdx.vmdk
Format specific information:
    cid: 3509963510
    parent cid: 3060125035
    create type: twoGbMaxExtentSparse
    extents:
        [0]:
            virtual size: 4261412864
            filename: Win7_x64_ssdx-000001-s001.vmdk
            cluster size: 65536
            format: SPARSE
        [1]:
            virtual size: 33554432
            filename: Win7_x64_ssdx-000001-s002.vmdk
            cluster size: 65536
            format: SPARSE

image: /vmw/Win7/Win7_x64_ssdx.vmdk
file format: vmdk
virtual size: 4.0G (4294967296 bytes)
disk size: 2.2G
cluster_size: 65536
Format specific information:
    cid: 3060125035
    parent cid: 4294967295
    create type: twoGbMaxExtentSparse
    extents:
        [0]:
            virtual size: 4261412864
            filename: /vmw_win7/Win7_x64_ssdx-s001.vmdk
            cluster size: 65536
            format: SPARSE
        [1]:
            virtual size: 33554432
            filename: /vmw_win7/Win7_x64_ssdx-s002.vmdk
            cluster size: 65536
            format: SPARSE
mytux:/vmw/Win7Test #   

 
“qemu-img” stellt uns eine über mehrere Filesystem-Orte verteilte Snapshot- und Extent-Zusammensetzung eines vmd-Images konsolidiert dar. Sprich: Durch die Option “- – backing-chain” werden alle Deskriptor-Dateien zu allen
Snapshots ausgelesen und in der richtigen Reihenfolge ausgegeben. Das ist zumindest im Falle mehrerer Disks und vieler Snapshots recht nützlich, zumal wenn unterschiedliche Disks eines VMware-Gastes sehr unterschiedliche Snapshot-Historien aufweisen sollten. Was einem in der Praxis durchaus unter die Finger kommt.

Leider muss der Linux-User aber von vornherein wissen, in welchem Verzeichnis man den jüngsten Snapshot (mit der höchsten Nummer im Namenszusatz) und die zugehörige Deskriptor-Datei findet. Die Verlinkung der vmdk-Snapshot-Chain erfolgt nur nach unten in Richtung Base-File – also einseitig.

Die im “type twoGbMaxExtentSparse” angegebenen 2GB für die Extends muss man unter aktuellen Linux-Systemen nicht zu ernst nehmen; faktisch operiert z.B. die VMware WS 14 mit wachsenden 4 GB Extents.

Übrigens:

Da Snapshots in vmdk-Images über eine Backing-Chain (im VMware-Sprech: eine Link-Chain) realisiert werden, liefert uns das Kommando “qemu-img snapshot -l” keine passende Informationen; die Snapshots sind anders als etwa in qcow2-Disks nicht intrinsischer Teil des/der primären Image-Files.

mytux:/vmw/Win7Test # qemu-img snapshot -l  Win7_x64_ssdx-000003.vmdk
mytux:/vmw/Win7Test # 

Beschaffen von Informationen zu Filesystemen in einem vmdk-Disk-Image

Das obige Kommando hat uns noch nicht gezeigt, welche Partitionen/Filesysteme in der Disk aktuell beheimatet sind. Diese Information benötigen wir aber für die Anwendung von “guestmount”. Hier hilft die “libguestfs” mit dem Tool “virt-filesystems” weiter:

mytux:/vmw/Win7Test # virt-filesystems -a Win7_x64_ssdx-000003.vmdk -l
Name       Type        VFS   Label   Size        Parent
/dev/sda1  filesystem  ntfs  Volume  2718957568  -
/dev/sda2  filesystem  ntfs  Volume  1572864000  -

oder – für die zusätzliche Ausgabe von Partitionen:

mytux:/vmw/Win7Test # virt-filesystems -a Win7_x64_ssdx-000003.vmdk --all --long --uuid -h
Name      Type       VFS  Label  MBR Size Parent   UUID
/dev/sda1 filesystem ntfs Volume -   2.5G -        00E60BCAE60BBF42
/dev/sda2 filesystem ntfs Volume -   1.5G -        42A048ACA048A7ED
/dev/sda1 partition  -    -      07  2.5G /dev/sda -
/dev/sda2 partition  -    -      07  1.5G /dev/sda -
/dev/sda  device     -    -      -   4.0G -        -

Gut, nicht wahr?
Hinweis:

Die Bezeichnungen “/dev/sda1”, “/dev/sda2” haben nichts mit evtl. existierenden, gleichnamigen Devices des aktuellen Hosts zu tun. Die Bezeichnungen beziehen sich ausschließlich auf interne Partitionen des Disk-Images.

Zu weiteren Optionen, wie etwa “–extra” für die Anzeige weiterer nicht mountbarer Filesysteme, siehe die man-page zum Kommando.

guestmount – bequemes Mounten vorhandener vmdk-Filesysteme

Mit dem obigen Wissen ausgestattet, können wir nun endlich guestmount einsetzen. Die Kommandostruktur ist für den Normalfall recht einfach

guestmount -a img-file -m /dev/sdax [–ro] mount-point-im-Linux-host

Wollen wir also in unserem Beispiel das zweite Filesystem mounten, so ist Folgendes anzugeben:

mytux:/vmw/Win7Test # guestmount -a Win7_x64_ssdx-000003.vmdk  -m /dev/sda2  --ro /mnt3 
mytux:/vmw/Win7Test # la /mnt3/
$RECYCLE.BIN/                           System Volume Information/
Cosmological_Voids/                     mysql-installer-community-5.6.14.0.msi
Muflons/                                ufos/
mytux:/vmw/Win7Test # la /mnt3/ufos/
total 5
drwxrwxrwx 1 root root    0 Mar 31 15:26 .
drwxrwxrwx 1 root root 4096 Mar 28 20:25 ..
-rwxrwxrwx 1 root root   18 
Mar 31 15:26 ufo.txt
-rwxrwxrwx 1 root root    0 Mar 31 14:02 xufos
mytux:/vmw/Win7Test #
mytux:/vmw/Win7Test # guestunmount  /mnt3 
mytux:/vmw/Win7Test # 

Hinweise:

  • Zum Entfernen eines Mounts muss man das Kommand “guestunmount” verwenden.
  • Die Option “–ro” sorgt dafür, dass “read-only” gemountet wird.

guestmount – Möglichkeit zum gestaffelten Mounten

Es gibt weitere Optionen und Einsatzmöglichkeiten für “guestmount”, die man der man-Seite entnehmen kann. Die anderen Möglichkeiten sind aber eher für Linux/Unix-Filesysteme im vmdk-Image geeignet. Auf eine Möglichkeit – nämlich die eines geschachtelten Mounts in einem Schritt – möchte ich aber doch hinweisen.

Eines meiner mit VMware virtualisierten Windows 7-Testsysteme weist ein (freies) Verzeichnis “mounts/mnt2” auf. Der aktuelle Snapshot des Hauptsystems mit dem Win7-OS heißt “Win7_x64-cl1-000011.vmdk”. Dann kann man etwa Folgendes machen:

mytux:/vmw/Win7Test # guestmount -a Win7_x64-cl1-000005.vmdk -m /dev/sda1 -a Win7_x64_ssdx-000003.vmdk  -m /dev/sdb2:/mounts/mnt2  --ro /mnt2 
mytux:/vmw/Win7Test # la /mnt2/
total 4194272
drwxrwxrwx  1 root root          0 Jan 25  2014 $Recycle.Bin
drwxrwxrwx  1 root root      12288 Mar 20 18:05 .
drwxr-xr-x 39 root root       4096 Mar 28 17:02 ..
....
-rwxrwxrwx  1 root root       8192 Aug 23  2012 BOOTSECT.BAK
drwxrwxrwx  1 root root       4096 Sep 23  2016 Boot
lrwxrwxrwx  2 root root         60 Jul 14  2009 Documents and Settings -> /sysroot/Users
lrwxrwxrwx  2 root root         60 Aug 23  2012 Dokumente und Einstellungen -> /sysroot/Users
....
drwxrwxrwx  1 root root       4096 Jan 25  2014 Users
drwxrwxrwx  1 root root      24576 Apr  8 11:43 Windows
...
-rwxrwxrwx  1 root root 4294434816 Apr  8 11:41 pagefile.sys
drwxrwxrwx  1 root root       4096 Mar 27 19:37 mounts
...

mytux:/vmw/Win7Test # la /mnt2/mounts/mnt2/ufos/
total 5
drwxrwxrwx 1 root root    0 Mar 31 15:26 .
drwxrwxrwx 1 root root 4096 Mar 28 20:25 ..
-rwxrwxrwx 1 root root   18 Mar 31 15:26 ufo.txt
-rwxrwxrwx 1 root root    0 Mar 31 14:02 xufos

mytux:/vmw/Win7Test # la /mnt2/mounts
total 28
drwxrwxrwx 1 root root  4096 Mar 27 19:37 .
drwxrwxrwx 1 root root 12288 Mar 20 18:05 ..
drwxrwxrwx 1 root root     0 Mar 22 10:30 mnt
drwxrwxrwx 1 root root  4096 Mar 28 20:25 mnt2
lrwxrwxrwx 1 root root   216 Mar 27 19:21 mnt3 -> /sysroot/.NTFS-3G/Volume{c5......}
lrwxrwxrwx 1 root root   216 Mar 27 19:37 mnt4 -> /sysroot/.NTFS-3G/Volume{a4......}

Nett, nicht wahr? Man beachte, dass die Partitionen des zweiten mit der Option “-a” bereitgestellten Images mit “/dev/sdbx” bezeichnet werden. Einige Informationen wurden im obigen Auszug mit “….” ersetzt.

Die Frage ist halt, in wieweit ein solcher geschachtelter Mount mit Windows-Systemen Sinn macht. Man könnte einwenden, dass auch unter Windows Disks in den Verzeichnisbaum gemountet werden können. Stimmt auch – nur wird ein solcher Mount viel umständlicher realisiert als unter Linux. Im obigen Beispiel zeigen die letzten Zeilen gerade solche belegten Mount-Punkte. Die dortigen Windows-Verweise führen aber ohne gestartetes System ins Nirwana. So funktioniert Folgendes leider nicht:

            
mytux:/vmw/Win7Test #  guestmount -a Win7_x64-cl1-000005.vmdk -m /dev/sda1 -a Win7_x64_ssdx-000003.vmdk  -m /dev/sdb2:/mounts/mnt4  --ro /mnt2 
libguestfs: error: mount_options: mount: /mounts/mnt4: No such file or directory
guestmount: '/dev/sdb2' could not be mounted.
guestmount: Did you mean to mount one of these filesystems?
guestmount:     /dev/sda1 (ntfs)
guestmount:     /dev/sdb1 (ntfs)
guestmount:     /dev/sdb2 (ntfs)

Man kann daher – auch wennn man schon weiß, wie
bestimmte NTFS-Partitionen in das Windows-Hauptlaufwerk gemountet werden – diese Verhältnisse unter Linux nicht direkt nachstellen.

Auf ähnliche Einschränkungen stößt man bzgl. der Guestmount-Option “-i” für vmdk-Images. Auch eine automatische Aufdröselung von Mount-Punkten funktioniert mit NTFS-Filesystemen nicht. Das ist aber nicht so schlimm; Forensiker können die wahre Struktur eine Windows-Maschine über die Registry (in Subverzeichnissen von Windows/System32/config) und Infos in weiteren Verzeichnissen auslesen.

guestmount – Sicherheit über Einsatz einer minimalen virtuellen QEMU-Maschine

Der Leser erinnert sich sicher an die mahnenden Worte von D.P.Berrange in
https://www.berrange.com/tags/libguestfs/
bzgl. der Risiken beim Mounten von Disk-Images virtualisierter Gastsysteme auf einem Linux-Host. Weitere Hinweise auf solche Risiken liefern die Entwickler von libguestfs unter folgendem Link:
http://libguestfs.org/guestfs-security.1.html.

Um evtl. Problemen mit manipulierten Disk-Images und ihren Filesystemen vorzubeugen, operiert “libguestfs” mit einer virtuellen QEMU-Maschine im Hintergrund. Ich zitiere aus dem Text des eben genannten Links:

“We run a Linux kernel inside a qemu virtual machine, usually running as a non-root user. The attacker would need to write a filesystem which first exploited the kernel, and then exploited either qemu virtualization (eg. a faulty qemu driver) or the libguestfs protocol, and finally to be as serious as the host kernel exploit it would need to escalate its privileges to root. Additionally if you use the libvirt back end and SELinux, sVirt is used to confine the qemu process. This multi-step escalation, performed by a static piece of data, is thought to be extremely hard to do, although we never say ‘never’ about security issues.”

Hervorhebung durch mich. Leute, dieser Ansatz gefällt mir! Dennoch funktioniert er auf einem Opensuse-System ohne SE-Linux, aber mit AppArmor, leider nicht vollständig (s.u.).

Können wir die virtuelle QEMU-Maschine (die übrigens von der Supermin-Gattung ist) sehen? Ja das geht; z.B. als unpriviligierter User “myself”:

myself:/vmw/ssdx> ps aux | grep qemu
myself      18986  0.0  0.0  10564  1640 pts/8    S+   12:22   0:00 grep --color=auto qemu
myself:/vmw/ssdx> guestmount -a Win7_x64_ssdx.vmdk  -m /dev/sda2  --ro /mnt/vmdk                                                        
myself:/vmw/ssdx> ps aux | grep qemu
myself      19002 19.8  0.3 1534676 247408 pts/8  Sl   12:22   0:00 /usr/bin/qemu-system-x86_64 -global virtio-blk-pci.scsi=off -nodefconfig -enable-fips -nodefaults -display none -machine accel=kvm:tcg -cpu host -m 500 -no-reboot -rtc driftfix=slew -no-hpet -global kvm-pit.lost_tick_policy=discard -kernel /var/tmp/.guestfs-1553/appliance.d/kernel -initrd /var/tmp/.guestfs-1553/appliance.d/initrd -device virtio-scsi-pci,id=scsi -drive file=/tmp/libguestfsCrlFc9/overlay1,cache=unsafe,format=qcow2,id=hd0,if=none -device scsi-hd,drive=hd0 -drive file=/var/tmp/.guestfs-1553/appliance.d/root,snapshot=on,id=appliance,cache=unsafe,if=none -device scsi-hd,drive=appliance -device virtio-serial-pci -serial stdio -device sga -chardev socket,path=/tmp/libguestfsCrlFc9/guestfsd.sock,id=channel0 -device virtserialport,chardev=channel0,name=org.libguestfs.channel.0 -append panic=1 console=ttyS0 udevtimeout=6000 udev.event-timeout=6000 no_timer_check acpi=off printk.time=1 cgroup_disable=memory root=/dev/sdb selinux=0 TERM=xterm-256color                                                                                                                                      
myself      19021  0.0  0.0  10564  1648 pts/8    S+   12:22   0:00 grep --color=auto qemu
myself:/vmw/ssdx> guestunmount /
mnt/vmdk
myself:/vmw/ssdx> ps aux | grep qemu
myself      19047  0.0  0.0  10564  1652 pts/8    S+   12:22   0:00 grep --color=auto qemu
myself:/vmw/ssdx> 

Man beachte die leider erfolgte Deaktivierung des Security Models durch den Parameter “selinux=0”; auf meinem Opensuse-System läuft AppArmor.

Immerhin: Es ist gut, dass eine virtuelle Maschine bei der Ausführung der guestmount- oder generell von libguestfs-Befehle zwischengeschaltet wird. Wie genau die Übergänge zwischen Fuse auf dem Linux-Host, dem Starten einer QEMU-Maschine, dem nachfolgenden Mount-Prozess innerhalb der QEMU-Machine (wiederum unter Einbeziehung von FUSE für das dortige Mounten des entdeckten Filesystems, z.B. NTFS) und dem Re-Export des schließlich emulierten Block-Devices auf den Host – genauer: auf den dortigen Mount-Point – funktioniert, muss uns als Anwender – Gott sei Dank – nicht interessieren. Aus dem Jahr 2009 stammt vom Erfinder folgende Darstellung der Prozess-Kette:

            
Linux VFS (in the host) -> fuse -> guestmount process -> libguestfs -> XDR protocol over a TCP socket -> host kernel -> QEMU’s SLIRP stack -> guest kernel -> guestfsd -> Linux VFS (in the guest) -> fuse -> mount-ntfs-3g -> Windows block device -> QEMU (emulating the block device) -> host kernel -> real block device

Siehe: https://rwmj.wordpress.com/2009/10/30/fuse-support-for-libguestfs/

Teile davon dürften heute wohl noch stimmen. Habe aber keine genaue Ahnung … 🙂 .

Ein paar Infos zur virtuellen libguestfs-QEMU-Maschine

Man kann das Starten der virtuellen Maschine auch an “libvirtd” deligieren. Das hat den Vorteil, dass man mittels per virsh-Kommandos ein paar Informationen über die virtuelle QEMU-Maschine ermitteln kann. Notwendig zum Involvieren von “libvirt” ist das Setzen einer Umgebungsvariablen für die Shell des unpriviligierten Users:

export LIBGUESTFS_ATTACH_METHOD=libvirt

Führen wir dann wieder “guestmount” aus, sehen wir, dass der Aufruf der virtuellen Maschine mit anderer Parametersetzung erfolgt:

myself:/vmw/ssdx> export LIBGUESTFS_ATTACH_METHOD=libvirt
myself:/vmw/ssdx> guestmount -a Win7_x64_ssdx.vmdk  -m /dev/sda2  --ro /mnt/vmdk
myself:/vmw/ssdx> ps aux | grep qemu
myself      13201  5.2  0.3 1927592 261572 ?      Sl   17:20   0:01 /usr/bin/qemu-system-x86_64 -machine accel=kvm -name guest=guestfs-7pup8sjqcmvakaoz,debug-threads=on -S -object secret,id=masterKey0,format=raw,file=/home/myself/.config/libvirt/qemu/lib/domain-1-guestfs-7pup8sjqcmva/master-key.aes -machine pc-i440fx-2.9,accel=kvm,usb=off,dump-guest-core=off -cpu host -m 500 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 61273dde-6a1c-4c0a-be8d-ae06494041aa -display none -no-user-config -nodefaults -device sga -chardev socket,id=charmonitor,path=/home/rmo/.config/libvirt/qemu/lib/domain-1-guestfs-7pup8sjqcmva/monitor.sock,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=delay -no-hpet -no-reboot -no-acpi -boot strict=on -kernel /var/tmp/.guestfs-1553/appliance.d/kernel -initrd /var/tmp/.guestfs-1553/appliance.d/initrd -append panic=1 console=ttyS0 udevtimeout=6000 udev.event-timeout=6000 no_timer_check acpi=off printk.time=1 cgroup_disable=memory root=/dev/sdb selinux=0 TERM=xterm-256color -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x3 -drive file=/tmp/libguestfsi5ApZX/overlay1,format=qcow2,if=none,id=drive-scsi0-0-0-0,cache=unsafe -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=1 -drive 
file=/tmp/libguestfsi5ApZX/overlay2,format=qcow2,if=none,id=drive-scsi0-0-1-0,cache=unsafe -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=1,lun=0,drive=drive-scsi0-0-1-0,id=scsi0-0-1-0 -chardev socket,id=charserial0,path=/tmp/libguestfsi5ApZX/console.sock -device isa-serial,chardev=charserial0,id=serial0 -chardev socket,id=charchannel0,path=/tmp/libguestfsi5ApZX/guestfsd.sock -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=org.libguestfs.channel.0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 -msg timestamp=on
myself      13256  0.0  0.0  10564  1612 pts/5    S+   17:20   0:00 grep --color=auto qemu
myself:/vmw/ssdx> 

virsh zeigt uns auch Devices der virtuellen Maschine an; leider aber nicht Details:

myself:/vmw/ssdx> virsh
Willkommen bei virsh, dem interaktiven Virtualisierungsterminal.

Tippen Sie:  'help' für eine Hilfe zu den Befehlen
       'quit' zum Beenden

virsh # list
 Id    Name                           Status
----------------------------------------------------
 1     guestfs-7pup8sjqcmvakaoz       laufend

virsh # domblklist guestfs-7pup8sjqcmvakaoz
Ziel       Quelle
------------------------------------------------
sda        /tmp/libguestfsi5ApZX/overlay1
sdb        /tmp/libguestfsi5ApZX/overlay2

virsh # domblkinfo guestfs-7pup8sjqcmvakaoz sda
Kapazität:     4294967296
Zuordnung:      200704
Physisch:       196672

virsh # domblkinfo guestfs-7pup8sjqcmvakaoz sdb
Kapazität:     4294967296
Zuordnung:      1904640
Physisch:       1966080

Man kann auch noch rausbekommen, dass unser vmdk.file innerhalb der virtuellen Maschine mit /dev/sda assoziiert ist:

virsh # dumpxml guestfs-7pup8sjqcmvakaoz
<domain type='kvm' id='1' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  <name>guestfs-7pup8sjqcmvakaoz</name>
  <uuid>61273dde-6a1c-4c0a-be8d-ae06494041aa</uuid>
  <memory unit='KiB'>512000</memory>
  <currentMemory unit='KiB'>512000</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <os>
    <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type>
    <kernel>/var/tmp/.guestfs-1004/appliance.d/kernel</kernel>
    <initrd>/var/tmp/.guestfs-1004/appliance.d/initrd</initrd>
    <cmdline>panic=1 console=ttyS0 udevtimeout=6000 udev.event-timeout=6000 no_timer_check acpi=off printk.time=1 cgroup_disable=memory root=/dev/sdb selinux=0 TERM=xterm-256color</cmdline>
    <boot dev='hd'/>
    <bios useserial='yes'/>
  </os>
  <cpu mode='host-passthrough' check='none'/>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>destroy</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/bin/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='unsafe'/>
      <source file='/tmp/libguestfsi5ApZX/overlay1'/>
      <backingStore type='file' index='1'>
        <format type='raw'/>
        <source file='/vmw_win7/ssdx/Win7_x64_ssdx.vmdk'/>
        <backingStore/>
      </backingStore>
      <target dev='sda' bus='scsi'/>
      <alias name='scsi0-0-0-0'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='
qemu' type='qcow2' cache='unsafe'/>
      <source file='/tmp/libguestfsi5ApZX/overlay2'/>
      <backingStore type='file' index='1'>
        <format type='raw'/>
        <source file='/var/tmp/.guestfs-1004/appliance.d/root'/>
        <backingStore/>
      </backingStore>
      <target dev='sdb' bus='scsi'/>
      <shareable/>
      <alias name='scsi0-0-1-0'/>
      <address type='drive' controller='0' bus='0' target='1' unit='0'/>
    </disk>
    <controller type='scsi' index='0' model='virtio-scsi'>
      <alias name='scsi0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </controller>
    <controller type='usb' index='0' model='piix3-uhci'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </controller>
    <serial type='unix'>
      <source mode='connect' path='/tmp/libguestfsi5ApZX/console.sock'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='unix'>
      <source mode='connect' path='/tmp/libguestfsi5ApZX/console.sock'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <channel type='unix'>
      <source mode='connect' path='/tmp/libguestfsi5ApZX/guestfsd.sock'/>
      <target type='virtio' name='org.libguestfs.channel.0' state='connected'/>
      <alias name='channel0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <input type='mouse' bus='ps2'>
      <alias name='input0'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input1'/>
    </input>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </memballoon>
  </devices>
  <qemu:commandline>
    <qemu:env name='TMPDIR' value='/var/tmp'/>
  </qemu:commandline>
</domain>

 
Man beachte den zweiten Eintrag unter <devices> !

Das war es dann aber auch schon;

virsh # domfsinfo
Fehler: Befehl 'domfsinfo' erfordert <domain> Option
virsh # domfsinfo guestfs-7pup8sjqcmvakaoz
Fehler: Unable to get filesystem information
Fehler: argument unsupported: QEMU guest agent is not configured

Wie der programmierte Fuse-Prozess auf dem Host das QEMU-Gastsystem und das dort benutzten /dev/sda auf den mountpoint auf dem Host bringt, lässt sich mit einfachen Systemtools niocht weiter analysieren. Das /dev/fuse auf /mnt/vmdk gemountet wird, ist dabei eine wenig aussagekräftige Binsenweisheit:

myself:/vmw/ssdx> mount | grep fuse
fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime)
vmware-vmblock on /run/vmblock-fuse type fuse.vmware-vmblock (rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other)
gvfsd-fuse on /run/user/1553/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1553,group_id=100)
/dev/fuse on /mnt/vmdk type fuse (rw,nosuid,nodev,relatime,user_id=1553,group_id=100)
myself:/
vmw/ssdx> la /sys/fs/fuse/connections/47
insgesamt 0
dr-x------ 2 myself  users 0 13. Apr 17:20 .
drwxr-xr-x 5 root root  0 13. Apr 09:15 ..
--w------- 1 myself  users 0 13. Apr 17:20 abort
-rw------- 1 myself  users 0 13. Apr 17:20 congestion_threshold
-rw------- 1 myself  users 0 13. Apr 17:20 max_background
-r-------- 1 myself  users 0 13. Apr 17:20 waiting

Sicherheit – Zugriff durch andere User?

Die Informationsseiten zu “guestmount” versprechen Folgendes:

Other users cannot see the filesystem by default. .. If you mount a filesystem as one user (eg. root), then other users will not be able to see it by default. The fix is to add the FUSE allow_other option when mounting:
sudo guestmount […] -o allow_other /mnt
and to enable this option in /etc/fuse.conf.

Eine nette Frage ist deshalb: Wie sicher ist denn der Zugang zu dem gemounteten Filesystem? Die angezeigten Rechte deuten eigentlich an, dass jeder zugreifen darf:

myself:/vmw/ssdx> la /mnt/vmdk
insgesamt 196128
drwxrwxrwx 1 root root      4096 28. Mär 19:53 .
drwxr-xr-x 5 root root      4096  8. Apr 11:14 ..
drwxrwxrwx 1 root root      4096 28. Mär 09:53 Cosmological_Voids
-rwxrwxrwx 2 root root 200822784  4. Nov 2013  mysql-installer-community-5.6.14.0.msi
drwxrwxrwx 1 root root         0 28. Mär 09:52 $RECYCLE.BIN
drwxrwxrwx 1 root root         0 28. Mär 09:51 System Volume Information
drwxrwxrwx 1 root root         0 28. Mär 19:53 ufos

Das täuscht aber; den selbst als User “root” erlebt man Folgendes:

mytux:~ # la /mnt/vmdk
ls: cannot access '/mnt/vmdk': Permission denied
mytux:~ # la /mnt/
ls: cannot access '/mnt/vmdk': Permission denied
total 16
drwxr-xr-x  5 root root 4096 Apr  8 11:14 .
drwxr-xr-x 39 root root 4096 Mar 28 17:02 ..
drwxr-xr-x  3 root root 4096 Mar 20  2017 bups
drwxr-xr-x  2 root root 4096 Apr  4  2017 tux
d?????????  ? ?    ?       ?            ? vmdk

Mit dieser Rechtesetzung kann nicht mal der User “root” was anfangen!

Also:

guestmount immer als unpriviligierter User ausführen!

(Auch wenn ich das selbst in den ersten Beispielen dieses Artikels selbst nicht gemacht habe.)

Apparmor als Security-Modell für die libguestfs-QEMU-Maschine wird leider (noch) ignoriert!

Die Tatsache, dass die libguestfs-Etwickler selbst darauf hinweisen, dass für die virtuelle libguestfs-Maschine sVirt und Sicherheitsregeln von SE-Linux/Apparmor zum Zuge kommen, weist uns auf 2 Dinge hin:

  • Wir sollten “guestmount” nicht als root ausführen, wenn das nicht zwingend nötig ist. Die Rechte an den vmdk-Files ändern wir ggf. entsprechend ab.
  • Wir sollten auf dem Linux-System, das wir für unsere Arbeiten verwenden, die Sicherheitseinstellungen für SELinux oder Apparmor prüfen!

Man kann “libvirt” auf einem Opensuse-System, auf dem Aparmor und nicht SE-Linux eingestzt wird, wie folgt konfigurieren: In der Datei “/etc/libvirt/qemu.conf” setzt man:

security_driver = “apparmor”
security_default_confined = 1
security_require_confined = 1

Zur Bedeutung dieser Parameter siehe die Erläuterungen im File selbst. Für normale virtuelle Maschinene funktioniert das auch; als Beispiel mag eine virtuelle Debian-Maschine dienen:

mytux:~ # ps aux | grep debian9
qemu     15096 14.2  0.2 9410692 193460 ?      Dl   17:51   0:08 /usr/bin/qemu-system-x86_64 -machine accel=kvm -name guest=debian9,debug-threads=on -S -object secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-1-debian9/master-key.aes ...
....
mytux~ # virsh 
Welcome to virsh, the virtualization interactive terminal.

Type: 
 'help' for help with commands
       'quit' to quit

virsh # list
 Id    Name                           State
----------------------------------------------------
 1     debian9                        running

virsh # dominfo debian9
Id:             1
Name:           debian9
UUID:           789498d2-e025-4f8e-b255-5a3ac0f9c965
OS Type:        hvm
State:          running
CPU(s):         3
CPU time:       16.4s
Max memory:     8388608 KiB
Used memory:    8388608 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: apparmor
Security DOI:   0
Security label: libvirt-789498d2-e025-4f8e-b255-5a3ac0f9c965 (enforcing)
virsh # 

Man beachte den korrekten Wert “apparmor” für das “Security model”.

[Off topic: Man erkennt übrigens, dass libvirt die QEMU-Maschine dem user qemu zuordnet und selbst mit root-Rechten operiert, selbst wenn man die virtuelle Machine über virt-manager als unprivilegierter User startet.]

Aber für unsere vom User “myself” per guestmount gestartet Maschine liefert virsh:

myself:/vmw/ssdx> virsh
virsh # dominfo guestfs-7pup8sjqcmvakaoz
Id:             1
Name:           guestfs-7pup8sjqcmvakaoz
UUID:           61273dde-6a1c-4c0a-be8d-ae06494041aa
OS Typ:         hvm
Status:         laufend
CPU(s):         1
CPU-Zeit:       1,3s
Max Speicher:   512000 KiB
Verwendeter Speicher: 512000 KiB
Bleibend:       nein
Automatischer Start: deaktiviert
Verwaltete Sicherung: nein
Sicherheits-Modell: none
Sicherheits-DOI: 0

Schade, kein Sicherheitsmodell! Apparmor wird hier ignoriert, obwohl wir den Start der libguestfs-QEMU-Maschine an libvirtd deligiert hatten! Perfekt ist das libguestfs/guestmount an dieser Stelle also (noch!) nicht …

Eine entsprechende Anfrage bei den libguestfs-Entwicklern habe ich übrigens gestartet. Siehe: https://bugzilla.redhat.com/show_bug.cgi?id=1564885

Konvertierung von vmdk-Disk-Images inkl. aller Snapshops und Extents in ein “raw-File” mit Hilfe von qemu-img

Wir kommen am Ende dieses Artikels nochmal auf das eingangs schon betrachtete Tool “qemu-img” zurück: Man kann “qemu-img” auch dazu verwenden, ein vmdk-Disk-Image in genau ein zusammenhängendes “raw-File” umzuwandeln. Das belegt dann allerdings den Plattenplatz, den die Extents bereits einnehmen.

mytux:/vmw/Win7Test # qemu-img convert -f vmdk -O raw -S 4k Win7_x64_ssdx-000003.vmdk image_ssdx.raw
mytux:/vmw/Win7Test # la -h | grep image
-rw-r--r-- 1 root root  4.0G Apr  7 14:46 image_ssdx.raw
mytux:/vmw/Win7Test # du -h image_ssdx.raw 
2.2G    image_ssdx.raw

mytux:/vmw/Win7Test # fdisk -l image_ssdx.raw
Disk image_ssdx.raw: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0efb9e3e

Device          Boot   Start     End Sectors  Size Id Type
image_ssdx.raw1         2048 5312511 5310464  2.5G  7 HPFS/NTFS/exFAT
image_ssdx.raw2      5312512 8384511 3072000  1.5G  7 HPFS/NTFS/exFAT
mytux:/vmw/Win7Test # 
mytux:/vmw/Win7Test # losetup -o 2720006144 /dev/loop2 image_ssdx.raw 
mytux:/vmw/Win7Test # mount /dev/loop2 /mnt2
mytux:/vmw/Win7Test # la /mnt2
total 196128
drwxrwxrwx  1 root root         0 Mar 28 09:52 $RECYCLE.BIN
drwxrwxrwx  1 root root      4096 Mar 28 20:25 .
drwxr-xr-x 39 root root      4096 Mar 28 17:02 ..
drwxrwxrwx  1 root root      4096 Mar 28 09:53 Cosmological_Voids
drwxrwxrwx  1 root root         0 Mar 28 20:26 Muflons
drwxrwxrwx  1 root root         0 Mar 28 09:51 System Volume Information
-rwxrwxrwx  2 root root 200822784 Nov  4  2013 mysql-installer-
community-5.6.14.0.msi
drwxrwxrwx  1 root root         0 Mar 31 15:26 ufos
mytux:/vmw/Win7Test # umount /mnt2
mytux:/vmw/Win7Test # losetup -d /dev/loop2

 
Die Berechnung des Offsets für das “losetup”-Kommando hatten wir schon in den letzten Artikeln besprochen. Die letzten zwei Kommandos drehen alles wieder zurück. Natürlich wird man bei Bedarf beim Mounten noch Einschränkungen der Zugriffsrechte vornehmen; siehe auch hierzu den letzten Artikel.

Vertraut der am Inhalt von vmdk-Files Interessierte/Forensiker also nicht auf “guestmount” oder “vmware-mount”, kann er mit Hilfe von “qemu-img” zunächst immer ein raw-File erstellen, mit dem er dann nach Herzenslust herumwerkeln kann.

Ausblick

Im nächsten Artikel dieser Serie

Mounten eines vmdk-Laufwerks im Linux Host – IV – affuse, vdfuse

werfen wir einen kleinen (etwas entäuschenden) Blick auf “affuse” und “vdfuse”.

Links

Infos zu libguestfs
http://libguestfs.org/
Manuals
http://libguestfs.org/guestfs.3.html
http://libguestfs.org/guestfs-security.1.html
https://rwmj.wordpress.com/2012/07/23/new-in-libguestfs-use-libvirt-to-launch-the-appliance/

guestmount
http://libguestfs.org/guestmount.1.html

Debian Packets
Deb-packets for libguestfs

qemu-img
managing-disk-images-with-qemu-img
https://en.wikibooks.org/wiki/QEMU/Images
sles-12-book_virt-data-cha-qemu-guest-inst-qemu-img.html
https://jmutai.com/2017/03/06/qemu-img-cheatsheet-for-working-with-qemu-img/

Allgemeines
stackoverflow.com questions 22327728 mounting-vmdk-disk-image

Mounten eines vmdk-Laufwerks im Linux Host – III – qemu-nbd, loop-devices, kpartx

In dieser Artikelserie beschäftigen wir uns damit, wie man von einer Linux-Umgebung aus direkt auf Partitionen von vmdk-Disk-Images zugreifen kann. In den letzten beiden Artikeln

Mounten eines vmdk Laufwerks im Linux Host – I – vmware-mount
Mounten eines vmdk-Laufwerks im Linux Host – II – Einschub, Spezifikation, Begriffe

hatten wir zunächst das Kommando “vmware-mount” betrachtet. “vmware-mount” kann Partitionen in Snapshots eines “sparse and growing vmdk-Images” direkt auf Zielverzeichnisse eines Linux-Baums mounten. Wir hatten dabei gesehen, dass zwischenzeitlich ein sog. “flat”-File angelegt wird. Die Rechtesetzung beim Mounten hatte uns noch nicht besonders gefallen. Da vmdk-Format unterschiedliche und komplexe Varianten von bedarfsgerecht wachsenden Images und Snapshots erlaubt, hatten wir im zweiten Artikel ein paar Seitenblicke auf die Spezifikation geworfen, um die Vielzahl von vmdk-Dateien zu einem Disk-Image und die zugehörige Nomenklatur besser zu verstehen. Nun wollen wir ein erstes natives Linux-Tools betrachten.

Da “vmdk” mit Virtualisierung zu tun hat, ist es kein Wunder, dass die beste Unterstützung für dieses Format unter Linux aus dem QEMU-Bereich – und damit von Red Hat und aufgekauften Firmen – kommt. Eines der Tools, auf die dabei inzwischen Verlass ist, gibt es schon sehr lange (seit etwa 2010): qemu-nbd.

nbd steht dabei für Network Block Device; Ziel des nbd-Toolsets war es, virtuelle Speichermedien auch über Server – also über Netz – für qemu-basierte virtuelle Maschinen auf Client-Systemen (z.B. Linux-Workstations) bereitzustellen. Schön beschrieben sind die Grundlagen aus den Anfangszeiten etwa hier :
Qemu-Buch zu Network Block Devices
https://de.wikipedia.org/wiki/Network_Block_Device

nbd kann aber natürlich auch lokal – also auf der eigenen Linux-Workstation – zur Erstellung eines Block-Devices auf Basis eines vmdk-Disk-Images eingesetzt werden. Das Kernelmodul “nbd” und das zugehörige CLI-Kommando “qemu-nbd” erweisen sich dabei als fähig, auch Snapshots des neuesten vmdk-Formats in der Version 6 richtig zu verarbeiten. Für die weitere Verwertung unter Linux werden – bei richtiger Parametrierung – ein oder mehrere ein Block-Devices erzeugt, die wir z.T. direkt mounten können.

Sicherheit und das direkte Mounten von virtuellen Disks/Filesystemen auf Linux-Hosts

Vorab ein paar mahnende Worte: vmdk, qcow2, etc. sind für virtuelle Maschinen gedacht. Gerade bei virtualisierten Windows-Maschinen, aber auch sonst, sollte man vorsichtig sein, wenn man nicht genau weiß, in welchem Zustand sich die Filesysteme des Images befinden. Ein manipuliertes Filesystem und/oder mit Malware behafteter Inhalt kann nach einem Mounten auch auf einem Linux-Host erheblichen Schaden anrichten. Leute, die etwas anderes glauben, erliegen einer Illusion.

Ich plädiere deshalb dafür, Experimente oder auch forensische Aktivitäten mit Partitionen aus vmdk-Images immer in einem virtuellen KVM-Linux-Gastsystem eines KVM-Hostes auszuführen. Das Gastsystem kann man hinreichend gut vom eigentlichen Virtualisierungs-Host isolieren. Die Performance ist auf aktuellen und SSD-basierten Systemen hinreichend gut, um auch mit großen vmdk-Images bequem hantieren zu können.

Wenn ich nachfolgend vom “Host” spreche, meine ich also immer das Linux-System, auf dem man mit dem vmdk-Image “forensisch” operiert – und nicht die virtuelle
Maschine, die das Image normalerweise direkt nutzt und auch nicht den Virtualisierungshost. Ich meine vielmehr einen speziellen KVM-Linux-Gast, von dem aus man auf das Image zugreift. Die zu untersuchenden vmdk-Dateien kann man auf einem solchen Gast z.B. über SSHFS bereitstellen – oder sie bei hinreichendem Platz einfach per scp in das Gast-Filesystem hineinkopieren.

Man lese zu den Gefahren etwa:
A reminder why you should never mount guest disk images on the host OS von D.P. Berrange

Zudem gilt immer:
Mehrfache Mounts mit ggf. konkurrierenden schreibenden Zugriffen sind unbedingt zu vermeiden! Operiert man mit dem Image entgegen meinem Ratschlag direkt auf dem Virtualisierungshost, so muss das virtualisierte Gastsystem, das das Image normalerweise nutzt, abgeschaltet sein. Oder: Man mountet zur Sicherheit in einem “read only”-Modus.

Notwendige Pakete für qemu-nbd

Wer sich unter Linux – in meinem Fall Opensuse Leap – mit qemu und KVM auseinandersetzt, hat die notwendigen Pakete mit ziemlicher Sicherheit bereits installiert. Erforderlich ist das Paket “qemu-tools” (unter Debian-Derivaten “qemu-utils”). Abhängigkeiten werden durch YaST (oder apt-get) aufgelöst. Unter Opensuse Leap ist das Paket bereits im Standard-Update-Repository enthalten; alternativ kann man auf das Virtualization Repository zurückgreifen.

Unterstützte vmdk-Formate

qemu-nbd greift intern auf die Fähigkeiten von “qemu-img” zurück. Die Seite en.wikibooks.org-wiki-QEMU-Images informiert darüber, welche vmdk-Formate (neben vielen anderen Formaten) qemu-img in einer aktuellen Version (≥ 2.9) unterstützt:

vmdk:
VMware 3 & 4, or 6 image format, for exchanging images with that product

Das Interessante ist, dass qemu-nbd die vorgegebenen vmdk-Dateien zu Snapshots und zur vmdk-Base-Disk nach außen – also in Richtung Linux-User – zu einem Block-Device zusammenführt. qemu-nbd legt also einen Block-Layer über die komplexe vmdk-Adressierungsstruktur. Die Hauptarbeit leistet dabei ein Kernelmodul.

Dreisatz zur Anwendung von qemu-nbd

Drei Schritte sind notwendig, um zu dem gewünschten Block-Devices und darin enthaltenen Filesysteme zu mounten.

Schritt 1 – Kernel-Modul laden:
Zunächst muss das “nbd”-Kernel-Modul geladen werden. Die Seite “kernel.org-Documentation-zu-nb erläutert die möglichen Parameter. Dieselbe Info liefert natürlich auch “modinfo”:

mytux:~ # modinfo nbd
filename:       /lib/modules/4.4.120-45-default/kernel/drivers/block/nbd.ko
license:        GPL
description:    Network Block Device
srcversion:     6F062B770FED9DC58072736
depends:        
retpoline:      Y
intree:         Y
vermagic:       4.4.120-45-default SMP mod_unload modversions 
signer:         openSUSE Secure Boot Signkey
sig_key:        03:32:FA:9C:BF:0D:88:BF:21:92:4B:0D:E8:2A:09:A5:4D:5D:EF:C8
sig_hashalgo:   sha256
parm:           nbds_max:number of network block devices to initialize (default: 16) (int)
parm:           max_part:number of partitions per device (default: 0) (int)

In meinem Testfall erwarte ich maximal 4 (NTFS/FAT-) Partitionen pro vmdk-Device, also:

mytux:/etc # modprobe nbd max-part=4
mytux:/etc # 

Schritt 2 – nbd-Device wählen und mit dem Disk-Image verknüpfen:
Defaultmäßig hält Linux 15 potentielle nbd-Devices unter dem Verzeichnis “/dev” vor. Nun muss ein solches “nbd”-Block-Device natürlich noch mit einem Disk-Image
verbunden werden. Wurde das Device “/dev/nbdx” – alos z.B. “/dev/nbd0” – noch nicht anderweitig benutzt, können wir es mit einem Disk-Image mittels der “-c” (= –connect) Option des Kommandos “<strong>qemu-nbd</strong>” zusammenführen.

Vorher müssen wir ein geeignetes Image wählen. Leser meines letzten Artikels wissen, dass auf meinem (selbst virtualisierten) Linux-System ein Testverzeichnis mit Dateien eines Win7-Gastes einer VMware-Umgebung existiert. Das Verzeichnis beinhaltet u.a. den zweiten Snapshot eines growable, sparse vmdk-Disk-Images zu einer Disk “Win7_x64_ssdx”. Um es noch komplizierter zu machen, befinden sich die ursprüngliche Deskriptor-Datei und die zugehörigen Extent-Dateien (inkl. der ursprünglichen Basis-Datei) in einem anderen Verzeichnis “/vmw/Win7”.

Das Verzeichnis “/vmw/Win7Test/” beinhaltet dagegen die Delta-Dateien (Deskriptor und Extents):

mytux:/vmwssd_w7prod/Win7_x64 # la | grep ssdx
-rw------- 1 myself  users    1507328 Mar 28 20:26 Win7_x64_ssdx-000001-s001.vmdk
-rw------- 1 myself  users      65536 Mar 28 19:54 Win7_x64_ssdx-000001-s002.vmdk
-rw------- 1 myself  users        370 Mar 28 20:24 Win7_x64_ssdx-000001.vmdk
-rw------- 1 myself  users     851968 Mar 29 10:38 Win7_x64_ssdx-000002-s001.vmdk
-rw------- 1 myself  users      65536 Mar 28 20:26 Win7_x64_ssdx-000002-s002.vmdk
-rw------- 1 myself  users      10240 Mar 29 10:37 Win7_x64_ssdx-000002.vmdk

Die Verlinkung zu den Ursprungsdateien unter “/vmw/Win7”

mytux:/vmwssd_w7prod/Win7_x64 # la /vmw/Win7/ | grep ssdx
-rw-------  1 myself  users 2344157184 Mar 28 19:53 Win7_x64_ssdx-s001.vmdk
-rw-------  1 myself  users     131072 Mar 27 19:37 Win7_x64_ssdx-s002.vmdk
-rw-------  1 myself  users        511 Mar 28 19:51 Win7_x64_ssdx.vmdk

ist, wie wir aus dem vorhergehenden Artikel wissen, natürlich über Verweise in den Deskriptor-Dateien Win7_x64_ssdx-000002.vmdk und Win7_x64_ssdx-000001.vmdk der Snapshots festgelegt.

Kommt qemu-nbd mit dieser komplexen Struktur klar? Ja – und wir müssen dabei nur die richtige Deskriptor-Datei angeben …

mytux:/vmw/Win7Test # qemu-nbd -c /dev/nbd0 Win7_x64_ssdx-000002.vmdk 
mytux:/vmw/Win7Test # la /dev | grep nbd0
brw-rw----   1 root disk       43,   0 Mar 30 14:51 nbd0
brw-rw----   1 root disk       43,   1 Mar 30 14:51 nbd0p1
brw-rw----   1 root disk       43,   2 Mar 30 14:51 nbd0p2
mytux:/vmw/Win7Test # fdisk -l /dev/nbd0
Disk /dev/nbd0: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0efb9e3e

Device      Boot   Start     End Sectors  Size Id Type
/dev/nbd0p1         2048 5312511 5310464  2.5G  7 HPFS/NTFS/exFAT
/dev/nbd0p2      5312512 8384511 3072000  1.5G  7 HPFS/NTFS/exFAT
mytux:/vmw/Win7Test # # 

Das, was hier so selbstverständlich aussieht, ist angesichts der Komplexität des vmdk-Formats eigentlich ein kleines Wunder. Man beachte, dass hier keine irgendwie geartete Kopie der vmdk-Disk in einem neuen Format erzeugt wurde. Vielmehr arbeiten wir auf den originalen Daten – deren Adressierung über eine Block-Layer-Schicht vermittelt wird. Dafür setzt qemu-nbd meines Wissens auch nicht FUSE ein (unix.stackexchange.com-questions-192875/qemu-nbd-vs-vdfuse-for-mounting-vdi-images)

Schritt 3 – Mounten:
So, wie wir qemu-nbd hier verwendet haben, ist es sehr zuvorkommend zu uns und weist neben dem Block-Device “/dev/nbd0” für die gesamte Disk gleich auch noch weitere Block-Devices für die intern erkannten Partitionen des Disk-Images aus. Letztere können wir direkt mounten:

nmytux:/vmw/Win7Test # mount /dev/nbd0p2 /mnt2
mytux:/vmw/Win7Test # la /mnt2
total 196128
drwxrwxrwx  1 root root         0 Mar 28 09:52 $RECYCLE.BIN
drwxrwxrwx  1 root root      4096 Mar 28 20:25 .
drwxr-xr-x 39 root root      4096 Mar 28 17:02 ..
drwxrwxrwx  1 root root      4096 Mar 28 09:53 Cosmological_Voids
drwxrwxrwx  1 root root         0 Mar 28 20:26 Muflons
drwxrwxrwx  1 root root         0 Mar 28 09:51 System Volume Information
-rwxrwxrwx  2 root root 200822784 Nov  4  2013 mysql-installer-community-5.6.14.0.msi
drwxrwxrwx  1 root root         0 Mar 29 10:37 ufos

Zugriffs-Rechte und deren Abänderung

Ähnlich wie bei “vmware-mount”, das wir im ersten Artikel dieser Serie behandelt hatten, bekommen wir je nach Zweck der vmdk-Untersuchung ggf. ein Problem mit Rechten – siehe die durchgehenden 777-Rechte-Kämme nach dem Mounten. Im Fall von qemu-nbd können wir das aber rechtzeitig im Zuge des Mountens korrigieren.

Dabei ist – je nach Untersuchungszweck – die Frage zu stellen: Wer soll welche Art von Zugriff erhalten und wie privilegiert soll derjenige sein? Ich zeige mal 2 Varianten. (Für das genauere Verständnis sollte man sich mit Mount-Optionen und umasks bzw. fmasks und dmasks befassen.)

Variante 1: Nur Root soll rein lesenden Zugang erhalten:

mytux:/vmw/Win7Test # mount -o uid=root,gid=root,umask=0277 /dev/nbd0p2 /mnt2
mytux:/vmw/Win7Test # la /mnt2
total 196128                                                                                                                        
dr-x------  1 root root         0 Mar 28 09:52 $RECYCLE.BIN/                                                                        
dr-x------  1 root root      4096 Mar 28 20:25 ./                                                                                   
drwxr-xr-x 39 root root      4096 Mar 28 17:02 ../
dr-x------  1 root root      4096 Mar 28 09:53 Cosmological_Voids/
dr-x------  1 root root         0 Mar 28 20:26 Muflons/
dr-x------  1 root root         0 Mar 28 09:51 System Volume Information/
-r-x------  2 root root 200822784 Nov  4  2013 mysql-installer-community-5.6.14.0.msi*
dr-x------  1 root root         0 Mar 29 10:37 ufos/

Variante 2: Nur der User “myself” soll lesenden und schreibenden Zugang zu Dateien und Directories des gemounteten NTFS-Systems erhalten:

mytux:/vmw/Win7Test # mount -o uid=rmx,gid=users,fmask=0177,dmask=0077 /dev/nbd0p2 /mnt2
mytux:/vmw/Win7Test # la /mnt2
total 196128
drwx------  1 myself  users         0 Mar 28 09:52 $RECYCLE.BIN
drwx------  1 myself  users      4096 Mar 28 20:25 .
drwxr-xr-x 39 root root       4096 Mar 28 17:02 ..
drwx------  1 myself  users      4096 Mar 28 09:53 Cosmological_Voids
drwx------  1 myself  users         0 Mar 28 20:26 Muflons
drwx------  1 myself  users         0 Mar 28 09:51 System Volume Information
-rw-------  2 myself  users 200822784 Nov  4  2013 mysql-installer-community-5.6.14.0.msi
drwx------  1 myself  users         0 Mar 29 10:37 ufos
mytux:/vmw/Win7Test # 

Die Linux-Rechte sagen allerdings wenig darüber aus, wem ggf. neu angelegte Dateien mit welchen Rechten dann später welchem User auf einem virtuellen Windows gehören würden. Siehe zu dieser Thematik den entsprechenden Abschnitt und zugehörige Links im ersten Artikel der Serie.

Unmounten und Entfernen der Beziehung eines nbd-Devices zum Disk-Image

Nachdem man die Untersuchung einer Partition des vmdk-Disk-Images unter Linux abgeschlossen hat, muss man alles wieder rückgängig machen. Das geht wie folgt:

mytux:/vmw/Win7Test # umount /mnt2
mytux:/vmw/Win7Test # qemu-nbd -d /dev/nbd0 
/dev/nbd0 disconnected
mytux:/vmw/Win7Test # rmmod nbd
mytux:/vmw/Win7Test # 

Den umount-Befehl muss
man natürlich für alle ggf. gemounteten Partitionen absetzen.

Nutzung von Loop-Devices?

nbd war deshalb sehr hilfsbereit, weil wir beim Laden des Kernelmoduls vorgegeben hatten, wieviele Partitionen maximal verwaltet werden sollen. Frage: Können wir die Partitionen auch anders bekommen, wenn wir etwa den Parameter des Kernelmoduls weglassen? Antwort: Ja, das geht.

Ich möchte zwei Varianten vorstellen, die sich nicht nur auf nbd-Devices, sondern in gleicher Weise auch auf raw- oder flat-Files, die man etwa als Output von “vmware-mount -f” erhalten würde, anwenden lassen.

Die erste Methode nutzt Loop-Devices. Loop- oder Loopback-Devices kennt der Linux-Anwender normalerweise im Zusammenhang mit mit der Nutzung von Filesystemen, die von Raw-Dateien beherbergt werden. Man vergisst dabei oft, dass sich Loop-Devices auch Block-Devices überstülpen lassen; die man-Page zu “losetup” sagt dazu:

DESCRIPTION
losetup is used to associate loop devices with regular files or block devices, to detach loop devices, and to query the status of a loop device.

Letztlich ist unter Linux/Unix halt alles ein File :-). Also:

mytux:/vmw/Win7Test # modprobe nbd
mytux:/vmw/Win7Test # qemu-nbd -c /dev/nbd0 Win7_x64_ssdx-000002.vmdk 
mytux:/vmw/Win7Test # la /dev | grep nbd0
brw-rw----   1 root disk       43,   0 Mar 31 15:19 nbd0

mytux:/vmw/Win7Test # fdisk -l /dev/nbd0
Disk /dev/nbd0: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0efb9e3e

Device      Boot   Start     End Sectors  Size Id Type
/dev/nbd0p1         2048 5312511 5310464  2.5G  7 HPFS/NTFS/exFAT
/dev/nbd0p2      5312512 8384511 3072000  1.5G  7 HPFS/NTFS/exFAT

Nun müssen wir noch die Offsets der Partitionen in Bytes aus den Start und End-Sektoren berechnen:

Offset Partition 1: 2048 * 512 = 1048576
Offset Partition 2: 5312512 * 512 = 2720006144

Diese Offset-Positionen sind dann über die Option “-o” im losetup-Kommando anzugeben:

mytux:/vmw/Win7Test # losetup -o 1048576 /dev/loop1 /dev/nbd0
mytux:/vmw/Win7Test # losetup -o 2720006144 /dev/loop2 /dev/nbd0
mytux:/vmw/Win7Test # mount /dev/loop1 /mnt2
mytux:/vmw/Win7Test # mount /dev/loop2 /mnt3
mytux:/vmw/Win7Test # la /mnt2
total 8
drwxrwxrwx  1 root root    0 Mar 27 19:35 $RECYCLE.BIN
drwxrwxrwx  1 root root 4096 Mar 27 19:35 .
drwxr-xr-x 39 root root 4096 Mar 28 17:02 ..
drwxrwxrwx  1 root root    0 Mar 27 19:34 System Volume Information

mytux:/vmw/Win7Test # touch /mnt2/hallo.txt
mytux:/vmw/Win7Test # la /mnt2
total 8
drwxrwxrwx  1 root root    0 Mar 27 19:35 $RECYCLE.BIN
drwxrwxrwx  1 root root 4096 Mar 31 15:24 .
drwxr-xr-x 39 root root 4096 Mar 28 17:02 ..
drwxrwxrwx  1 root root    0 Mar 27 19:34 System Volume Information
-rwxrwxrwx  1 root root    0 Mar 31 15:24 hallo.txt

mytux:/vmw/Win7Test # la /mnt3
total 196128
drwxrwxrwx  1 root root         0 Mar 28 09:52 $RECYCLE.BIN
drwxrwxrwx  1 root root      4096 Mar 28 20:25 .
drwxr-xr-x 39 root root      4096 Mar 28 17:02 ..
drwxrwxrwx  1 root root      4096 Mar 28 09:53 Cosmological_Voids
drwxrwxrwx  1 root root         0 Mar 28 20:26 Muflons
drwxrwxrwx  1 root root         0 Mar 28 09:51 System Volume Information
-rwxrwxrwx  2 root root 200822784 Nov  4  2013 mysql-installer-community-5.6.14.0.msi
drwxrwxrwx  1 root root         0 Mar 31 14:02 ufos
mytux:/vmw/Win7Test # 
mytux:/vmw/Win7Test # cat /mnt3/ufos/ufo.txt
Ufos are not real
mytux:/vmw/Win7Test #

Zurückdrehen können wir den gesamten Prozess wie folgt:

mytux:/vmw/Win7Test # umount /mnt3
mytux:/vmw/Win7Test # umount /mnt2
mytux:/vmw/Win7Test # losetup -d /dev/loop2
mytux:/vmw/Win7Test # losetup -d /dev/loop1
mytux:/vmw/Win7Test # qemu-nbd -d /dev/nbd0 
/dev/nbd0 disconnected
mytux:/vmw/Win7Test # modprobe -r nbd
mytux:/vmw/Win7Test # 

Loop-Devices und “vmware-mount -f”
Das Ganze klappt natürlich auch mit “vmware-mount -f” und dem dadurch erzeugten “flat”-File (s. den ersten Artikel):

mytux:/vmw/Win7Test # vmware-mount -f Win7_x64_ssdx-000002.vmdk /mnt/vmdk
mytux:/vmw/Win7Test # la /mnt/vmdk
total 4194304
-rw------- 1 myself users 4294967296 Mar 31 15:25 flat
mytux:/vmw/Win7Test # losetup -o 2720006144 /dev/loop2 /mnt/vmdk/flat 
mytux:/vmw/Win7Test # mount /dev/loop2 /mnt3
mytux:/vmw/Win7Test # cat /mnt3/ufos/ufo.txt 
Ufos are not real
mytux:/vmw/Win7Test # umount /mnt3
mytux:/vmw/Win7Test # losetup -d /dev/loop2
mytux:/vmw/Win7Test # vmware-mount -d /mnt/vmdk
mytux:/vmw/Win7Test #

Über diesen Weg können wir übrigens auch das Problem mit den Zugriffsrechten lösen, dass wir im ersten Artikel für “vmware_mount” angesprochen hatten – wir legen die Rechte analog zum oben besprochenen Vorgehen im Zuge des mount-Befehls fest.

kpartx?

Erfahrene Linux-User wissen, dass kpartx ein nettes Tool ist, das aus Block-Devices oder Raw-Files evtl. enthaltene Partitionstabellen ermittelt und über “/dev/mapper” entsprechende Devices bereitstellt. Das funktioniert natürlich auch auf Basis von “/dev/nbdX”-Devices:

mytux:/vmw/Win7Test # modprobe nbd
mytux:/vmw/Win7Test # qemu-nbd -c /dev/nbd0 Win7_x64_ssdx-000002.vmdk 
mytux:/vmw/Win7Test # kpartx -av /dev/nbd0 
add map nbd0p1 (254:12): 0 5310464 linear 43:0 2048
add map nbd0p2 (254:13): 0 3072000 linear 43:0 5312512    
mytux:/vmw/Win7Test # la /dev/mapper | grep nbd0
lrwxrwxrwx  1 root root       8 Mar 31 15:58 nbd0p1 -> ../dm-12
lrwxrwxrwx  1 root root       8 Mar 31 15:53 nbd0p2 -> ../dm-13
mytux:/vmw/Win7Test # mount /dev/dm-13 /mnt3
mytux:/vmw/Win7Test # cat /mnt3/ufos/ufo.txt
Ufos are not real
mytux:/vmw/Win7Test # umount /mnt3
mytux:/vmw/Win7Test # kpartx -d /dev/nbd0
mytux:/vmw/Win7Test # la /dev/mapper | grep nbd0
mytux:/vmw/Win7Test # modprobe -r nbd
mytux:/vmw/Win7Test # 

Analog für ein flat-File von vmware-mount:

mytux:/vmw/Win7Test # vmware-mount -f Win7_x64_ssdx-000002.vmdk /mnt/vmdk
mytux:/vmw/Win7Test # kpartx -av /mnt/vmdk/flat 
add map loop0p1 (254:12): 0 5310464 linear 7:0 2048
add map loop0p2 (254:13): 0 3072000 linear 7:0 5312512
mytux:/vmw/Win7Test # mount /dev/dm-13 /mnt3
mytux:/vmw/Win7Test # cat /mnt3/ufos/ufo.txt
Ufos are not real
mytux:/vmw/Win7Test # umount /mnt3
mytux:/vmw/Win7Test # kpartx -d /mnt/vmdk/flat
loop deleted : /dev/loop0
mytux:/vmw/Win7Test # vmware-mount -d /mnt/vmdk
mytux:/vmw/Win7Test # 

Alles gut !

Read-Only-Option?

In allen oben dargestellten Beispielen haben wir bislang durchgehend rw-Mounts durchgeführt. Da ist bei vielen Analysen nicht erwünscht. Grundsätzlich ist im Umgang mit Partitionen regelmäßig Vorsicht angebracht, um nichts zu zerstören. Write-´Zugriffe sollte man immer zuerst auf Kopien testen.

Daher stellt sich die Frage nach einer “ro”-Option von “qemu-nbd”. Die gibt es, sie lautet “-r”. Deren Setzung schlägt auf alle weiteren Maßnahmen durch:

mytux:/vmw/Win7Test # modprobe nbd max-part=4
mytux:/vmw/Win7Test # qemu-nbd -r -c /dev/nbd0 Win7_x64_ssdx-000002.vmdk 
mytux:/vmw/Win7Test # mount /dev/nbd0p2 /mnt3
fuse: mount failed: Permission denied
mytux:/vmw/Win7Test # mount -o ro /dev/nbd0p2 /mnt3
mytux:/vmw/Win7Test # 

Gibt es Größenlimit für die virtuelle Disk?

Ehrlich gesagt: keine Ahnung. Wenn es ein aktuelles Limit gibt, würde ich aufgrund älterer Infos im Zusammenhang mit nbd auf 1TB tippen. Wenn jemand was Genaueres weiß, kann er mir ja eine Mail schreiben. Siehe auch:

vsphere-50 und vddk
vddk51_programming.pdf

Fazit und Ausblick

Das nbd-Kernelmodul und das Kommando qemu-nbd eröffnen relativ einfache Zugänge zu komplexen vmdk-Image-Dateien. Dabei wird auch die aktuelle Version 6 des vmdk-Formats beherrscht. Wir haben zudem die Möglichkeit, das Mounten der bereitgestellten nbd-Block-Devices bzgl. der Rechte individuell zu gestalten.

Im nächsten Artikel

Mounten eines vmdk-Laufwerks im Linux Host – IV – guestmount, virt-filesystems, qemu-img

gehe ich kurz auf “qemu-img” ein und betrachte dann das Kommando “guestmount” aus der neueren und Fuse-basierten Toolkiste von “libguestfs”.

Links

losetup – Abkürzung für bestimmte mknod-Operationen zur Nutzung von Loop-Devices
unix.stackexchange.com/questions/98742/how-to-add-more-dev-loop-devices-on-fedora-19

qemu-nbd
https://wiki.ubuntuusers.de/QEMU/
https://opsech.io/posts/2017/Jun/07/how-to-mount-vm-disk-images-on-fedora.html
http://blog.vmsplice.net/2011/02/how-to-access-virtual-machine-image.html
https://sweetcode.io/introduction-to-linux-network-block-devices/

Mounten eines vmdk-Laufwerks im Linux Host – II – Einschub, Spezifikation, Begriffe

Diese Artikelserie befasst sich mit Linux-Kommandos, die den Zugriff auf Inhalte von Image-Files für virtuelle vmdk-Disks erlauben. Den Lesern meines letzten Artikels zum Kommando “vmware-mount”

Mounten eines vmdk Laufwerks im Linux Host – I – vmware-mount

möchte ich in diesem Artikel ein paar Links zur vmdk-Spezifikation nachreichen. Dabei wird einerseits nochmals die Komplexität des vmdk-Formats deutlich, mit denen Linux-Tools sich auseinandersetzen müssen. Andererseits möchte ich im Vorgriff auf weitere Artikel ein paar Begrifflichkeiten glattziehen und die Nomenklatur von “sprechenden” Zusätzen in vmdk-Datei-Namen erläutern. Dieser Einschub war nicht geplant; er erschien mir aber u.a. sinnvoll, um zu verdeutlichen, warum bestimmte Linux-Tools, mit denen wir uns noch beschäftigen werden, ernsthafte Problem mit bestimmten vmdk-Varianten haben.

vmdk-Spezifikationen

Das vmdk-Format ist ziemlich komplex und hat sich im Lauf der Zeit auch mehrfach geändert. Das Format nimmt auf unterschiedliche Bedürfnisse Rücksicht, die im Zusammenhang mit Virtualisierung und zugehörigen Image-Files für virtuelle Disks auf Virtualisierungshosts auftreten. Zu nennen sind diesbzgl.: Platzbedarf versus Performance; Zustandssicherung von virtuellen Maschinen durch Snapshots und zugehörige Delta-Informationen; unterschiedliche Lagerstätten von vmdk_Files im Verzeichnisbaum.

Den aktuellen Stand spiegeln Informationen unter folgenden Links wieder:

vmdk-spec-in-ascii-doc-format
VMware PDF zu Virtual Disk Format 5.0
https://www.vmware.com/app/vmdk/?src=vmdk
ttgtmedia-PDF zum Umgang mit vmdk

Einige weitere interessante Infos liefert auch die API-Beschreibung für Entwickler:
https://vdc-download.vmware.com/vmwb-repository/dcr-public/ae1a858c-2f59-4a75-b333-f2ddfa631fbd/4ae542fa-c7ec-4713-a3a0-6fef938b03d1/vddk60_programming.pdf

Ich kann euch das Lesen nicht abnehmen, nachfolgend gehe ich aber auf Punkte ein, die die Vielzahl und die unterschiedlichen Bezeichnungen von vmdk-Dateien, deren Anzahl sich unter bestimmten Voraussetzungen im Lauf der Zeit beträchtlich erhöhen kann, erklären.

Vielfalt – schon bei einer einzelnen virtuellen Maschine

Im Hauptverzeichnis zu einer meiner virtuellen Testmaschinen finden sich etwa folgende vmdk-Dateien:

mytux:/vmw/WinTest # ls | grep vmdk
Win7_x64-cl1-000001-s001.vmdk
Win7_x64-cl1-000001-s002.vmdk
...
Win7_x64-cl1-000001-s016.vmdk
Win7_x64-cl1-000001-s017.vmdk
Win7_x64-cl1-000001.vmdk
Win7_x64-cl1-000002-s001.vmdk
Win7_x64-cl1-000002-s002.vmdk
...
Win7_x64-cl1-000002-s016.vmdk
Win7_x64-cl1-000002-s017.vmdk
Win7_x64-cl1-000002.vmdk
Win7_x64-cl1-000003-s001.vmdk
Win7_x64-cl1-000003-s002.vmdk
...
Win7_x64-cl1-000003-s016.vmdk
Win7_x64-cl1-000003-s017.vmdk
Win7_x64-cl1-000003.vmdk
Win7_x64-cl1-000004-s001.vmdk
Win7_x64-cl1-000004-s002.vmdk
...
Win7_x64-cl1-000004-s016.vmdk
Win7_x64-cl1-000004-s017.vmdk
Win7_x64-cl1-000004.vmdk
Win7_x64-cl1-s001.vmdk
Win7_x64-cl1-s002.vmdk
...
Win7_x64-cl1-s016.vmdk
Win7_x64-cl1-s017.vmdk
Win7_x64-cl1-s018.vmdk
Win7_x64-cl1.vmdk
Win7_x64_ssd_ex-000001.
vmdk
Win7_x64_ssd_ex-000002.vmdk
Win7_x64_ssd_ex-000003.vmdk
Win7_x64_ssdx-000001-s001.vmdk
Win7_x64_ssdx-000001-s002.vmdk
Win7_x64_ssdx-000001.vmdk
Win7_x64_ssdx-000002-s001.vmdk
Win7_x64_ssdx-000002-s002.vmdk
Win7_x64_ssdx-000002.vmdk

 
Das ist schon eine erstaunliche Vielfalt; dabei habe ich in der Liste bereits viele Dateien (u.a. sog. Extents mit Namenszusätzen “s003” bis “s015”) ausgeblendet. Um die Lage noch zu verkomplizieren, liegen einige Basisdateien zu Testzwecken auch noch in in einem anderen Verzeichnis (nämlich /vmw/Win7).

Hinweis: VMware legt Snapshots defaultmäßig immer im Verzeichnis der virtuellen Maschine an; die Ursprungsdateien für Disk-Images können sich jedoch an anderer Stelle im Verzeichnisbaum befinden.

Hinweise und ein paar Zitate aus der Spezifikation

Die ersten drei der oben genannten Dokumente legen u.a. fest, dass die reinen vmdk-Dateien, also diejenigen ohne “-snnn”-Anteil im Namen, sogenannte “Deskriptor”-Dateien sind. Meine Leser kennen den Begriff schon vom vorhergehenden Artikel. Auch das nächste Zitat belegt (bis auf den letzten Satz) einige Punkte, die ich bereits früher angedeutet hatte:

“VMware virtual disks can be described at a high level by looking at two key characteristics:
     * The virtual disk may use backing storage contained in a single file, or it may use storage that consists of a collection of smaller files.
    * All of the disk space needed for a virtual disk’s files may be allocated at the time the virtual disk is created, or the virtual disk may start small and grow as needed to accommodate new data.
A particular virtual disk may have any combination of these two characteristics.
One characteristic of recent ‐ generation VMware virtual disks is that a text descriptor describes the layout of the data in the virtual disk. This descriptor may be saved as a separate file or may be embedded in a file that is part of a virtual disk.”

Ich nenne in dieser Artikelserie ein Disk-Image, das sich über mehrere Dateien erstreckt, auch einen “Container“. In der Reihe der Dateien, die gemäß vmdk-Spezifikation zu einem Container gehören, ist zu unterscheiden zwischen

  • der Deskriptor-Datei
  • den durchnummerierten “Extent”-Dateien.

Das erste Extent-File bezeichne ich auch als “Base-File” (nicht zu verwechseln mit der “Base-Disk”; s.u.)

Das vierte der oben per Link angegebenen Dokumente weist dabei auf Folgendes hin (eine noch präzisere Info zu den verschiedenen Erscheinungsformen von vmdk-Disk-Images liefert die API-Doku):

“The VMDK file can have four different forms. Type 0 (monolithic sparse disk), Type 1 (growable; split into 2GB files), Type 2 (single pre-allocated; monolithic sparse disk), and Type 3 (pre-allocated; split into 2GB files). Types 1, 2, and 3 use a disk descriptor file, while type 0 does not.
To make changes to the VMDK file, you need to be able to open and view the disk descriptor; otherwise, with the type 0 single disk, you would need to edit a very large binary file with a hex editor – an unwise choice. A better option, if you have the VMDK file on a VMFS file system, is to use vmkfstools to easily export the file in a Type 3 format.”

Hinweis:

Obwohl hier 2GB als Standardgröße der Extension-Files einer “growable, sparse Disk” angegeben werden, werden u.a. von der VMware-Workstation unter Linux inzwischen standardmäßig 4GB große Dateien für Extent-Dateien erzeugt.

Die Komplexität wird durch Snapshots noch weiter gesteigert: Die die
vmdk-Spezifikation erklärt Snapshots über Dateien (“Links”) in einer Link-Kette, bei der Delta-Files auf logisch vorhergehende Delta-Files und zuletzt auf Files der ursprüngliche “Base”-Disk verweisen – und zwar nach folgendem Muster:

Delta-Dateien zu Snapshot N   =>   Delta-Dateien zu Snapshot N-1   =>   …   =>   Delta-Dateien zu Snapshot 1   =>   Dateien der Base-Disk

Eine Base-Disk kann als “growable Disk” angelegt worden sein. Sie und auch zugehörige Snapshots weisen dann ein Base-File und weitere Extents auf – in den Snapshots sind die jeweiligen Dateien dann aber nur mit Delta-Informationen zum jeweiligen Extent gefüllt.

Wie schlägt sich die Komplexität in den Namens-Zusätzen der vmdk-Files nieder?

Eine interessante Frage, mit der man sich ggf. auseinandersetzen muss, ist, wie sich die mögliche Struktur in der Namensgebung von vmdk-Dateien widerspiegelt. Dazu gibt es – zumindest bzgl. der VMware Workstation – vier Regeln:

  • Eine Datei, die durch Clonen einer Maschine mit VMware-Tools entstanden ist, erhält einen Zusatz “-clN”. N steht dabei für die Nummer des Clones.
  • Ein Snapshot, der mit VMware-Tools angelegt wurde, erhält einen Zusatz in Form einer 6-stelligen Nummer, z.B. “-000024”. Im Beispiel wäre das der 24-te Snapshot.
  • Eine Deskriptor-Datei enthält außer dem Clone- und dem Snapshot-Zusatz keine weiteren Zusätze im Namen.
  • Eine neue Extend-Datei erhält in aufsteigender Nummerierung einen Zusatz “-sNNN”; dabei steht “NNN” für eine dreistellige Zahl – z.B. “-s017”. Das Beispiel würde das File für den 17-ten Extent markieren. Ein erster Extent (“-s001”) wird bei einer growable sparse Disk immer angelegt; das zugehörige File ist das von mir als solches bezeichnete Base-File.

Dabei gilt nicht zwingend, dass die Snapshot-Nummer für alle Disk-Images einer virtuellen Maschine immer gleich sein muss. Eine Disk könnte der Maschine ja z.B. erst nach dem Snapshot 43 hinzugefügt worden sein. Pro Disk wird ab dem ersten zugehörigen Snapshot-Event hochnummeriert: Die Dateien zur neuen Disk erhalten dann beim zweiten nachfolgenden Snapshot “-000002” als Zusatz, während bei älteren Disks der Zähler schon auf “-000045” steht.

Blick auf eine Deskriptor-Datei

Nun könnten wir uns ja einfach mal eine Descriptor-Datei ansehen. Aber Vorsicht bei “monolithic sparse disks” (Typ 0)! Die Shell (cat-Kommando) und viele einfache Editoren sind keine Hex-Editoren! “Typ 0” ist aber gerade für unsere Test-Disk, die durch “/vmw/WinTest/Win7_x64_ssd_ex-000003.vmdk” beschrieben wird, gegeben. Problemfreier sollte sich die Deskriptor-Datei dagegen für eine andere zweite vmdk-Disk, die als Container mit 2 “sparse extends” (Typ 1) angeboten wird, auslesen lassen. Probieren wir das mal mit dem Deskriptor File “Win7_x64_ssdx-000002.vmdk” des für diese Disk vorliegenden zweiten Snapshots aus:

mytux:/vmw/Win7Test # cat Win7_x64_ssdx-000002.vmdk 
# Disk DescriptorFile
version=1
encoding="UTF-8"
CID=a3a5e6df
parentCID=d135caf6
createType="twoGbMaxExtentSparse"
parentFileNameHint="Win7_x64_ssdx-000001.vmdk"
# Extent description
RW 8323072 SPARSE "Win7_x64_ssdx-000002-s001.vmdk"
RW 65536 SPARSE "Win7_x64_ssdx-000002-s002.vmdk"

# The Disk Data Base 
#DDB

mytux:/vmw/Win7Test # cat Win7_x64_ssdx-000001.vmdk 
# Disk DescriptorFile
version=1
encoding="UTF-8"
CID=d135caf6
parentCID=b665cd6b
createType="twoGbMaxExtentSparse"
parentFileNameHint="/vmw/Win7/Win7_x64_ssdx.vmdk"
# Extent description
RW 8323072 SPARSE "Win7_x64_
ssdx-000001-s001.vmdk"
RW 65536 SPARSE "Win7_x64_ssdx-000001-s002.vmdk"

# The Disk Data Base 
#DDB

ddb.longContentID = "d10b249e54a5cd42df5ab314d135caf6"
mytux:/vmwssd_w7prod/Win7_x64 # 

Was lernen wir?

  • In der Deskriptor-Datei sind keine Informationen enthalten, die die Partitionsstruktur der Disk-Images offenbaren würden.
  • Die Extents sind als wachsende “sparse”-Dateien konfiguriert.
  • Die Verlinkung erfolgt über CIDs und Pfadangaben.
  • Die Base-Disk wurde im vorliegenden Fall in einem anderen Verzeichnis definiert als dem der virtuellen Maschine.

Interne Daten-Adressierung und Partitionsinformation

Die vmdk-Spezifikation beschreibt relativ detailliert, wie die die Block-Adressierung der wachsenden Daten systematisch über zugehörige Informationen

  • in Headern von Extent-Files,
  • in einem sog. Grain-Directory des Extents
  • und zugehörigen Grain-Tabellen mit Einträgen zu Offsets für konkret definierte “Grains” (Block of Sectors, GrainSize*SectorSize, z.B. 128 * 512 = 64KB)

realisiert und gesteuert wird. Ferner gilt, dass die Deskriptor-Information in Extent Files selbst enthalten sein kann.

Die Partitionsinformation liegt bei einer normalen Platte in der Partitionstabelle (MBR, GPT-Format). Diese befindet sich ziemlich am Anfang einer Platte. Daraus folgern wir, dass dem Erkennen des Basis-Files eines “sparse/growable”-Disk-Images und der Analyse dieses Files (neben der Deskriptor-Datei) große Bedeutung zukommt.

Runterbrechen auf ein Flat- oder Raw-File?

Der Einsatz von Loop-Devices unter Linux für den Zugriff auf Partitionen, die in Disk-Images verborgen werden, erfordert ein spezielles “flaches” Format einer zusammenhängenden Datei. Letztere wird manchmal als “raw”- oder “flat”-File bezeichnet.

Da vmdk-Disks wegen Snapshots und Extents vielfach in Einzeldateien gesplittet und letztere wiederum untereinander verlinkt sind, muss ein solches zusammenhängendes “raw”-File erstmal durch Analyse der Dateibeziehungen, der Adressierung von virtuellen Datenblöcken innerhalb einer Datei und durch Auswertung von Delta-Informationen erzeugt werden.

Das erledigen viele Tool-Entwickler, indem sie FUSE-Mechanismen nutzen.

Alternativ kann man (über FUSE) auch andere Schritte gehen – und das Filesystem direkt mit dem Host-Kernel oder dem zwischengeschobenen Kernel einer (verdeckten) virtuellen Maschine kommunizieren lassen (siehe hierzu etwa
http://libguestfs.org/guestfs-security.1.html. Generell ist übrigens zu sagen, dass das direkte Mounten eines Filesystems aus einer ggf. manipulierten virtuellen Maschine über Loop-Devices durchaus mit Gefahren verbunden sein kann.)

Da vmdk so komplex ist, wundert es nicht, dass etliche im Internet besprochene Linux-Tools wie affuse, vdfuse und z.T. auch vmdkmount in ihrem aktuellen Zustand an der korrekten Aufdröselung von Snapshots oder aber Extents scheitern. Zumindest nach meiner aktuellen Erfahrung.

Runterbrechen auf ein Block-Device?

Alternativ zu einem Flat-File kann ein Tool auch ein “künstliches” Block-Device für das Disk-Image bereitstellen. Dazu muss – ähnlich wie bei echten HW-Disk-Treibern – ein “künstliches” Device mit einem entsprechenden Block-Layer durch ein Kernel-Modul, das die korrekte Adressierung leistet, bereitgestellt und verwaltet werden.

Zusammenfassung / Ausblick

vmdk-Images sind komplex; sie

  • vdmk-Disk-Images erlauben Snapshots – d.h. die Verlinkung von Delta-Files.
  • Ein vdmk-Disk-Image kann als Container
    angelegt werden, der sich über viele Einzeldateien (Extends) erstreckt.
  • Das Disk-Image kann so angelegt werden, dass die Zahl der Extents (und zugehöriger Dateien) im Lauf der Zeit bedarfsgerecht wächst. Jeder Extent wächst dabei dynamisch auf sein Limit an.
  • Ein vdmk-Disk-Image kann alternativ als eine sukzessive wachsende Einzeldatei für ein Disk-Image angelegt werden.
  • Ein vdmk-Disk-Image erlaubt eine einmalige, vollständige Platz-Allokierung für die gesamte Disk.
  • Pro vdmk-Disk-Image sind mehrere Partitionen/Filesysteme erlaubt.

Davon treten ggf. mehrere Punkte in Kombination auf. Das stellt Linux-Tools u.a. vor das Problem, wie man interessierten Usern entweder

  • eine flat- oder raw-Datei zur Verfügung stellen will, die der User dann selbst – z.B. über Loop-Devices – weiterverarbeitet,
  • einen linux-fähigen Block-Layer über die vmdk-Adressierung legen,
  • oder mittels FUSE gleich einen anderen, ggf. direkteren Zugang zu den enthaltenen Partitionen eines vmdk-Disk-Images liefert.

Im nächsten Artikel

Mounten eines vmdk-Laufwerks im Linux Host – III – qemu-nbd, loop-devices, kpartx

bespreche ich zunächst ein Linux-Tool, das den zweiten der genannten Wege einschlägt und dabei auch Snapshots und Extents beherrschen – nämlich qemu-nbd

Mounten eines vmdk Laufwerks im Linux Host – I – vmware-mount

Manchmal muss man sich auf einem Linux-Virtualisierungs-Host direkt – d.h. ohne Umweg über virtualisierte Gastsysteme – mit dem Inhalt von “vmdk”-Dateien auseinandersetzen. Ich stelle in diesem und nachfolgenden Beiträgen ein paar einfache Möglichkeiten vor, die ich selbst immer mal zum Mounten von Filesystemen, die sich innerhalb von vmdk-Dateien befinden, in den Verzeichnisbaum meiner Linux-Workstations benutze. Als Beispiele müssen dabei NTFS-Testpartitionen einer vmdk-Disk herhalten, die einer virtuellen Maschine mit Win7 zugeordnet wurden.

Szenarien für den direkten Zugriff unter Linux?

“vmdk”-Dateien dienen unter Linux primär dazu, VMware-Gastsysteme – aber z.B. auch Virtualbox- und qemu-Gastsysteme – mit einem virtuellen “Festplatten”-Unterbau auszustatten. Ich spreche nachfolgend daher auch von “vmdk-Disks“. Ein allgemeiner Begriff, der das Prinzip von virtuellen Disks in Form von Dateien umschreibt, ist der eines Disk-Images.

Eine vmdk-Disk kann wie eine echte Platte auch Filesysteme (wie Ext4, NTFS oder BrtFS) aufnehmen. Unter KVM korrespondieren zu “vmdk” etwa “qcow2”-Dateien. Die Nutzung von Linux-Dateien als Container für Filesysteme bringt beim Virtualisieren einige Vorteile mit sich: u.a. kann man die virtuellen Platten relativ problemlos zwischen Hosts hin- und her bewegen. Natürlich lässt sich auch die Durchführung von Backups für “vmdk”-Dateien besonders einfach mit Linux-Bordmitteln durchführen.

Nun könnte man sagen, dass man auf die über “vmdk” bereitgestellten Filesysteme ja immer über die virtuelle VMware-Gast-Maschine selbst zugreifen kann. Das stimmt so nicht uneingeschränkt: Bisweilen muss man etwa die Pflege des/der auf der vmdk-Datei installierten Filesystems/e über Tools des Hosts betreiben. In anderen Fällen ist eine Bereinigung von eingefangenen Viren auf einem NTFS-Filesystem nötig, ohne dass das betroffene Gast-System gebootet werden soll. Ein anderes wichtiges Szenario ist die forensische Analyse von Inhalten der virtuellen Maschine – z.B. eines kompromittierten Windows-Gastsystems – durch Linux-Tools. Für letzteres reicht oftmals der lesende Zugriff. Weitere Anwendungsfälle sind logischerweise auch Pen-Tests (oder Hacker-Angriffe), bei denen der “Angreifer” von einem (teil-)eroberten Virtualisierungshost aus die Extraktion von Daten aus dort vorhandenen vmdk-Dateien virtueller Maschinen anstrebt.

Toolunterstützung unter Linux?

Die Spezifikation zu “vmdk” ist seit einiger Zeit offen; man erwartet daher, dass der Zugriff auf Inhalte von vmdk-Dateien (bzw. -“Laufwerken”) unter Linux gut unterstützt wird. Unterstützung bedeutet für mich dabei primär die Erfüllung zweier Anforderungen:

  • Der Inhalt von “vmdk”-Disks sollte sich für den berechtigten User nach ein paar Schritten so darstellen, als gebe es dort (ggf. mehrere) Partitionen mit je einem unter Linux handhabbaren Filesystem (wie etwa NTFS von MS).
  • Unter diesen Filesystemen muss man dann eines auswählen und – wie von echten Festplatten gewohnt – mounten können.

Für den Anwender ist der Einsatz entsprechender Tools unter Linux unterschiedlich komfortabel: Einige Tools führen alle notwendigen Schritte inkl. des Mountens für den User bequem in einem Rutsch durch; besonders nachvollziehbar ist das Vorgehen hinter den Kulissen des/der jeweiligen Kommandos dann aber nicht. Dies gilt im Besonderen für die Behandlung sog. vmdk-Container.

FUSE, Loop Devices – Komplexität durch Snapshots, “sparse vmdk-Container” mit mehreren “Extension Files” und mit mehreren internen Partitionen/Filesystemen

Es gibt vier Hindernisse, die Entwicklern von vmdk-Tools überwinden müssen:

  • Sparse-vmdk: Spezielle Schwierigkeiten bei der Analyse der in vmdk-Disks
    verborgenen Filesysteme bereitet u.a. die Tatsache, dass eine einzelne vmdk-“Disk” oftmals in Form eines Containers daherkommt, der sich über mehrere vmdk-Dateien (jedes davon z.B. mit einer Größe von 4GB) erstreckt.
    Man spricht hier von “growable split and sparse file vmdk“; die “virtuelle” Platte wächst auf dem Host durch immer neu angelegte 2GB oder 4GB große Extents erst im Lauf der Zeit auf die Gesamtgröße an. Auch jedes einzelne neue Extension File selbst wächst dabei bedarfsgerecht an.
    Es gibt dann eine “führende”, beschreibende vmdk-Datei – etwa mydisk.vmdk – und etliche weitere Extension-Dateien mit der Endung “-sNNN” – also z.B. “mydisk-sNNN.vmdk“; “NNN” steht dabei für eine dreistellige Nummer. Die führende Datei nennt man auch Deskriptor-Datei (s. hierzu den nächsten kommenden Artikel).
  • Mehrere Partitionen auf einer Disk: In beiden Fällen (sparse und flat) kommt hinzu, dass eine vmdk-Disk mehrere Partitionen beinhalten kann.
  • Loop-Devices und Offsets: Hat man die Partitionen in einer vmdk-Disk erstmal erkannt, muss man entsprechende Linux-“Devices” für den Zugriff als Blockdevice definieren. Dabei muss man sich natürlich auch um den sog. “Offset” einer spezifischen Partition relativ zum Anfang der beherbergenden Disk-Datei(en) kümmern.
  • Snapshots: Weiter verkompliziert wird die Handhabung für den Nutzer noch dadurch, dass man unter VMware Snapshots einer virtuellen Maschine anlegen kann. Solche Snapshots äußern sich in weiteren Zusätzen der vmdk-Dateien; z.B. mydisk-000001-s001.vmdk. Man muss also unter der Menge vorhandene vmdk-Disk-Dateien geeignete Snapshot-Dateien auswählen (z.B. mydisk-000001.vmdk). Dabei können die führende Snapshot-Datei und die ehemals führende Datei (die auch der Snapshot mitnutzt) u.U. in verschiedenen Verzeichnissen liegen (s.u.). Noch weitere Namens-Zusätze unterscheiden übrigens ggf. Clones virtueller Maschinen.

Ergänzende Hinweise (im nächsten Artikel liefere ich dazu auch Links):

Zu einer “growable split and sparse Disk” (Container) gibt es auch die Variante, dass zwar über mehrere Files hinweg gesplittet wird, aber der gesamte Plattenplatz von vornherein allokiert wird. Die erste Extent-Datei nennt man auch “Base-File” des vmdk-Disk-Images.
Das Gegenteil zu einer Sparse Disk, die über viele Extension Files verteilt ist, ist das sog. “monolithic file vmdk“; dabei wird von Anfang an nur genau eine vmdk-Datei für die angestrebte virtuellen Platte angelegt. Das bringt neben strukturellen Unterschieden u.a. geringfügige Performance-Vorteile. Aber auch hier gibt es wieder zwei Möglichkeiten: Die Datei kann von vornherein den gesamten Platz der virtuellen Disk allokieren, oder sie kann langsam wachsen. In letzterem Fall spricht man auch von einer “Monolithic Sparse Disk”.

Bei aktuellen Linux-Werkzeugen zu vmdk führt der Weg zur Lösung der oben genannten Probleme intern regelmäßig über die Nutzung von FUSE und Loop-Devices. Letztere werden manchmal auch Loopback-Devices genannt; sie sind aber nicht mit dem gleichnamigen Netzwerk-Device “lo” zu verwechseln. Siehe zu Loop-Devices etwa
Wikipedia-Artikel zu Loop-Devices;
OSDevv.org zu Loopback-Device;
http://www.tldp.org/HOWTO/archived/Loopback-Root-FS/Loopback-Root-FS-2.html.

In “vmdk”-Containern mit einer Vielzahl von sparse vmdk-Dateien, aber auch in wachsenden monolithischen vmdk-Dateien ist die Adressierung von Sektoren
und Daten-Blöcke unterschiedlicher Partitionen verständlicherweise kompliziert. Auf solche vmdk-Disk-Images kann man unter Linux deshalb weder fdisk noch kpartx direkt loslassen. Leider. Aber kleine Umwege mit linux-eigenen Zusatztools führen auch dann zum Ziel – selbst wenn man nicht das nachfolgend besprochene Tool von VMware einsetzen will.

Zugriff mit dem VMware-Tool “vmware-mount”

Hat man die VMware-Workstation für Linux lizenziert, finden sich nach der Installation unter “/usr/bin/” eine Reihe von Kommando-Tools vor, die mit “vmware-” beginnen.

mytux:~ # vmware
vmware                            vmware-installer                  vmware-ping
vmware-authd                      vmware-license-check.sh           vmware-tray
vmware-authdlauncher              vmware-license-enter.sh           vmware-usbarbitrator
vmware-collect-host-support-info  vmware-modconfig                  vmware-vdiskmanager
vmware-fuseUI                     vmware-mount                      vmware-vim-cmd
vmware-gksu                       vmware-netcfg                     vmware-vprobe
vmware-hostd   

Die meisten dieser Kommandos haben eine Option “help”, die Informationen liefert. “man”-Seiten gibt es leider nicht.

Für uns relevant ist im aktuellen Kontext “vmware-mount“. Dieses nützliche CLI-Werkzeug ist auch Teil des VMware VDDK (s. folgenden Link vddk/; das VDDK wird unabhängig von der VMware WS angeboten und enthält auch Tools für den Remote-Zugriff auf Virtual Disks eines VMware ESX-Servers).

“vmware-mount help” zeigt die nötigsten Infos und Optionen zum Kommando an:

mytux:~ # vmware-mount help
VMware DiskMount Utility version 6.5.0, build-7528167

Usage: vmware-mount diskPath [partition num] mountPoint
       vmware-mount [option] [opt args]

There are two modes for mounting disks.  If no option is
specified, we mount individual partitions from virtual disks
independently.  The filesystem on the partition will be
accessible at the mount point specified.

The -f option mounts a flat representation of a disk on a
user-specified mount point.  The user must explicitly unmount
the disk when finished.  A disk may not be in both modes at once.

Options: -p <diskID>      list all partitions on a disk
         -l <diskID>      list all mounted partitions on a disk
         -L               list all mounted disks
         -d <mountPoint>  cleanly unmount this partition
                          (closes disk if it is the last partition)
         -f <diskPath> <mountPoint> mount a flat representation of the disk
                          at "mountPoint/flat."
         -k <diskID>      unmount all partitions and close disk
         -K <diskID>      force unmount all partitions and close disk
         -x               unmount all partitions and close all disks
         -X               force unmount all partitions and close all disks
         -r               mount the disk or partition read-only
         -o               comma-separated list of options to be passed
                          to the 'mount' when mounting a partition

 
Wissen muss man demnach noch, was eine sog. “” ist; diese Info erhält man z.B. aus einem von unter VMware bereitgestellten PDF (VMwareDiskMount.pdf :

“In the following list of options, is an identifier of the form username@hostname:/path/to/disk for remote disks, or just the /path/to/disk for local disks.”

Man kann diskIDs für vmdk-Files auf ESX-Servern einsetzen. Das interessiert uns hier nicht
weiter.
Auf lokalen Linux-Systemen entspricht eine diskID gerade einem Pfad (Path) zu einer führenden vmdk-Datei.

Identifikation von Partitionen mit vmware-mount

Probieren wir “vmware-mount” einfach mal lokal aus; auf meinem Testsystem liegt etwa unter “/vmw/Win7” eine Windows 7-Installation für VMware Workstation, die u.a. eine kleine vmdk-Disk namens “Win7_x64_ssd_ex.vmdk” mit einer NTFS-Partition für Testzwecke beherbergt. Um es einfach zu machen, besteht dieses Disk-Image nur aus genau einem vmdk-File (monolithic sparse disk). Es sind keine Extension Files vorgesehen; der Speicherplatz ist aber nicht vorallokiert. “vmware-mount” hat damit erwartungsgemäß keine Probleme:

mytux:/vmw # vmware-mount -p /vmw/Win7/Win7_x64_ssd_ex.vmdk/ 
Nr      Start       Size Type Id Sytem                   
-- ---------- ---------- ---- -- ------------------------
 1       2048   12576768 BIOS  7 HPFS/NTFS

Es wird korrekterweise genau eine Partition mit NTFS erkannt (6GB; 512Byte Sektorgröße). Wären mehrere File-Systeme enthalten, würden die entsprechend aufgelistet werden (s.u.).

fdisk erkennt weder die Partitionen einer über genau ein File repräsentierten monolithischen vmdk-Disk noch die eines echten vmdk-Containers

“fdisk -l” erkennt im Gegensatz zu vmware-mount nur die Blockstruktur des Files als Ganzes, nicht aber dessen interne Filesystem-Struktur:

mytux:~ # fdisk -l /vmw/Win7/Win7_x64_ssd_ex.vmdk 
Disk /vmw/Win7/Win7_x64_ssd_ex.vmdk: 34.9 MiB, 36569088 bytes, 71424 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

Das gilt, obwohl für meine spezielle Test-Disk nur genau ein (wachsendes) vmdk-File vorliegt:

mytux:~ # la /vmw/Win7/ | grep ex
-rw-rw-rw-  1 myself  users   36569088 Mar 23 18:03 Win7_x64_ssd_ex.vmdk

Nun umfasst meine virtuelle Maschine aber auch noch eine weitere Test-Disk, deren Container tatsächlich zwei unterschiedliche Files beinhaltet:

mytux:/vmw/Win7 # la | grep ssdx
-rw-------  1 myself  users 2344157184 Mar 27 19:38 Win7_x64_ssdx-s001.vmdk
-rw-------  1 myself  users     131072 Mar 27 19:37 Win7_x64_ssdx-s002.vmdk
-rw-------  1 myself  users        511 Mar 27 19:34 Win7_x64_ssdx.vmdk

Leider liefert fdisk auch für diesen Fall kein besseres Ergebnis:

mytux:/vmw/Win7 # fdisk -l Win7_x64_ssdx.vmdk 
fdisk: cannot open Win7_x64_ssdx.vmdk: Inappropriate ioctl for device
mytux:/vmw/Win7 # fdisk -l Win7_x64_ssdx-s001.vmdk 
Disk Win7_x64_ssdx-s001.vmdk: 2.2 GiB, 2344157184 bytes, 4578432 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

Dagegen ermittelt vmware-mount auch für diesen komplexen vmdk-Container die richtige Filesystem-Information:

mytux:/vmw/Win7 # vmware-mount -p Win7_x64_ssdx.vmdk 
Nr      Start       Size Type Id Sytem                   
-- ---------- ---------- ---- -- ------------------------
 1       2048    5310464 BIOS  7 HPFS/NTFS
 2    5312512    3072000 BIOS  7 HPFS/NTFS

Aus diesem Grund vermutet man, dass vmware-mount intern zunächst einmal das hoch-spezifische vmdk-(Container)-Format in ein für Linux handhabbares “flat-file”-Format aufdröselt. Zur linux-konformen Handhabung der vmdk-Spezifikation wird dabei intern auf zeitgemäße FUSE-Mechanismen zurückgegriffen. Sagt zumindest eine Recherche zu unterschiedlichen FUSE-Formaten im Internet …

Mounten

Die allgemeine Form des “vmware-mount”-Kommandos ist:

myself@mytux:~> su -c 'vmware-mount /vmw/Win7/Win7_x64_ssd_ex.vmdk /mnt/vmdk/'

Zur Durchführung des Mounts braucht man root-Rechte. Im obigen Fall muss man also das root-Passwort kennen. Alternativ wechselt man gleich in eine root-Shell.

Wir sehen dann in meinem Testfall etwa folgende Inhalte:

myself@mytux:~> la /mnt/vmdk/        
insgesamt 9
drwxrwxrwx 1 root root 4096 22. Mär 10:57 .
drwxr-xr-x 5 root root 4096 20. Mär 18:36 ..
drwxrwxrwx 1 root root    0 22. Mär 10:34 $RECYCLE.BIN
drwxrwxrwx 1 root root    0 21. Mär 08:41 System Volume Information
-rwxrwxrwx 1 root root   11 22. Mär 10:57 ufo1.txt
drwxrwxrwx 1 root root    0 22. Mär 10:36 ufodir
-rwxrwxrwx 1 root root    6 20. Mär 18:35 ufo.txt

Beispiele mit mehreren Partitionen innerhalb einer vmdk-Disk und mit mehreren vmdk-Files eines echten vmdk-Containers diskutiere ich weiter unten. Dabei läuft alles aber weitgehend analog zum eben erläuterten Beispiel ab.

Zwischenschritte von vmware-mount

vmware-mount nimmt uns freundlicherweise gleich mehrere Aktionen ab:

  • Involvieren von “FUSE”-basierten Methoden zur Bereitstellung der “vmdk”-Disk als zusammenhängendes “flat“-File. Dieses (scheinbar) zusammenhängende File wird in einem temporären Verzeichnis unter “/run/vmware/fuse” bereitgestellt
    /run/vmware/fuse/ID-Nummer/flat
    Das Verzeichnis erhält eine ID-Nr, die die Disk identifiziert. Die ID wird als Hash generiert.
  • Anlegen eines Loop-Devices (hier: /dev/loop0) mit richtiger Offset-Positionierung (hier: 1048576).
  • Mounten des Loop-Devices (hier /dev/loop0) auf dem Ziel-Mount-Punkt (hier: /mnt/vmdk); das geschieht wiederum mit Hilfe des Fuse-Plugins für ntfs-ng3

Mehr Information?

Ein paar weiterführende Informationen findet man für unser Testbeispiel durch folgende Kommandos:

mytux:~ # mount
....
/dev/fuse on /run/vmware/fuse/13958668715283886016 type fuse (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)
/dev/loop0 on /mnt/vmdk type fuseblk (ro,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other,blksize=4096)
...
mytux:~ # losetup -l
NAME       SIZELIMIT  OFFSET AUTOCLEAR RO BACK-FILE                                  DIO
/dev/loop0         0 1048576         0  0 /run/vmware/fuse/13958668715283886016/flat   0
....
mytux:~ # cat /run/vmware/fuse/13958668715283886016.info 
.encoding = "UTF-8"
backingPath = "/vmw_win7/Win7_x64_ssd_ex.vmdk"
diskName = "/vmw_win7/Win7_x64_ssd_ex.vmdk"
mountPath = "/run/vmware/fuse/13958668715283886016"
refCount = "1"
privateFlatFile = "TRUE"
isRemote = "FALSE"
openFlags = "0"
readOnly = "FALSE"
mountPath0 = "/mnt/vmdk"
loopPath0 = "/dev/loop0"

 
Auf die Bestimmung des Offsets kommen wir weiter unten zurück.

Sicheres Unmounten

Hat man mittes vmware-mount einen schreibenden Zugriff realisiert, so ist schon allein wegen des umfangreichen Cachings auf einem Linux-Host ein sicheres Unmounten erforderlich: Dabei erfolgt vorab eine Synchronisation (Sync) von geänderten Daten vom Cache in das/die Container-File/s hinein. Das Unmounten erfordert die Angabe der Option “-d”:

mytux:~ # vmware-mount -d /mnt/vmdk/ 

Anzugeben ist dabei lediglich der Mount-Point.
Manchmal dauert der Unmount-Prozess wg. der Syncs zur Festplatte einen Tick.

Mounten als Flat File?

Die Option “-f” (s. oben) deutet an, dass “vmware-mount” dem Linux-User auch die Möglichkeit gibt, einen vmdk-Container einfach nur in ein zusammenhängendes “flat”-File umzuwandeln, das man dann selbst einer weiteren Behandlung zuführen kann:

mytux:~ # vmware-mount "-f" /vmw/Win7/Win7_x64_ssd_ex.vmdk /mnt
mytux:~ # la /mnt
total 6291456
-rw-rw-rw- 1 myself users 6442450944 Mar 23 18:03 flat
mytux:~ # fdisk -l /mnt/flat
Disk /mnt/flat: 6 GiB, 6442450944 bytes, 12582912 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x77138461

Device     Boot Start      End  Sectors Size Id Type
/mnt/flat1       2048 12578815 12576768   6G  7 HPFS/NTFS/exFAT

Wie man die in einem solchen “Flat”-File enthaltenen Filesysteme konkret über Loop-Devices nutzen kann, besprechen wir im übernächsten Artikel, in dem wir ein natives Linux-Tool für den Zugriff auf einen vmdk-Disk-Container benutzen werden.

Vorsicht mit Modifikationen und Rechten bei NTFS-Partitionen einer vmdk-Disk

Da wir gerade bei Rechten waren, ist eine Warnung bzgl. NTFS-Systemen in vmdk-Containern angebracht:

Die User und Rechte im virtualisierten Gastsystem (hier Win7) sind im Linux-Host nicht ohne weiteres bekannt. Bei der Anwendung von ntfs-3g müssen daher Standard-“Umsetzungen” von Linux-UIDs/GIDs auf Windows SIDs verwendet werden sowie Standard-ACL-Abbildungen erfolgen. Im Fall von “vmware-mount” bedeuten die intern gewählten Standard-Umsetzungen:

Warnung 1: Nach dem oben besprochenen Einsatz von vmware-mount erhält jeder Linux-User auf dem Linux-System Lese- und Schreibrechte – sowohl am Flat-File wie auch bzgl. des gemounteten Filesystems.

Das ist leider unabhängig von den (ursprünglichen) Linux-Rechten des Mount-Punktes (hier: /mnt/vmdk). Man probiere das selbst aus und lasse sich die Rechte vor und nach dem Mounten anzeigen. Das hat denn ggf. auch Konsequenzen im virtualisierten Windows-System:

Warnung 2: Evtl. manuell nach dem vmware-mount angelegte Dateien/Ordner auf dem NTFS-System gehören später unter dem virtualisierten Windows zwar den dortigen Administratoren – aber auch dort hat jeder Windows-User trotzdem Vollzugriff.

Diese Rechte-Situation zu ändern ist meines Wissens mit VMware-Tools alleine nicht möglich. Siehe zu einer feingranulareren, Nutzer-unterstüzten Abbildung aber:
Windows Partitionen einbinden mit NTFS-3G.

Read-Only-Mount

Im Zweifel ist es besser, auf Nummer sicher zu gehen und die Filesystem der virtuellen Disk-Images nur read-only zu mounten. Also (als root):

mytux:~ # vmware-mount -r /vmw/Win7/Win7_x64_ssd_ex.vmdk /mnt/vmdk/

Obwohl die Rechte danach immer noch identisch zum vorherigen rw-Mount angezeigt werden, sind faktisch keine Schreibzugriffe mehr möglich. das verhindert aber immer noch nicht den Diebstahl von Daten durch unbefugte Nutzer. In einem kommenden Artikel komme ich beim Zugriff auf “flat”-Files über Loop-Devices auf dieses Thema zurück.

2-te Partition einer Snapshot-vmdk-Disk mounten

Abschließend habe ich zu unserer Test-Disk mal drei Snapshots angelegt und sie zudem danach in zwei NTFS-Partitionen unterteilt. Dann ergibt sich folgendes komplexere Bild:

Die ursprüngliche vmdk-Disk lag unter “/vmw/Win7/”, die virtuelle Maschine mit ihrer Haupdisk aber unter “/vmw/Win7Prod/”
. Die Snapshots der ursprünglichen Disk
/vmw/Win7/Win7_x64_ssd_ex.vmdk
wurden automatisch aber unter “/vmw/Win7Prod/” abgelegt – der letzte als
/vmw/Win7Prod/Win7_x64_ssd_ex-000003.vmdk.

Der Unterschied mach sich sich schon beim Betrachten der Partitionen bemerkbar:

mytux:/vmw/Win7Prod # vmware-mount -p ../Win7/Win7_x64_ssd_ex.vmdk 
Nr      Start       Size Type Id Sytem                   
-- ---------- ---------- ---- -- ------------------------
 1       2048   12576768 BIOS  7 HPFS/NTFS

mytux:/vmw/Win7Prod # vmware-mount -p Win7_x64_ssd_ex-000003.vmdk 
Nr      Start       Size Type Id Sytem                   
-- ---------- ---------- ---- -- ------------------------
 1       2048    6295552 BIOS  7 HPFS/NTFS
 2    6297600    6279168 BIOS  7 HPFS/NTFS

Mounten der zweiten Partition im dritten Snapshot zeigt:

mytux:/vmw/Win7Prod # la | grep _ex
-rw------- 1 myself  users   42860544 Mar 27 11:19 Win7_x64_ssd_ex-000001.vmdk
-rw------- 1 myself  users    1572864 Mar 27 11:51 Win7_x64_ssd_ex-000002.vmdk
-rw------- 1 myself  users    1572864 Mar 27 11:56 Win7_x64_ssd_ex-000003.vmdk

mytux:/vmw/Win7Prod # vmware-mount  Win7_x64_ssd_ex-000003.vmdk 2 /mnt/vmdk

mytux:/vmw/Win7Prod # la /mnt/vmdk
total 8
drwxrwxrwx  1 root root 4096 Mar 27 11:15 .
drwxr-xr-x 38 root root 4096 Mar 20 11:14 ..
drwxrwxrwx  1 root root    0 Mar 27 11:08 System Volume Information
drwxrwxrwx  1 root root    0 Mar 27 11:50 tull
mytux:/vmw/Win7Prod7 # la /run/vmware/fuse
total 8
drwxr-xr-x 3 root   root    80 Mar 27 12:08 .
drwxr-xr-x 5 root   root   180 Mar 27 11:56 ..
dr-xr-xr-x 2 myself users 4096 Mar 27 12:08 11844985246325345490
-rw-r--r-- 1 root   root   344 Mar 27 12:08 11844985246325345490.info
mytux:/vmw/Win7Prod # losetup
NAME       SIZELIMIT     OFFSET AUTOCLEAR RO BACK-FILE                                  DIO
/dev/loop0         0 3224371200         0  0 /run/vmware/fuse/11844985246325345490/flat   0

 
Der Offset errechnet sich hier übrigens aus einem Standard vmdk-Offset von 2048 * 512 Byte plus der Größe der ersten Partition

2048 * 512 + 6295552 * 512 = 6297600 * 512 = 3224371200

Ganz analog läuft unser Beispiel mit dem echten Container “Win7_x64_ssdx.vmdk”, der zwei Extension-Files und zwei Filesysteme beinhaltet:

mytux:/vmw/Win7 # vmware-mount -p Win7_x64_ssdx.vmdk 
Nr      Start       Size Type Id Sytem                   
-- ---------- ---------- ---- -- ------------------------
 1       2048    5310464 BIOS  7 HPFS/NTFS
 2    5312512    3072000 BIOS  7 HPFS/NTFS
mytux:/vmw/Win7 # vmware-mount  Win7_x64_ssdx.vmdk /mnt2
mytux:/vmw/Win77 # la /mnt2
total 8
drwxrwxrwx  1 root root    0 Mar 27 19:35 $RECYCLE.BIN
drwxrwxrwx  1 root root 4096 Mar 27 19:35 .
drwxr-xr-x 38 root root 4096 Mar 20 11:14 ..
drwxrwxrwx  1 root root    0 Mar 27 19:34 System Volume Information
mytux:/vmw/Win7 # vmware-mount -d /mnt2
umount: /var/run/vmware/fuse/15887816320560912647.links/19: target is busy
        (In some cases useful info about processes that
         use the device is found by lsof(8) or fuser(1).)
mytux:/vmw/Win7 # vmware-mount -d /mnt2
Failed to unmount partition '/mnt2': Nothing mounted at the given mountpoint
mytux:/vmw/Win7 # vmware-mount  Win7_x64_ssdx.vmdk 2 /mnt2
mytux:/vmw/Win7 # la /mnt2
total 196124
drwxrwxrwx  1 root root      4096 Mar 27 19:38 .
drwxr-xr-x 38 root root      4096 Mar 20 11:14 ..
drwxrwxrwx  1 root root         0 Mar 27 19:37 System Volume Information
-rwxrwxrwx  2 root root 200822784 Nov  4  2013 mysql-installer-community-5.6.14.0.msi
mytux:/vmw/Win7 # vmware-mount -d /mnt2

Hier sieht man übrigens, dass man bei einer manchmal auftauchende
Fehlermeldung “target is busy” im Unmount-Process, die u.a. auch durch Desktop-Suchmaschinen bedingt sein kann, nicht gleich in Panik verfallen muss.

Man beachte beim zweiten Mount-Versuch die 2 in “vmware-mount Win7_x64_ssdx.vmdk 2 /mnt2″; diese 2 spezifiziert das zweite Filesystem. Auch in diesem Fall wird natürlich ein “Flat-File” angelegt:

mytux:/vmw/Win7 # vmware-mount  Win7_x64_ssdx.vmdk 2 /mnt2
mytux:/vmw/Win7 # la /run/vmware/fuse 
total 8
drwxr-xr-x 3 root root    80 Mar 27 20:50 .
drwxr-xr-x 5 root root   180 Mar 27 19:38 ..
dr-xr-xr-x 2 rmo  users 4096 Mar 27 20:50 15887816320560912647
-rw-r--r-- 1 root root   299 Mar 27 20:50 15887816320560912647.info
mytux:/vmw/Win7 # la /run/vmware/fuse/15887816320560912647 
total 4194304
-rw------- 1 myself  users 4294967296 Mar 27 19:34 flat
mytux:/vmw/Win7 # 

Fazit

vmware-mount bietet eine einfache Möglichkeit, Partitionen, die in vmdk-Containern enthalten sind, unter Linux zu mounten. Container kann man aber auch einfach nur als ein Flat-File mounten und die Behandlung der enthaltenen Partitionen über Loop-Devices selbst übernehmen. Die automatisch vergebenen Rechte (voller Lese- und Schreibzugriff durch jedermann) erfordern aber Vorsicht.

Im nächsten Beitrag

Mounten eines vmdk-Laufwerks im Linux Host – II – Einschub, Spezifikation, Begriffe

liefere ich zunächst einige Hinweise zur vmdk-Spezifikation nach und versuche dann, durch Rückgriff auf ein Tool aus dem qemu-Bereich, das erforderliche Flat-File zu einem vmdk-Container ohne vmware-mount bereitzustellen.

Links

https://www.novell.com/communities/coolsolutions/retrieve-modify-take-backup-files-inside-vmdk-offline-mode/

systemd bug: systemd-tmpfiles-setup.service fails with unknown user “systemd-network”

I had a strange error after updating “systemd” on one of my Opensuse server systems from version 228.41.1 to version 228.44.1. This update seems harmless, but it is not. With it substantial changes appear in the file /usr/lib/tmpfiles.d/systemd.conf. Especially the lines:

d /run/systemd/netif 0755 systemd-network systemd-network -
d /run/systemd/netif/links 0755 systemd-network systemd-network -
d /run/systemd/netif/leases 0755 systemd-network systemd-network -
</p>

In my case this lead to trouble – service “systemd-tmpfiles-setup.service” started to fail :

# systemctl status -l systemd-tmpfiles-setup
● systemd-tmpfiles-setup.service - Create Volatile Files and Directories
   Loaded: loaded (/lib/systemd/system/systemd-tmpfiles-setup.service; static)
   Active: failed (Result: exit-code) .....
...
...
Mar 12 11:33:32 myserv systemd-tmpfiles[509]: [/usr/lib/tmpfiles.d/systemd.conf:19] Unknown user 'systemd-network'.

I checked whether user “systemd-network” existed with YaST. Yes, it was there – with all its default details.
However the command

getent passwd systemd-network

did not give me anything!

It took me a bit to find out what had happened. On this server I had once experimented with NIS, NISplus. The “/etc/passwd”-file still contained a line

+::::::

The “/etc/group”-file had a corresponding “+:::”. However, no active NIS server is any longer defined. Should not matter as long as the file have a correct format, i.e. as long as the NIS-lines are placed at the bottom of the files …

But:
At some point in time (?) systemd had created the user “systemd-network” and a corresponding group. Unfortunately, both entries were dumbly added at the end of the files “/etc/passwd” and “/etc/group” – i.e. after the already existing NIS-lines.

systemd-timesync:x:478:478:systemd Time Synchronization:/:/sbin/nologin
+::::::
systemd-network:x:475:475:systemd Network Management:/:/sbin/nologin

Not funny! Because, this in turn became the cause for the empty “getent”-answer!

However, it seems that systemd now uses “getent” to check the existence of some special systemd-users like “systemd-network” as a requirement for starting certain services. Which then leads to errors …

Summary
“systemd” seems to add new user- and group-entries at the bottom of the files “/etc/passwd” and “/etc/group” – without checking for NIS lines. Or it at least did at some point in the past. This may prevent the start of some initial services for which the existence of user or group entries are checked.

So, if you run across a similar problem check your “passwd” and “group” files for wrong entries at the end of the file! Move the NIS lines to the very bottom of the files. Afterward “getent” will work again for all user entries – and your failed services hopefully will start again.

Note: If you still get errors for “unknown systemd-users” you have to check whether entries for all the required users really exist in “/etc/passwd”.

P.S.: The stupid thing on Opensuse is that YaST shows you the required users with passwd-entries below a NIS line as existing, whereas “getent” does not.