KVM: fsck direkt auf dem KVM-Host zu Gast-Filesystemen in LUKS-verschlüsselten LVM-Volumes – Unterschiede zwischen Raw Devices und qcow2-Image-Files

Ich betreibe bestimmte Linux-Systeme als KVM-Gäste mit verschlüsseltem Plattenunterbau. Die Partitionen des KVM-Hosts selbst sind zwar auch verschlüsselt; in diesem Artikel betrachte ich aber verschlüsselte virtuelle Disks für KVM-Gastsysteme. Ich nutze hierfür auf dem KVM-Host definierte LVM-Volumes, die mit dm-crypt/LUKS verschlüsselt wurden.

Dabei setze ich regelmäßig zwei Varianten ein:

  • Variante 1: Ein oder mehrere verschlüsselte LVM-Volumes werden dem Gastsystem (in entschlüsseltem Zustand) als “Raw-Devices” zur Verfügung gestellt. Das Gastsystem erstellt dort seine Partitionen (oder im Einzelfall auch eigene LVM-Volumes) mit je einem Linux-Filesystem.
  • Variante 2: Verschlüsselte LVM-Volumes des Hosts enthalten qcow2-Container-Dateien, die vom KVM-Gast als virtuelle Disks genutzt werden. Im qcow2-Container legt der Gast dann eigene LVM-Volumes mit einem Linux-Filesystem an.

Für regelmäßige fsck-Checks der Filesysteme im KVM-Gast kann man einerseits dadurch sorgen, dass man entsprechende Einstellungen für das Gast-Filesystem selbst vornimmt. So kann man mit “tune2fs” den sog. “maximum mount count” auf eine hinreichend kleine Anzahl von Mounts stellen. Das empfiehlt sich vor allem beim root-Filesystem des Gastes: Das darf ja bei der Durchführung von fsck nicht gemountet sein – dies erfordert ansonsten Kunstgriffe, wenn man im bootenden KVM-Gast vor dem Mounten des root-Filesystems fsck erzwingen will.

Manchmal möchte man im Rahmen automatisierter Maintenance-Verfahren aber auch direkt vom KVM-Host aus Filesystem-Checks mit fsck für die Filesystem der KVM-Gäste durchführen. Natürlich ohne das Gastsystem hochzufahren. Wie macht man das im Fall der genannten zwei Varianten?

fsck in Variante 1 – LVM-Volume als verschlüsseltes Raw-Device des Gastes

Variante 1 weist folgende Schichtung bzgl. der physikalischen und virtuellen Disks auf:

  • Physikalische Plattenpartitionen für Raid   >>  
  • Raid 10   >>  
  • LVM   >>  
  • LVM-Groups und LVM-Volumes, die der Host nutzen kann   >>  
  • dm-crypt/LUKS-Verschlüsselung eines (oder mehrerer) von LVM-Volumes, die den Gästen as Raw-Devices bereitgestellt werden.   >>  
  • KVM/QEMU- und Gastsystem mit Zugriff auf das Raw-Volume als virtuelle Platte   >>  
  • Partitionen (oder LVM-Volumes) im Gastsystem   >>  
  • ext4-Filesysteme im Gastsystem

Hier führt der Weg über die Anwendung von “cryptsetup” und z.B. das Tool “kpartx” (das man natürlich installiert haben muss). Wir führen alle Operation natürlich nur dann durch, wenn das KVM-Gastsystem selbst nicht läuft. Wir müssen vermeiden, dass auf die Partitionen des Gastes von mehreren Betriebssystemen aus (Host und Gast) gleichzeitig schreibend zugegriffen wird.

Ich gehe in unserem Beispiel mal davon aus, dass die Entschlüsselung des betreffenden LVM-Volumes für den Gast auf dem KVM-Host noch nicht vorgenommen wurde. Dieses Volume liege in einer logischen Volume Group “lvg2” und habe die Bezeichnung “lvhd0”.

Das Kommando “la” ist in folgendem Beispiel ein Alias für ‘ls -la’; alle Kommandos werden direkt auf dem Host ausgeführt. Das jeweilige KVM-Gastsystem ist nicht hochgefahren. Unter dem Verzeichnis “/dev/mapper” finden wir dann bei aktivierten Volume-Groups auf dem KVM-Host etwa
folgenden Eintrag vor;

mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     340 Aug  4 09:46 .
drwxr-xr-x 22 root root    9720 Aug  4 09:50 ..
crw-------  1 root root 10, 236 Aug  4 09:41 control
... 
lrwxrwxrwx  1 root root       8 Aug  4 09:46 lvg2-lvhd0 -> ../dm-11
...                                                                    

Zunächst müssen wir dieses Volume entschlüsseln:

mytux:~ # cryptsetup open /dev/mapper/lvg2-lvhd0  cr_hd0
Enter passphrase for /dev/mapper/lvg2-lvhd0: 

mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     340 Aug  4 09:46 .
drwxr-xr-x 22 root root    9720 Aug  4 09:50 ..
crw-------  1 root root 10, 236 Aug  4 09:41 control
lrwxrwxrwx  1 root root       8 Aug  4 09:46 cr_hd0 -> ../dm-16
...
lrwxrwxrwx  1 root root       8 Aug  4 09:46 lvg2-lvhd0 -> ../dm-11
...                                                                    

Ok. Der Befehl “qemu-img” informiert uns darüber, dass wir es tatsächlich mit einem Raw-Device (von 100GB Größe) zu tun haben:

 
mytux:~ # qemu-img info /dev/mapper/cr_hd0
image: /dev/mapper/cr_hd0
file format: raw
virtual size: 100G (107372085248 bytes)
disk size: 0

Infos zur Partitionierung des “Raw Devices”
In unserem Beispiel befinden sich auf dem entschlüsselten LVM-Volume des Hosts zwei Partitionen des Gastes: eine swap-Partition und eine Partition mit einem ext4-Filesystem. Es gibt mehrere Tools, mit denen man die Partitionsstruktur unterhalb eines Raw-Devices für einen KVM-Gast auf dem Host selbst untersuchen kann:
“fdisk”, “parted”, “virt-filesystems” und eben auch “kpartx”:

 
mytux:~ # fdisk -l /dev/mapper/cr_hd0
Disk /dev/mapper/cr_imap: 100 GiB, 107372085248 bytes, 209711104 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: 0x00041fe1

Device                    Boot   Start       End   Sectors  Size Id Type
/dev/mapper/cr_hd0-part1         2048   3067903   3065856  1.5G 82 Linux swap / Solaris
/dev/mapper/cr_hd0-part2 *    3067904 167772159 164704256 78.6G 83 Linux

mytux:~ # parted /dev/mapper/cr_hd0 unit s print
Model: Linux device-mapper (crypt) (dm)
Disk /dev/mapper/cr_hd0: 209711104s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start     End         Size        Type     File system     Flags
 1      2048s     3067903s    3065856s    primary  linux-swap(v1)  type=82
 2      3067904s  167772159s  164704256s  primary  ext4            boot, type=83
 
mytux:~ # virt-filesystems -a /dev/mapper/cr_hd0 --extra
/dev/sda1
/dev/sda2
mytux:~ # virt-filesystems -a /dev/mapper/cr_hd0 --extra -l
Name       Type        VFS   Label  Size         Parent
/dev/sda1  filesystem  swap  -      1569718272   -
/dev/sda2  filesystem  ext4  -      84328579072  -
 
mytux:~ # kpartx -l /dev/mapper/cr_hd0 
cr_hd01 : 0 3065856 /dev/mapper/cr_hd0 2048
cr_hd02 : 0 164704256 /dev/mapper/cr_hd0 3067904

Hinweis:

kpartx liefert Infos zur Partionierung (samt Offests) auch für Disk-Image-Files im “Raw”-Format. kpartx funktioniert jedoch nicht für Disk-Image-Files im qcow2-Format!

Mit Ausnahme von “virt-filesystems” stellen uns alle oben vorgestellten Tools auch Offset-Informationen zur Verfügung:
Die Angaben 2048(s) und 3067904(s) entsprechen Offset-Adressen der Partitionen; wir müssen die Zahl
der Sektoren allerdings noch mit der Anzahl der Bytes (512) multiplizieren: also z.B. 2048 * 512 ist der Offset für die erste (swap-) Partition.

Man könnte zur Partitionsbestimmmung auch “guestfish” und die zu guestfish gehörigen Sub-Kommandos run und list-filesystems oder aber auch das Tool “qemu-nbd” heranziehen. “qemu-nbd” diskutiere ich gleich im Detail anhand der Variante 2.

Partitionen des Raw-LVM-Volumes (= Raw-Device für das KVM-Gastsytem )ansprechen
“kpartx -a” liefert uns für Devices im Raw-Format eine einfache Möglichkeit, die darin liegenden Partitionen anzusprechen.

mytux:~ # kpartx -a /dev/mapper/cr_hd0
mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     420 Aug  6 14:36 .
drwxr-xr-x 22 root root    9740 Aug  6 14:36 ..
crw-------  1 root root 10, 236 Aug  6 08:26 control
lrwxrwxrwx  1 root root       8 Aug  6 14:32 cr_hd0 -> ../dm-16
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd01 -> ../dm-17
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd02 -> ../dm-18
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd0_part1 -> ../dm-17
lrwxrwxrwx  1 root root       8 Aug  6 14:36 cr_hd0_part2 -> ../dm-18
....
lrwxrwxrwx  1 root root       7 Aug  6 08:55 lvg2-lvhd0 -> ../dm-11
...
mytux:~ # 

Man beachte die unterschiedliche Bezeichnung, die auf das gleiche Device verlinken. Wir wissen bereits, dass die zweite Partition ein ext4-Filesystem des KVM-Gastes enthält. Also

mytux:~ # fsck -f /dev/mapper/cr_hd02
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/cr_hd02: 1016912/5152768 files (0.1% non-contiguous), 6724050/20588032 blocks
mytux:~ # 

Anschließend können wir das Mapping durch “kpartx -d” wieder rückgängig machen:

mytux:~ # kpartx -d /dev/mapper/cr_hd0
mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     340 Aug  6 14:45 .
drwxr-xr-x 22 root root    9700 Aug  6 14:45 ..
crw-------  1 root root 10, 236 Aug  6 08:26 control
lrwxrwxrwx  1 root root       8 Aug  6 14:32 cr_hd0 -> ../dm-16
...
lrwxrwxrwx  1 root root       7 Aug  6 08:55 lvg2-lvhd0 -> ../dm-11 
mytux:~ # 

Was tun, wenn das Gastsystem auch selbst LVM nutzt?
In unserem Fall lag im Gastsystem selbst keine LVM-Struktur vor. Hätten wir das gehabt, hätten wir noch zwei weitere Schritte vornehmen müssen – nämlich “vgscan”, “vgchange -ay”. Erst danach hätten wir “fsck” ausführen können. Wir werden dies weiter unten bei der Diskussion der Variante 2 sehen.

Arbeit über Loop-Devices
Der Vollständigkeit halber zeige ich kurz noch, wie man Partitionen von KVM-RAW-Devices über ihre Offsets auch als Loop-Devices ansprechen kann. Die zweite Partition hat in unserem Beispiel einen Offset von 3067904 * 512 = 1570766848 Bytes.

Also:

mytux:~ # losetup -r -o 1570766848  /dev/loop3 /dev/mapper/cr_hd0
mytux:~ # fsck -f /dev/loop3
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
fsck.ext4: Operation not permitted while trying to open /dev/loop3
You must have r/w access to the filesystem or be root
mytux:~ # losetup -d  /dev/loop3 
mytux:~ # losetup  -o 1570766848  /dev/loop3 /dev/mapper/cr_hd0  
mytux:~ # fsck -f /dev/loop3     
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking 
reference counts
Pass 5: Checking group summary information
/dev/loop3: 1016912/5152768 files (0.1% non-contiguous), 6724050/20588032 blocks
mytux:~ # 
mytux:~ # tune2fs -l /dev/loop3
tune2fs 1.42.11 (09-Jul-2014)
Filesystem volume name:   <none>
Last mounted on:          /
Filesystem UUID:          4388dd4b-ac1a-5c9c-b8d6-88e53b12bd2d
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              5152768
Block count:              20588032
Reserved block count:     267644
Free blocks:              13863982
Free inodes:              4135856
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1019
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Flex block group size:    16
Filesystem created:       Mon Jan  6 15:44:37 2014
Last mount time:          Mon Aug  6 08:56:27 2018
Last write time:          Mon Aug  6 15:01:58 2018
Mount count:              0
Maximum mount count:      2
Last checked:             Mon Aug  6 15:01:58 2018
Check interval:           172800 (2 days)
Next check after:         Wed Aug  8 15:01:58 2018
Lifetime writes:          2270 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      ce2daf83-bc25-44d5-fcdf-b35afd5c8f2b
Journal backup:           inode blocks
mytux:~ # 
mytux:~ # losetup -d  /dev/loop3

Der Leser sieht, dass ich in der letzten Befehlssequenz anfänglich aus lauter guter Gewohnheit das Device nur im read-only modus als Loop-Device angelegt hatte. Erst nach einer Korrektur läuft dann fsck. Natürlich kann man dann z.B. auch tune2fs auf das Loop-Device anwenden. Über Loop-Devices geht es also auch. Man muss dann halt nur die Offsets wissen!

fsck in Variante 2 – verschlüsseltes LVM-Volume mit Disk-Image-File im “qcow2”-Format

In diesem Szenario liegt eine wirklich komplexe Schichtung vor:

KVM-Host -> LVM-Volume-Group -> Luks-verschlüsseltes LVM-Volume -> qcow2-Image-File -> Partitions- und LVM-Struktur des KVM-Gastsystems -> Volumegroup mit LVM-Volume des Gastes -> ext4-Filesystem

In diesem Szenario wirken sich vor allem zwei bedeutsame Unterschiede zur Variante 1 aus:

  • Unser Disk-Image-File (eine Art Container-File; “os43.qcow2”) hat kein Raw-Format – daran scheitert u.a. “kpartx -a”.
  • In dem Container-File befindet sich eine Partition, mittels derer das Gastsystem eine LVM-Logical-Volume-Group “lvg1” samt einem Logical Volume “lvroot” angelegt hat.

Zum ersten Problem:
Es ist hier zu bedenken, dass wir das zu prüfende Filesystem ja nicht auf dem Host mounten wollen. Das einzige mir bekannte Programm, das uns den Inhalt (also die Partitionen) des qcow2-Files samt Offsets bedarfsgerecht zur Verfügung stellt, ist <strong>qemu-nbd</strong>. Bedarfsgerecht heißt hier, dass Physical Volumes (Partitione) des Gastes anschließend auf dem KVM-Host in Form von Loop-Devices weiter genutzt werden können. Das ermöglicht es uns dann, die LVM Volume-Group und die LVM-Volumes innerhalb des qcow2-Files anzusprechen und “fsck -f” auszuführen.

Hinweis:

Es gibt zwar eine Möglichkeit eine Standardvariante von fsck innerhalb des Kommandos “guestfish” aus der libguestfs-Suite anzuwenden (s.u.); “fsck -f” geht damit aber nicht.

Zum zweiten Problem:
Neben der Aufdröselung der Partitionsstruktur (samt Offsets) im qcow2-File mit seinem komplexen Format, müssen geeignete Tools auf dem Host auch noch die interne LVM-Struktur erkennen und zu aktivieren. Wir werden hierfür das Gespann “vgscan und “vgchange” einsetzen.

Entschlüsselung und Mounten des LVM-Volumes des Hosts
Alle nachfolgenden Kommandos werden wieder direkt auf dem KVM-Host ausgeführt. Zunächst müssen wir wie in Variante 1 das passende LVM-Volume des KVM-Hosts entschlüsseln. Wir müssen das dekryptierte Device anschließend aber auch noch an geeigneter Stelle des Hosts mounten, um das dort enthaltene Disk-Image-File ansprechen zu können:

mxtux:~ # cryptsetup open /dev/mapper/volssd10-kvmos  cr_kvmos
Enter passphrase for /dev/mapper/volssd10-kvmos:
mxtux:~ # 
mxtux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     420 Aug  6 11:52 .
drwxr-xr-x 27 root root   12300 Aug  6 11:52 ..
crw-------  1 root root 10, 236 Aug  6 08:49 control
lrwxrwxrwx  1 root root       8 Aug  6 11:48 cr_kvmos -> ../dm-16
...
lrwxrwxrwx  1 root root       7 Aug  6 11:48 volssd10-kvmos -> ../dm-6
...  
mxtux:~ # 
mount /dev/mapper/cr_kvmos /kvm/os                                                                  
mxtux:~ # 

