Repository navigation
Don't write bind mounts to /etc/fstab for nodev - #15322
Chr0mium24 wants to merge 1 commit into
Conversation
The Bash remediation of mount_option_nodev_nonroot_local_partitions takes the source of every local mount reported by findmnt and, if the mount point has no /etc/fstab entry, appends a new entry with that source. For bind mounts and other mounts of a file system subtree, findmnt reports the source as DEVICE[PATH], for example /dev/mapper/vg0-root[/srv/b]. Such an entry names a device that does not exist, so on the next boot systemd waits for it, local-fs.target fails and the system ends up in emergency mode. Skip mounts whose source has the [PATH] suffix unless the mount point already has an /etc/fstab entry. In that case the remediation only adds nodev to the existing entry, as before, so btrfs subvolumes and bind mounts that are listed in /etc/fstab are still remediated. Resolves: ComplianceAsCode#15292
|
Hi @Chr0mium24. Thanks for your PR. I'm waiting for a ComplianceAsCode member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
This datastream diff is auto generated by the check Click here to see the full diffbash remediation for rule 'xccdf_org.ssgproject.content_rule_mount_option_nodev_nonroot_local_partitions' differs.
--- xccdf_org.ssgproject.content_rule_mount_option_nodev_nonroot_local_partitions
+++ xccdf_org.ssgproject.content_rule_mount_option_nodev_nonroot_local_partitions
@@ -57,6 +57,17 @@
fi
done
+ # findmnt shows bind mounts and other mounts of a file system subtree,
+ # such as btrfs subvolumes, as DEVICE[PATH]. That is not a device which
+ # can be written to /etc/fstab, so such a mount is only remediated when
+ # it already has an entry in /etc/fstab.
+ if [[ "$device" == *\[*\] ]]; then
+ fstab_entry_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "$mount_point")"
+ if ! grep -q "$fstab_entry_regexp" /etc/fstab; then
+ continue
+ fi
+ fi
+
# If we reach here, it's a local, non-root partition that isn't excluded.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $mount_point)"
|
Description:
mount_option_nodev_nonroot_local_partitions, skip a mount whose findmnt source has the formDEVICE[PATH](a bind mount, or a mount of a subdirectory or a btrfs subvolume) if its mount point has no/etc/fstabentry. If it has one, the remediation addsnodevto that entry, the same as before./etc/fstabentry, and a bind mount that has its own/etc/fstabentry withoutnodev.Rationale:
The remediation gets the mounts from
findmnt --mtab --raw --evaluateand keeps the records whose source matches\s/dev/\w. When the root of a mount inside its file system is not/, findmnt prints the source asSPEC[ROOT], for example/dev/mapper/vg0-root[/srv/b]. If the mount point is not in/etc/fstab,bash_ensure_mount_option_in_fstabappends$device $mount_point $device_type defaults,...,nodev 0 0, and the[...]source ends up in/etc/fstab. On the next boot systemd waits 90 s for a device that doesn't exist,local-fs.targetfails, and the host drops into emergency mode. Podman hosts hit this because containers/storage bind-mounts its overlay directory onto itself.A mount like that can't be recreated from its findmnt source, so the remediation now leaves it alone unless
/etc/fstabalready has an entry for the mount point. The new check uses the same regular expression thatbash_ensure_mount_option_in_fstabuses to choose between "append a new entry" and "edit the existing entry", so the append branch can't be reached with a[PATH]source. Mounts that have an fstab entry, such as btrfs subvolumes mounted withsubvol=and bind mounts listed in fstab, go through the same code as before.findmnt has no option to leave out bind mounts.
--nofsrootonly removes the[PATH]suffix, and that would turn the record into/dev/mapper/vg0-root /srv/b xfs ..., an fstab entry that mounts the whole root file system on/srv/b. The suffix is the only marker findmnt gives. Inmisc-utils/findmnt.c, theSOURCEcolumn is printed as%s[%s]whenever the fs root is not/and--nofsrootisn't set. I checked the source of util-linux v2.23 (RHEL 7 / OL 7), v2.32 (RHEL 8), v2.40 (RHEL 10) and current master, and they all do this. The fix adds no findmnt option or new tool, only a bash pattern match and agrep -qlike the ones the script already uses. The rendered script is byte-identical for rhel8, rhel9, rhel10, ol7, ol8, almalinux9, fedora, sle12, sle15, sle16, ubuntu2204, ubuntu2404, debian11 and debian12.Not changed here: the OVAL check reads
/proc/mounts, where a bind mount shows the underlying device. So a bind mount that exists only at runtime and has nonodev(for example the Podman one, when its source file system is mounted withoutnodev) is still reported after remediation. Before this change it was reported as fixed, but the fstab entry left behind made the host unbootable.Fixes mount_option_nodev_nonroot_local_partitions writes bind mounts into /etc/fstab (DEVICE[PATH] source), host boots into emergency mode #15292
Review Hints:
bind_mount_not_in_fstab.fail.shshould pass on master too. The fstab part of the check accepts any/dev/\S+source, so it can't see the bad line. The scenario covers remediation with such a bind mount present and keeps that case in the test set.bind_mount_in_fstab_without_nodev.fail.shcovers the "mount point already in fstab" path. It should pass with and without this change, and fail if[PATH]sources were skipped unconditionally.ssg.jinjaand the rhel9 product environment, the same way the build renders it but without the container/bootc platform wrapper. It then ran as a non-root user on Ubuntu 22.04 (GNU bash 5.1.16, GNU sed and grep, util-linux 2.37.2) against temporary copies of/etc/fstab,/etc/mtaband/etc/security/namespace.conf, withfindmntreplaced by canned output andmount,mountpointandmkdirreplaced by logging stubs. On the same host, the realfindmnt --mtab --raw --evaluateprints sources such astmpfs[/snapd/ns], so the cannedDEVICE[PATH]records match what util-linux prints./on/dev/mapper/vg0-root, plusmount --bind /srv/b /srv/b): on master the remediation appends/dev/mapper/vg0-root[/srv/b] /srv/b xfs defaults,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota,nodev 0 0, the same line as in the issue. With this change,/etc/fstabis unchanged./homemissingnodev,/var/logwithnodev, a btrfs subvolume/opt(/dev/vdc1[/@opt],UUID=entry in fstab), a bind mount/srv/wwwlisted in fstab,/datamounted but not in fstab, gfs2, nfs4,/boot,/boot/efi, a polyinstantiated/tmp/tmp-inst,/srv/band/var/lib/containers/storage/overlay. Master appends the/srv/band overlay lines with[PATH]sources. With this change those two are skipped and nothing else changes:/home,/optand/srv/wwwgetnodevin their existing entries, and/datais appended as/dev/vdb1 /data ext4 defaults,relatime,nodev 0 0.[PATH]line. With this change, nothing is written.shellcheck -s bash -S warning --extended-analysis=false(the options of the<product>-bash-shellcheckctest) reports nothing on the rendered script before or after the change. At default severity, the findings are the same before and after.tests/ensure_bash_remediations_do_not_exit.py,tests/ensure_paths_are_short.py,utils/check_eof.pyandutils/check_smart_quotes.pypass.,bindadded to its options, soansible.posix.mountmay write a different broken entry. I haven't verified this. If it turns out to be true, it can be handled separately../build_product rhel9 --datastream-only, then./tests/automatus.py rule --libvirt qemu:///system <vm> --datastream build/ssg-rhel9-ds.xml mount_option_nodev_nonroot_local_partitions.