Skip to content

Bug: check reports boot problems when ESP grub.cfg is unreadable #14

@rocketman-code

Description

@rocketman-code

Current Behavior

Running atomic-rollback check as a non-root user on a default Fedora install
exits 1 and reports "System has boot problems.", even when the system is fully
bootable. The underlying cause is that the check cannot read
/boot/efi/EFI/fedora/grub.cfg, which is mounted root-readable only:

$ atomic-rollback check
atomic-rollback: checking system bootability

  Cannot determine how GRUB boots this system: cannot read ESP grub.cfg:
  Permission denied (os error 13). Ensure /boot/efi/EFI/fedora/grub.cfg
  exists and the root filesystem is mounted.

System has boot problems.
$ echo $?
1

Expected Behavior

A user running check without sufficient privilege to read the boot
configuration should be told the check could not be performed because of
insufficient access. That outcome is different from a result indicating the
system actually has boot problems. The two carry very different implications.
One means the user should re-run with appropriate privilege. The other means
the system may not boot.

Context

The current headline conclusion contradicts the detail line directly above it.
The detail correctly identifies a permission error, but the conclusion treats
it as a discovered boot problem. A user who trusts the tool's headline will
believe the system is unbootable when it is in fact fine, and may take
corrective action that itself risks the boot state.

The ESP mount is structurally root-readable-only on default Fedora installs
(fmask=0077,dmask=0077 in the live mount, mode 700 on /boot/efi), so any
non-root invocation of check reaches this path on every default install.

This is a result-classification issue, not a check-correctness issue. The
underlying check is operating as intended. The problem is that the code
flattens a "could not determine" outcome into a "found a problem" outcome.

Discovered on atomic-rollback-0.3.7-1.fc43 installed from the COPR.

Technical Details

Reproduction

On a default Fedora install with the ESP mounted at /boot/efi, as a
non-root user:

$ atomic-rollback check

Observe exit code 1 and the conflated "System has boot problems" message.

Relevant Code

In src/main.rs:144-156, the Command::Check handler treats every
BootStatus::Fail the same way:

println!("atomic-rollback: checking system bootability\n");
match check::verify_bootable(Path::new(&root)) {
    check::BootStatus::Pass => { println!("\nSystem is bootable."); }
    check::BootStatus::Warn => { ... }
    check::BootStatus::Fail(failures) => {
        for f in &failures { eprintln!("  {f}"); }
        println!("\nSystem has boot problems.");
        std::process::exit(1);
    }
}

In src/check.rs:51-58, verify_bootable collapses any
GrubContext::from_system error into BootStatus::Fail:

pub fn verify_bootable(root: &Path) -> BootStatus {
    let grub = match GrubContext::from_system(root) {
        Ok(g) => g,
        Err(e) => return BootStatus::Fail(vec![format!(
            "Cannot determine how GRUB boots this system: {e}. \
             Ensure {}/grub.cfg exists and the root filesystem is mounted.",
            P.esp_dir
        )]),
    };
    ...
}

In src/grub.rs:28-31, the io::Error from the failed read is converted to
String, which discards the ErrorKind:

let esp_cfg = root.join(&P.esp_dir[1..]).join("grub.cfg");
let content = fs::read_to_string(&esp_cfg)
    .map_err(|e| format!("cannot read ESP grub.cfg: {e}"))?;

Root Cause

GrubContext::from_system returns Result<_, String>, which discards the
io::ErrorKind of the underlying read failure at the point of conversion.
Downstream code in verify_bootable and main has no way to distinguish "I
could not read the configuration" from "I read the configuration and it
indicates a problem". Both flow through the same BootStatus::Fail branch and
produce the same headline message.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions