From aed3bf785c85981cae51f1700efd96d709d86b46 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Mon, 2 Aug 2021 16:35:09 +0200 Subject: [PATCH] image-info: mount partitions in correct order when analysing image image-info's code which analysed image with multiple partitions was not correctly working with more than two partitions, which had to be the root '/' and EFI partition '/boot/efi'. The consequence was that SELinux labels on paths which were mounted incorrectly could have been reported as incorrect. Modify `append_partitions()` to first read the fstab entries and then mount all partitions using their UUID in the correct order. Only then analyze the image filesystem tree. Regenerate affected image test cases. Signed-off-by: Tomas Hozza --- .../manifests/rhel_85-aarch64-ami-boot.json | 28 +-------- .../manifests/rhel_85-aarch64-ec2-boot.json | 25 -------- tools/image-info | 58 +++++++++++-------- 3 files changed, 36 insertions(+), 75 deletions(-) diff --git a/test/data/manifests/rhel_85-aarch64-ami-boot.json b/test/data/manifests/rhel_85-aarch64-ami-boot.json index 8456943f5..431cc530b 100644 --- a/test/data/manifests/rhel_85-aarch64-ami-boot.json +++ b/test/data/manifests/rhel_85-aarch64-ami-boot.json @@ -10795,7 +10795,6 @@ }, "rpm-verify": { "changed": { - "/boot": ".M.......", "/etc/chrony.conf": "S.5....T.", "/etc/dnf/plugins/product-id.conf": "..5....T.", "/etc/dnf/plugins/subscription-manager.conf": "..5....T.", @@ -10814,34 +10813,9 @@ "/var/spool/anacron/cron.monthly": ".M.......", "/var/spool/anacron/cron.weekly": ".M......." }, - "missing": [ - "/boot/efi", - "/boot/efi/EFI", - "/boot/efi/EFI/BOOT", - "/boot/efi/EFI/BOOT/BOOTAA64.EFI", - "/boot/efi/EFI/BOOT/fbaa64.efi", - "/boot/efi/EFI/redhat", - "/boot/efi/EFI/redhat", - "/boot/efi/EFI/redhat/BOOTAA64.CSV", - "/boot/efi/EFI/redhat/fonts", - "/boot/efi/EFI/redhat/grubaa64.efi", - "/boot/efi/EFI/redhat/mmaa64.efi", - "/boot/efi/EFI/redhat/shim.efi", - "/boot/efi/EFI/redhat/shimaa64-redhat.efi", - "/boot/efi/EFI/redhat/shimaa64.efi", - "/boot/grub2", - "/boot/grub2/grubenv", - "/boot/loader/entries" - ] + "missing": [] }, "selinux": { - "context-mismatch": [ - { - "actual": "unconfined_u:object_r:unlabeled_t:s0", - "expected": "system_u:object_r:boot_t:s0", - "filename": "/boot" - } - ], "policy": { "SELINUX": "enforcing", "SELINUXTYPE": "targeted" diff --git a/test/data/manifests/rhel_85-aarch64-ec2-boot.json b/test/data/manifests/rhel_85-aarch64-ec2-boot.json index 45609410e..9b1da0f7b 100644 --- a/test/data/manifests/rhel_85-aarch64-ec2-boot.json +++ b/test/data/manifests/rhel_85-aarch64-ec2-boot.json @@ -10835,7 +10835,6 @@ }, "rpm-verify": { "changed": { - "/boot": ".M.......", "/etc/chrony.conf": "S.5....T.", "/etc/dnf/plugins/product-id.conf": "..5....T.", "/etc/dnf/plugins/subscription-manager.conf": "..5....T.", @@ -10857,34 +10856,10 @@ "/var/spool/anacron/cron.weekly": ".M......." }, "missing": [ - "/boot/efi", - "/boot/efi/EFI", - "/boot/efi/EFI/BOOT", - "/boot/efi/EFI/BOOT/BOOTAA64.EFI", - "/boot/efi/EFI/BOOT/fbaa64.efi", - "/boot/efi/EFI/redhat", - "/boot/efi/EFI/redhat", - "/boot/efi/EFI/redhat/BOOTAA64.CSV", - "/boot/efi/EFI/redhat/fonts", - "/boot/efi/EFI/redhat/grubaa64.efi", - "/boot/efi/EFI/redhat/mmaa64.efi", - "/boot/efi/EFI/redhat/shim.efi", - "/boot/efi/EFI/redhat/shimaa64-redhat.efi", - "/boot/efi/EFI/redhat/shimaa64.efi", - "/boot/grub2", - "/boot/grub2/grubenv", - "/boot/loader/entries", "/etc/yum.repos.d/redhat-rhui.repo" ] }, "selinux": { - "context-mismatch": [ - { - "actual": "unconfined_u:object_r:unlabeled_t:s0", - "expected": "system_u:object_r:boot_t:s0", - "filename": "/boot" - } - ], "policy": { "SELINUX": "enforcing", "SELINUXTYPE": "targeted" diff --git a/tools/image-info b/tools/image-info index 01033e8de..ba0a99b3d 100755 --- a/tools/image-info +++ b/tools/image-info @@ -7,6 +7,7 @@ import errno import functools import glob import mimetypes +import operator import json import os import platform @@ -1812,44 +1813,55 @@ def append_filesystem(report, tree, *, is_ostree=False): print("EFI partition", file=sys.stderr) -def partition_is_esp(partition): - return partition["type"] == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" - - -def find_esp(partitions): - for i, p in enumerate(partitions): - if partition_is_esp(p): - return p, i - return None, 0 - - def append_partitions(report, device, loctl): partitions = report["partitions"] - esp, esp_id = find_esp(partitions) with contextlib.ExitStack() as cm: - + # open each partition as a loop device devices = {} + device_idx_by_part_uuid = {} for n, part in enumerate(partitions): start, size = part["start"], part["size"] dev = cm.enter_context(loop_open(loctl, device, offset=start, size=size)) devices[n] = dev read_partition(dev, part) + if part["uuid"]: + device_idx_by_part_uuid[part["uuid"].upper()] = n + # find partition with fstab and read it + fstab = [] for n, part in enumerate(partitions): if not part["fstype"]: continue - with mount(devices[n]) as tree: - if esp and os.path.exists(f"{tree}/boot/efi"): - with mount_at(devices[esp_id], f"{tree}/boot/efi", options=['umask=077']): - append_filesystem(report, tree) - # situation when /boot is on a separate partition - elif esp and os.path.exists(f"{tree}/efi"): - with mount_at(devices[esp_id], f"{tree}/efi", options=['umask=077']): - append_filesystem(report, tree) - else: - append_filesystem(report, tree) + if os.path.exists(f"{tree}/etc/fstab"): + fstab.extend(read_fstab(tree)) + break + # sort the fstab entries by the mountpoint + fstab = sorted(fstab, key=operator.itemgetter(1)) + + # mount all partitions to ther respective mount points + root_tree = "" + for n, fstab_entry in enumerate(fstab): + part_uuid = fstab_entry[0].split("=")[1].upper() + part_device = devices[device_idx_by_part_uuid[part_uuid]] + part_mountpoint = fstab_entry[1] + part_fstype = fstab_entry[2] + part_options = fstab_entry[3].split(",") + + # the first mount point should be root + if n == 0: + if part_mountpoint != "/": + raise RuntimeError("The first mountpoint in sorted fstab entries is not '/'") + root_tree = cm.enter_context(mount(part_device)) + continue + + cm.enter_context(mount_at(part_device, f"{root_tree}{part_mountpoint}", options=part_options, extra=["-t", part_fstype])) + + if not root_tree: + raise RuntimeError("The root filesystem tree is not mounted") + + append_filesystem(report, root_tree) def analyse_image(image):