Informationen zum Partitionsaufbau innerhalb des qcow2-Image-Files:
Während kpartx keine ausreichenden Informationen liefert, ermöglicht uns das Kommando “virt-filesystems” aus der libguestfs-Suite (bei Bedarf installieren!) einen Einblick in die Unterteilung des qcow2-Image-Files “os43.qcow2”:

mytux:~ # virt-filesystems  -a  /kvm/os/os43.qcow2 --extra -l 
Name              Type        VFS   Label  Size        Parent
/dev/sda1         filesystem  swap  -      2153775104  -
/dev/lvg1/lvroot  filesystem  ext4  -      8589934592  -

Netterweise erkennt “virt-filesystems” sogar die LVM-Volume-Group “lvg1” und das Volume “lvroot” ! Wir könnten dieses logische Volume des Gastes nun sogar mittels des Kommandos “guestmount” (ebenfalls Teil der libguestfs) auf dem Host mounten und mit den Inhalten arbeiten:

mytux:~ # guestmount -a /kvm/os/os43.qcow2 -m /dev/lvg1/lvroot --ro /mnt2
mytux:~ # la /mnt2
total 136
drwxr-xr-x  23 root root   4096 Jun  7 18:27 .
drwxr-xr-x  40 root root   4096 Jul 25 18:55 ..
drwxr-xr-x   2 root root   4096 May 14 19:20 bin
drwxr-xr-x   3 root root   4096 May 14 19:22 boot
drwxr-xr-x   2 root root   4096 May 14 17:09 dev
drwxr-xr-x 128 root root  12288 Aug  4 11:41 etc
drwxr-xr-x   3 rmu  users  4096 May 28 17:43 extras
drwxr-xr-x   4 root root   4096 May 15 20:29 home
drwxr-xr-x  12 root root   4096 May 14 19:20 lib
drwxr-xr-x   7 root root  12288 May 14 19:21 lib64
drwx------   2 root root  16384 May 14 17:09 lost+found
drwxr-xr-x   2 root root   4096 May 10  2017 mnt
drwxr-xr-x   2 root root   4096 May 10  2017 opt
drwxr-xr-x   2 root root   4096 May 14 17:09 proc
drwx------   9 root root   4096 Jun 12 21:52 root
drwxr-xr-x   2 root root   4096 May 14 17:09 run
drwxr-xr-x   2 root root  12288 May 14 21:12 sbin
drwxr-xr-x   2 root root   4096 May 10  2017 selinux
drwxr-xr-x   5 root root   4096 May 14 17:12 srv
drwxr-xr-x   2 root root   4096 May 14 17:09 sys
drwxrwxrwt  26 root root  12288 Aug  4 11:41 tmp
drwxr-xr-x  13 root root   4096 May 14 17:10 usr
drwxr-xr-x  12 root root   4096 May 14 17:24 var
mytux:~ # umount /mnt2

Leider bringt uns das hinsichtlich des angestrebten “fsck” aber gar nichts.

nEinsatz von “qemu-nbd”
Im Gegensatz zu RAW-Devices oder Raw-Image-Files kommen wir an dieser Stelle nicht um den Einsatz von des qemu-eigenen Kommandos “qemu-nbd” herum. Also:

mxtux:~ # modprobe nbd max_part=8
mxtux:~ # qemu-nbd --connect=/dev/nbd0 /kvm/os/os43.qcow2 
mxtux:~ # la /dev/ | grep nbd0
brw-rw----   1 root disk       43,   0 Aug  6 16:22 nbd0
brw-rw----   1 root disk       43,   1 Aug  6 16:22 nbd0p1
brw-rw----   1 root disk       43,   2 Aug  6 16:22 nbd0p2

Was verbirgt sich hinter diesen neuen Devices dahinter?

mxtux:~ # fdisk -l /dev/nbd0
Disk /dev/nbd0: 15 GiB, 16106127360 bytes, 31457280 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: 0x000392a8

Device      Boot   Start      End  Sectors Size Id Type
/dev/nbd0p1         2048  4208639  4206592   2G 82 Linux swap / Solaris
/dev/nbd0p2 *    4208640 31457279 27248640  13G 8e Linux LVM

Aha, fdisk erkennt, dass die zweite Partition LVM nutzt. Wie kommen wir nun weiter? “kpartx” führt uns nicht zum Ziel, da LVM Volume Groups erst aktiviert werden müssen. Hierzu sind zwei Schritte nötig

  • Schritt 1: Wir müssen uns das LVM-Device des qcow2-Files auf dem Host zugänglich machen – als Loop-Device. Dazu berechnen wir dessen Offset ( = 4208640 * 512 = 2154823680)
  • Schritt 2: Wir müssen wir auf dem KVM-Host das Kommando “vgscan” ausführen und danach die gewünschten Volume Group mit “vgchange” aktivieren

Also:

mxtux:~ # vgscan
  Reading all physical volumes.  This may take a while...
  Found volume group "volssd10" using metadata type lvm2
  Found volume group "lvgssd5" using metadata type lvm2
  Found volume group "lvg2" using metadata type lvm2
  Found volume group "lvg10f2" using metadata type lvm2
  Found volume group "volgrp1" using metadata type lvm2

mxtux:~ # losetup -o 2154823680 /dev/loop5 /dev/nbd0

mxtux:~ # vgscan
  Reading all physical volumes.  This may take a while...
  Found volume group "lvg1" using metadata type lvm2
  Found volume group "volssd10" using metadata type lvm2
  Found volume group "lvgssd5" using metadata type lvm2
  Found volume group "lvg2" using metadata type lvm2
  Found volume group "lvg10f2" using metadata type lvm2
  Found volume group "volgrp1" using metadata type lvm2
mxtux:~ # 

Aha, vgscan erkennt eine neue Volume-Group “lvg1”. Wir sehen hier übrigens, dass es sich lohnt, die Bezeichnungen von Groups auf dem Host und den Gastsystemen unterschiedlich und global eindeutig zu wählen – etwas, das ich hier zu meiner Schande versäumt habe. Nun müssen wir die Volume Group noch aktivieren:

mxtux:~ # vgchange -ay lvg1
  1 logical volume(s) in volume group "lvg1" now active
mxtux:~ #
mxtux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     460 Aug  6 16:44 .
drwxr-xr-x 28 root root   12880 Aug  6 16:44 ..
crw-------  1 root root 10, 236 Aug  6 08:49 control
lrwxrwxrwx  1 root root       8 Aug  6 11:48 cr_kvmos -> ../dm-16
...
lrwxrwxrwx  1 root root       8 Aug  6 16:44 lvg1-lvroot -> ../dm-19
...
lrwxrwxrwx  1 root root       8 Aug  6 16:33 nbd0p2p1 -> ../dm-18
...

mxtux:~ # fdisk -l /dev/mapper/lvg1-lvroot
Disk /dev/mapper/lvg1-lvroot: 8 GiB, 8589934592 bytes, 16777216 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

mxtux:~ # 
virt-filesystems -a /dev/nbd0 --extra --parts --blkdevs --filesystems -l --lvs
Name             Type       VFS  Label MBR Size        Parent
/dev/sda1        filesystem swap -     -   2153775104  -
/dev/lvg1/lvroot filesystem ext4 -     -   8589934592  -
/dev/lvg1/lvroot lv         -    -     -   8589934592  /dev/lvg1
/dev/sda1        partition  -    -     82  2153775104  /dev/sda
/dev/sda2        partition  -    -     8e  13951303680 /dev/sda
/dev/sda         device     -    -     -   16106127360 -

Nun können wir den Filesystem-Check des LVM-Volume des KVM-Gasts, das sich m qcow2-File befindet, auf dem KVM-Host ausführen. Und danach alle Kommandos wieder rückgängig machen:

mxtux:~ # fsck -f /dev/mapper/lvg1-lvroot
fsck from util-linux 2.29.2
e2fsck 1.42.11 (09-Jul-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/lvg1-lvroot: 245825/524288 files (0.1% non-contiguous), 1707336/2097152 blocks
mxtux:~ # 
mxtux:~ #  vgchange -an lvg1
  0 logical volume(s) in volume group "lvg1" now active
rux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     440 Aug  6 17:09 .
drwxr-xr-x 27 root root   12840 Aug  6 17:09 ..
crw-------  1 root root 10, 236 Aug  6 08:49 control
lrwxrwxrwx  1 root root       8 Aug  6 11:48 cr_kvmos -> ../dm-16
...
lrwxrwxrwx  1 root root       8 Aug  6 16:33 nbd0p2p1 -> ../dm-18
..
mxtux:~ # losetup -d /dev/loop5 
mxtux:~ # qemu-nbd -d /dev/nbd0 
/dev/nbd0 disconnected
mxtux:~ # rmmod nbd
mxtux:~ # 

Ich bitte zu beachten, dass wir in diesem Fall trotz der bereits sehr komplexen Schichtung immer noch einen Vorteil hatten: Es gab nur genau ein virtuelles LVM-Physical-Volume des Gast-Systems, nämlich die zweite Partition innerhalb des qcow2-Files. Ferner gabe es nur eine Volume-Group. Bei mehreren “Volume Groups”, die sich über unetrschiedliche “Physical Volumes” aus verschiedenen virtuellen Partitionen des Gastes erstreckten, hätten wir alle zugehörigen virtuellen Partitionen auf dem Host als Loop-Devices bereitstellen müssen. Das ist uns im Beipiel erspart geblieben.

fsck in einer dritten Variante – verschlüsseltes LVM-Volume mit einem RAW Image File

Nach all dem Zirkus mit qcow2 stellt sich die Frage: Warum verwendet man nicht gleich Image-Files im Raw-Format? Das ist ein gute Frage; ich werde die Antwort aber auf einen anderen Artikel verschieben. Genannt sei nur der Vorteil des langsam auf die Maximalgröße wachsenden Platzbedarfs im Falle qcow2. Für Disk-Image-Files im Raw-Format spricht aber die Performance. Dennoch ein lapidarer Hinweise zum Einsatz von “fsck” für Partitionen in Raw-Container-Files:

Dieser Fall kann im Kern fast genauso behandelt werden kann, wie oben unter Variante 1 beschrieben. Wer so etwas testen will, kann ja mal ein qcow2-File in ein Raw-Format-File mittels des Kommandos “qemu-img convert” umwandeln (s. die entsprechende man -Seite).

Fazit und eine Alternative

“fsck” mit zugehörigen Optionen für Filesysteme anzuwenden, die sich in verschlüsselten LVM-Volumes eines KVM-Hosts befinden, ist relativ einfach, wenn das LVM-Volume dem KVM-Gast entweder direkt als Raw-Device zur Verfügung gestellt wird oder aber über ein Disk-Image-File im RAW-Format, das sich auf dem Volume befindet. Befinden sich dann unter dem Raw-Device nur gewöhnliche Partitionen kann man sich das Leben mit “kpartx” bequem machen.

Deutlich schwieriger wird die Sache aber mit qcow2-Imag-Files und/oder virtuellen Partitionen von Image-Files, die auf dem Gastsystem in dortigen LVM-Volume-Groups eingesetzt werden. Im Falle von qcow2-Files muss man zunächst zwingend das Kernel-Modul “nbd” und den “qemu-nbd”-Befehl einsetzen.
LVM-Groups innerhalb vom Image-Disk-Files verlangen ferner die Bereitstellung aller entsprechenden zugehörigen virtuellen “Physical Volumes” (virtuelle Partitionen) als Loop-Devices auf dem KVM-Host. Danach sind die Befehle “vgscan” und “vgchange” anzuwenden, um schließlich unter “/dev/mapper” das logische Volume des Gastes mit seinem Filesystem zu erhalten. Erst dann kann man hierauf “fsck” anwenden. Das ist schon komplex, aber man hat am Ende die volle Kontrolle über fsck.

Wem das alles zu schwierig ist, der kann alternativ mal eine einfache Standardvariante des fsck-Befehls unter “guestfish” für Filesysteme von KVM-Gästen ausprobieren. Funktioniert für Raw-Devices und qcow2-Files!

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/