mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
daemon: inspect: check /etc/crypttab for /dev/mapper/*
Encrypted root fs on SUSE distros will present itself like so: ``` /dev/mapper/cr_root / btrfs defaults 0 0 UUID=588905f9-bfa4-47b5-9fe8-893cb8ad4a0b /var btrfs subvol=/@/var 0 0 ... more subvols here ... UUID=8a278363-3042-4dea-a878-592f5e1b7381 swap btrfs defaults 0 0 /dev/mapper/cr_root /.snapshots btrfs subvol=/@/.snapshots 0 0 cr_root UUID=5289379a-a707-41b5-994c-c383f7ed54cc none x-initrd.attach ``` This breaks `-i` inspection, since libguestfs doesn't know what /dev/mapper/cr_root is supposed to be, and nothing in the appliance will autopopulate that path. This isn't a problem on Fedora, where it uses UUID= instead of a /dev/mapper path. Currently when we see /dev/mapper as a mount prefix, we only attempt to do some LVM name mapping. This extends libguestfs to check /etc/crypttab first. If we find an entry for the mapper path, and it points to the encrypted luks UUID, we use that UUID to build the associated /dev/disk/by-id/dm-uuid-CRYPT-* path, which is a symlink to the unencrypted /dev/dm-X path Resolves: https://issues.redhat.com/browse/RHEL-93584 Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
@@ -41,7 +41,7 @@ let rec check_fstab ?(mdadm_conf = false) (root_mountable : Mountable.t)
|
||||
os_type =
|
||||
let mdadmfiles =
|
||||
if mdadm_conf then ["/etc/mdadm.conf"; "/etc/mdadm/mdadm.conf"] else [] in
|
||||
let configfiles = "/etc/fstab" :: mdadmfiles in
|
||||
let configfiles = "/etc/fstab" :: "/etc/crypttab" :: mdadmfiles in
|
||||
|
||||
(* If verbose, dump the contents of each config file as that can be
|
||||
* useful for debugging.
|
||||
@@ -179,7 +179,7 @@ and check_fstab_entry md_map root_mountable os_type aug entry =
|
||||
root_mountable
|
||||
(* Resolve guest block device names. *)
|
||||
else if String.starts_with "/dev/" spec then
|
||||
resolve_fstab_device spec md_map os_type
|
||||
resolve_fstab_device spec md_map os_type aug
|
||||
(* In OpenBSD's fstab you can specify partitions
|
||||
* on a disk by appending a period and a partition
|
||||
* letter to a Disklable Unique Identifier. The
|
||||
@@ -194,7 +194,7 @@ and check_fstab_entry md_map root_mountable os_type aug entry =
|
||||
* assume that this is the first disk.
|
||||
*)
|
||||
let device = sprintf "/dev/sd0%c" part in
|
||||
resolve_fstab_device device md_map os_type
|
||||
resolve_fstab_device device md_map os_type aug
|
||||
)
|
||||
(* Ignore "/.swap" (Pardus) and pseudo-devices
|
||||
* like "tmpfs". If we haven't resolved the device
|
||||
@@ -353,7 +353,7 @@ and parse_md_uuid uuid =
|
||||
* the real VM, which is a reasonable assumption to make. Return
|
||||
* anything we don't recognize unchanged.
|
||||
*)
|
||||
and resolve_fstab_device spec md_map os_type =
|
||||
and resolve_fstab_device spec md_map os_type aug =
|
||||
(* In any case where we didn't match a device pattern or there was
|
||||
* another problem, return this default mountable derived from [spec].
|
||||
*)
|
||||
@@ -366,7 +366,7 @@ and resolve_fstab_device spec md_map os_type =
|
||||
|
||||
if String.starts_with "/dev/mapper" spec then (
|
||||
debug_matching "/dev/mapper";
|
||||
resolve_dev_mapper spec default
|
||||
resolve_dev_mapper spec default aug
|
||||
)
|
||||
|
||||
else if PCRE.matches re_xdev spec then (
|
||||
@@ -540,24 +540,71 @@ and resolve_fstab_device spec md_map os_type =
|
||||
default
|
||||
)
|
||||
|
||||
and resolve_dev_mapper spec default =
|
||||
(* LVM2 does some strange munging on /dev/mapper paths for VGs and
|
||||
* LVs which contain '-' character:
|
||||
*
|
||||
* ><fs> lvcreate LV--test VG--test 32
|
||||
* ><fs> debug ls /dev/mapper
|
||||
* VG----test-LV----test
|
||||
*
|
||||
* This makes it impossible to reverse those paths directly, so
|
||||
* we have implemented lvm_canonical_lv_name in the daemon.
|
||||
*)
|
||||
try
|
||||
match Lvm_utils.lv_canonical spec with
|
||||
| None -> default
|
||||
| Some device -> Mountable.of_device device
|
||||
with
|
||||
(* Ignore devices that don't exist. (RHBZ#811872) *)
|
||||
| Unix.Unix_error (Unix.ENOENT, _, _) -> default
|
||||
and resolve_dev_mapper spec default aug =
|
||||
let augpath =
|
||||
sprintf "/files/etc/crypttab/*[target='%s']/device"
|
||||
(Filename.basename spec) in
|
||||
match aug_get_noerrors aug augpath with
|
||||
| Some device ->
|
||||
(* /dev/mapper name is present in /etc/crypttab *)
|
||||
if verbose() then eprintf "mapped to crypttab device=%s\n%!" device;
|
||||
(* device string is one of:
|
||||
* + UUID=... without any shell quoting
|
||||
* + An absolute path
|
||||
*)
|
||||
if String.starts_with "UUID=" device then (
|
||||
(* We found the UUID for the encrypted LUKS partition, now we use
|
||||
* that to get the unencrypted /dev/dm-X via
|
||||
* /dev/disk/by-id/dm-uuid-CRYPT-* automagic paths. The format is
|
||||
*
|
||||
* /dev/disk/by-id/dm-uuid-CRYPT-$TYPE-$LUKSUUID-$DMNAME
|
||||
*
|
||||
* The fields are
|
||||
* + $TYPE: `LUKS1` or `LUKS2`
|
||||
* + $LUKSUUID: The UUID we got from crypttab, but with `-` removed
|
||||
* + $DMNAME: this would be `cr_root` for `/dev/mapper/cr_root`, but
|
||||
* we just ignore that.
|
||||
*)
|
||||
let byid_dir = "/dev/disk/by-id" in
|
||||
let uuid = String.sub device 5 (String.length device - 5) in
|
||||
let short_uuid = String.replace uuid "-" "" in
|
||||
let regstr = sprintf "^dm-uuid-CRYPT-LUKS.-%s-.*$" short_uuid in
|
||||
let re_dmcrypt = PCRE.compile regstr in
|
||||
let entries = Sys.readdir byid_dir |> Array.to_list in
|
||||
try
|
||||
let filename = List.find (fun f -> PCRE.matches re_dmcrypt f) entries in
|
||||
let fullpath = Filename.concat byid_dir filename in
|
||||
let resolved_path = Unix_utils.Realpath.realpath fullpath in
|
||||
eprintf("Found crypttab mapping %s -> %s\n%!") fullpath resolved_path;
|
||||
Mountable.of_device (resolved_path)
|
||||
with
|
||||
Failure _ | Not_found ->
|
||||
eprintf("Failed to find matching regex %s/%s\n%!") byid_dir regstr;
|
||||
Mountable.of_device spec
|
||||
) else (
|
||||
Mountable.of_device spec
|
||||
)
|
||||
| None ->
|
||||
(* Assume /dev/mapper device is LVM *)
|
||||
|
||||
(* LVM2 does some strange munging on /dev/mapper paths for VGs and
|
||||
* LVs which contain '-' character:
|
||||
*
|
||||
* ><fs> lvcreate LV--test VG--test 32
|
||||
* ><fs> debug ls /dev/mapper
|
||||
* VG----test-LV----test
|
||||
*
|
||||
* This makes it impossible to reverse those paths directly, so
|
||||
* we have implemented lvm_canonical_lv_name in the daemon.
|
||||
*)
|
||||
try
|
||||
match Lvm_utils.lv_canonical spec with
|
||||
| None -> default
|
||||
| Some device -> Mountable.of_device device
|
||||
with
|
||||
(* Ignore devices that don't exist. (RHBZ#811872) *)
|
||||
| Unix.Unix_error (Unix.ENOENT, _, _) -> default
|
||||
|
||||
|
||||
(* type: (h|s|v|xv)
|
||||
* disk: [a-z]+
|
||||
|
||||
Reference in New Issue
Block a user