Skip to content

Commit

Permalink
rootmap: handle filesystems with LUKS integrity
Browse files Browse the repository at this point in the history
Systems where some filesystems were luks2-encrypted with 'integrity' option have special
crypt-integrity devices:
```
NAME                 FSTYPE      FSVER LABEL        UUID
vda
|-vda3               crypto_LUKS 2     crypt_bootfs f55add4a-1351-4699-9e61-32f33a68a031
| `-crypt_bootfs_dif
|   `-crypt_bootfs   ext4        1.0   boot         3d4ed0e4-40ba-4930-99ff-35d2be907ec3
|-vda4               crypto_LUKS 2     crypt_rootfs 7c5341bf-9616-4ce1-90dc-111b03379799
| `-crypt_rootfs_dif
|   `-crypt_rootfs   xfs               root         d0bc5f93-f2ac-42f3-8b16-27b0794266c5
```

So to get 'uuid' of such devices, we have to recursively go to the underlying block device.
crypt-integrity devices on the other hand should be skipped during 'rdcore rootmap'.

Signed-off-by: Nikita Dubrovskii <[email protected]>
  • Loading branch information
nikita-dubrovskii committed Jul 14, 2022
1 parent 0ad0423 commit 69b706d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 40 deletions.
56 changes: 32 additions & 24 deletions src/bin/rdcore/rootmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ fn device_to_kargs(root: &Mount, device: PathBuf) -> Result<Option<Vec<String>>>
if blktype.starts_with("raid") || blktype == "linear" {
Ok(Some(get_raid_kargs(&device)?))
} else if blktype == "crypt" {
Ok(Some(get_luks_kargs(root, &device)?))
if Disk::new(&device)?.is_luks_integrity()? {
Ok(None)
} else {
Ok(Some(get_luks_kargs(root, &device)?))
}
} else if blktype == "part" || blktype == "disk" || blktype == "mpath" {
Ok(None)
} else {
Expand Down Expand Up @@ -143,27 +147,14 @@ fn split_mdadm_line(line: &str) -> Result<(String, String)> {
}

fn get_luks_kargs(root: &Mount, device: &Path) -> Result<Vec<String>> {
// The LUKS UUID is a property of the backing block device of *this* block device, so we have
// to get its parent. This is a bit awkward because we're already iterating through parents, so
// theoretically we could re-use the same state here. But meh... this is easier to understand.
let deps = get_blkdev_deps(device)?;
match deps.len() {
0 => bail!("missing parent device for {}", device.display()),
1 => {
let uuid = get_luks_uuid(&deps[0])?;
let name = get_luks_name(device)?;
let mut kargs = vec![format!("rd.luks.name={}={}", uuid, name)];
if crypttab_device_has_netdev(root, &name)? {
kargs.push("rd.neednet=1".into());
kargs.push("rd.luks.options=_netdev".into());
}
Ok(kargs)
}
_ => bail!(
"found multiple parent devices for crypt device {}",
device.display()
),
let uuid = get_luks_uuid(device)?;
let name = get_luks_name(device)?;
let mut kargs = vec![format!("rd.luks.name={}={}", uuid, name)];
if crypttab_device_has_netdev(root, &name)? {
kargs.push("rd.neednet=1".into());
kargs.push("rd.luks.options=_netdev".into());
}
Ok(kargs)
}

// crypttab is the source of truth for whether an encrypted block device requires networking.
Expand Down Expand Up @@ -216,9 +207,26 @@ fn get_luks_name(device: &Path) -> Result<String> {
}

fn get_luks_uuid(device: &Path) -> Result<String> {
Ok(runcmd_output!("cryptsetup", "luksUUID", device)?
.trim()
.into())
// The LUKS UUID is a property of the backing block device of *this* block device, so we have
// to get its parent. This is a bit awkward because we're already iterating through parents, so
// theoretically we could re-use the same state here. But meh... this is easier to understand and
// handle crypt-integrity case
let deps = get_blkdev_deps(device)?;
match deps.as_slice() {
[] => bail!("missing parent device for {}", device.display()),
[device] => {
if Disk::new(&device)?.is_dm_device() {
return get_luks_uuid(device);
}
Ok(runcmd_output!("cryptsetup", "luksUUID", device)?
.trim()
.into())
}
_ => bail!(
"found multiple parent devices for crypt device {}",
device.display()
),
}
}

pub fn bind_boot(config: BindBootConfig) -> Result<()> {
Expand Down
44 changes: 28 additions & 16 deletions src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,23 @@ use crate::{runcmd, runcmd_output};

#[derive(Debug)]
pub struct Disk {
pub path: String,
path: String,
}

impl Disk {
pub fn new(path: &str) -> Result<Self> {
let canon_path = Path::new(path)
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
let path = path.as_ref();
let canon_path = path
.canonicalize()
.with_context(|| format!("canonicalizing {}", path))?;
.with_context(|| format!("canonicalizing {}", path.display()))?;

let canon_path = canon_path
.to_str()
.with_context(|| {
format!(
"path {} canonicalized from {} is not UTF-8",
canon_path.display(),
path
path.display()
)
})?
.to_string();
Expand Down Expand Up @@ -156,7 +157,7 @@ impl Disk {
// Our investigation found nothing. If the device is expected to be
// partitionable but reread failed, we evidently missed something,
// so error out for safety
if !self.is_dm_device()? {
if !self.is_dm_device() {
return rereadpt_result;
}

Expand All @@ -166,22 +167,33 @@ impl Disk {
/// Get a handle to the set of device nodes for individual partitions
/// of the device.
pub fn get_partition_table(&self) -> Result<Box<dyn PartTable>> {
if self.is_dm_device()? {
if self.is_dm_device() {
Ok(Box::new(PartTableKpartx::new(&self.path)?))
} else {
Ok(Box::new(PartTableKernel::new(&self.path)?))
}
}

fn is_dm_device(&self) -> Result<bool> {
let canon_path = Path::new(&self.path)
.canonicalize()
.with_context(|| format!("canonicalizing {}", &self.path))?;
// convert back to &str because .starts_with on a Path doesn't mean the same thing
let canon_path = canon_path
.to_str()
.with_context(|| format!("path {} is not UTF-8", canon_path.display()))?;
Ok(canon_path.starts_with("/dev/dm-"))
pub fn is_dm_device(&self) -> bool {
self.path.starts_with("/dev/dm-")
}

pub fn is_luks_integrity(&self) -> Result<bool> {
if !self.is_dm_device() {
return Ok(false);
}
Ok(runcmd_output!(
"dmsetup",
"info",
"--columns",
"--noheadings",
"-o",
"uuid",
&self.path
)
.with_context(|| format!("checking if device {} is type LUKS integrity", self.path))?
.trim()
.starts_with("CRYPT-INTEGRITY-"))
}
}

Expand Down

0 comments on commit 69b706d

Please sign in to comment.