Skip to content

Commit

Permalink
install/baseline: use sfdisk, not lsblk
Browse files Browse the repository at this point in the history
I think this may also help with the install flake we've been
seeing where we somehow get the partitions mixed up.

- Use `sfdisk` in the baseline install because it's what
  we're switching to using anyways later on
- Add some verification at least for the root and EFI partitions
  that we read back the expected type
  • Loading branch information
cgwalters committed Jul 17, 2024
1 parent e4def13 commit f735c53
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 25 deletions.
15 changes: 15 additions & 0 deletions lib/src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ impl PartitionTable {
pub(crate) fn path(&self) -> &Utf8Path {
self.device.as_str().into()
}

// Find the partition with the given offset (starting at 1)
pub(crate) fn find_partno<'a>(&'a self, partno: u32) -> Result<&'a Partition> {
let r = self
.partitions
.get(partno.checked_sub(1).expect("1 based partition offset") as usize)
.ok_or_else(|| anyhow::anyhow!("Missing partition for index {partno}"))?;
Ok(r)
}
}

impl Partition {
pub(crate) fn path(&self) -> &Utf8Path {
self.node.as_str().into()
}
}

#[context("Listing partitions of {dev}")]
Expand Down
49 changes: 24 additions & 25 deletions lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,24 +328,18 @@ pub(crate) fn install_create_rootfs(
// we're targeting, but this is a simple coarse hammer.
crate::blockdev::udev_settle()?;

// Now inspect the partitioned device again so we can find the names of the child devices.
let device_partitions = crate::blockdev::list_dev(&devpath)?
.children
.ok_or_else(|| anyhow::anyhow!("Failed to find children after partitioning"))?;
// Given a partition number, return the path to its device.
let findpart = |idx: u32| -> Result<String> {
// checked_sub is here because our partition numbers start at 1, but the vec starts at 0
let devpath = device_partitions
.get(idx.checked_sub(1).unwrap() as usize)
.ok_or_else(|| anyhow::anyhow!("Missing partition for index {idx}"))?
.path();
Ok(devpath)
};

let base_rootdev = findpart(rootpn)?;
// Re-read what we wrote into structured information
let base_partitions = &crate::blockdev::partitions_of(&devpath)?;

let root_partition = base_partitions.find_partno(rootpn)?;
if root_partition.parttype.as_str() != LINUX_PARTTYPE {
anyhow::bail!(
"root partition {partno} has type {}; expected {LINUX_PARTTYPE}",
root_partition.parttype.as_str()
);
}
let (rootdev, root_blockdev_kargs) = match block_setup {
BlockSetup::Direct => (base_rootdev, None),
BlockSetup::Direct => (root_partition.node.to_owned(), None),
BlockSetup::Tpm2Luks => {
let uuid = uuid::Uuid::new_v4().to_string();
// This will be replaced via --wipe-slot=all when binding to tpm below
Expand All @@ -356,21 +350,23 @@ pub(crate) fn install_create_rootfs(
let tmp_keyfile = tmp_keyfile.path();
let dummy_passphrase_input = Some(dummy_passphrase.as_bytes());

let root_devpath = root_partition.path();

Task::new("Initializing LUKS for root", "cryptsetup")
.args(["luksFormat", "--uuid", uuid.as_str(), "--key-file"])
.args([tmp_keyfile])
.args([base_rootdev.as_str()])
.args([root_devpath])
.run()?;
// The --wipe-slot=all removes our temporary passphrase, and binds to the local TPM device.
// We also use .verbose() here as the details are important/notable.
Task::new("Enrolling root device with TPM", "systemd-cryptenroll")
.args(["--wipe-slot=all", "--tpm2-device=auto", "--unlock-key-file"])
.args([tmp_keyfile])
.args([base_rootdev.as_str()])
.args([root_devpath])
.verbose()
.run_with_stdin_buf(dummy_passphrase_input)?;
Task::new("Opening root LUKS device", "cryptsetup")
.args(["luksOpen", base_rootdev.as_str(), luks_name])
.args(["luksOpen", root_devpath.as_str(), luks_name])
.run()?;
let rootdev = format!("/dev/mapper/{luks_name}");
let kargs = vec![
Expand All @@ -383,12 +379,15 @@ pub(crate) fn install_create_rootfs(

// Initialize the /boot filesystem
let bootdev = if let Some(bootpn) = boot_partno {
Some(findpart(bootpn)?)
Some(base_partitions.find_partno(bootpn)?)
} else {
None
};
let boot_uuid = if let Some(bootdev) = bootdev.as_deref() {
Some(mkfs(bootdev, root_filesystem, "boot", []).context("Initializing /boot")?)
Some(
mkfs(bootdev.node.as_str(), root_filesystem, "boot", [])
.context("Initializing /boot")?,
)
} else {
None
};
Expand Down Expand Up @@ -419,22 +418,22 @@ pub(crate) fn install_create_rootfs(
// Create the underlying mount point directory, which should be labeled
crate::lsm::ensure_dir_labeled(&target_rootfs, "boot", None, 0o755.into(), sepolicy)?;
if let Some(bootdev) = bootdev.as_deref() {
mount::mount(bootdev, &bootfs)?;
mount::mount(bootdev.node.as_str(), &bootfs)?;
}
// And we want to label the root mount of /boot
crate::lsm::ensure_dir_labeled(&target_rootfs, "boot", None, 0o755.into(), sepolicy)?;

// Create the EFI system partition, if applicable
if let Some(esp_partno) = esp_partno {
let espdev = &findpart(esp_partno)?;
let espdev = base_partitions.find_partno(esp_partno)?;
Task::new("Creating ESP filesystem", "mkfs.fat")
.args([espdev.as_str(), "-n", "EFI-SYSTEM"])
.args([espdev.node.as_str(), "-n", "EFI-SYSTEM"])
.verbose()
.quiet_output()
.run()?;
let efifs_path = bootfs.join(crate::bootloader::EFI_DIR);
std::fs::create_dir(&efifs_path).context("Creating efi dir")?;
mount::mount(espdev, &efifs_path)?;
mount::mount(espdev.node.as_str(), &efifs_path)?;
}

let luks_device = match block_setup {
Expand Down

0 comments on commit f735c53

Please sign in to comment.