Skip to content

Commit 2bc942c

Browse files
committed
feature gate Crucible-specific boot digest code
1 parent bc489dd commit 2bc942c

File tree

5 files changed

+83
-40
lines changed

5 files changed

+83
-40
lines changed

.github/workflows/rust.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,15 @@ jobs:
5050
run: cargo build -p propolis-mock-server --verbose
5151
- name: Test Libraries
5252
run: cargo test --lib --verbose
53+
# Build and test propolis-the-library on its own; `cargo test --lib` as used
54+
# above builds the entire workspace, meaning propolis-server default features
55+
# are used to build and run propolis-lib tests. Instead, this check uses
56+
# `cargo build -p propolis` to only operate with that one crate.
57+
build-and-test-propolis-lib:
58+
runs-on: ubuntu-latest
59+
steps:
60+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
61+
- name: Build
62+
run: cargo build -p propolis --verbose
63+
- name: Test Propolis-lib
64+
run: cargo test -p propolis --verbose

bin/propolis-server/src/lib/initializer.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ impl MachineInitializer<'_> {
733733
settings.order.first()
734734
});
735735

736-
let crucible_volume = if let Some(entry) = boot_disk_entry {
736+
let boot_backend = if let Some(entry) = boot_disk_entry {
737737
let disk_dev =
738738
self.spec.disks.get(&entry.device_id).ok_or_else(|| {
739739
MachineInitError::BootOrderEntryWithoutDevice(
@@ -758,7 +758,9 @@ impl MachineInitializer<'_> {
758758
block_backend.as_any().downcast_ref::<block::CrucibleBackend>()
759759
{
760760
if backend.is_read_only() {
761-
Some(backend.clone_volume())
761+
Some(attestation::boot_digest::Backend::Crucible(
762+
backend.clone_volume(),
763+
))
762764
} else {
763765
// Disk must be read-only to be used for attestation.
764766
slog::info!(
@@ -779,7 +781,7 @@ impl MachineInitializer<'_> {
779781
None
780782
};
781783

782-
vm_rot.prepare_instance_conf(uuid, crucible_volume);
784+
vm_rot.prepare_instance_conf(uuid, boot_backend);
783785

784786
Ok(())
785787
}
File renamed without changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use vm_attest::Measurement;
6+
7+
use anyhow::Result;
8+
use slog::Logger;
9+
10+
#[cfg(feature = "crucible")]
11+
mod crucible;
12+
13+
#[derive(Debug)]
14+
pub enum Backend {
15+
#[cfg(feature = "crucible")]
16+
Crucible(::crucible::Volume),
17+
}
18+
19+
pub async fn compute(backend: Backend, log: &Logger) -> Result<Measurement> {
20+
slog::info!(log, "computing disk digest for {backend:?}");
21+
22+
match backend {
23+
#[cfg(feature = "crucible")]
24+
Backend::Crucible(vol) => {
25+
// TODO: load-bearing sleep: we have a Crucible volume, but we can
26+
// be here and chomping at the bit to get a digest calculation
27+
// started well before the volume has been activated; in
28+
// `propolis-server` we need to wait for at least a subsequent
29+
// instance start. Similar to the scrub task for Crucible disks,
30+
// delay some number of seconds in the hopes that activation is done
31+
// promptly.
32+
//
33+
// This should be replaced by awaiting for some kind of actual
34+
// "activated" signal.
35+
//
36+
// see #1078
37+
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
38+
39+
crucible::boot_disk_digest(vol, log).await
40+
}
41+
}
42+
}

lib/propolis/src/attestation/server.rs

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use dice_verifier::Attest;
1818

1919
use vm_attest::VmInstanceConf;
2020

21-
use crate::attestation::ATTESTATION_ADDR;
21+
use crate::attestation::{boot_digest, ATTESTATION_ADDR};
2222

2323
#[derive(Copy, Clone)]
2424
pub struct AttestationServerConfig {
@@ -58,49 +58,36 @@ pub struct AttestationSockInit {
5858
log: slog::Logger,
5959
vm_conf_send: oneshot::Sender<VmInstanceConf>,
6060
uuid: uuid::Uuid,
61-
volume_ref: Option<crucible::Volume>,
61+
boot_backend_ref: Option<boot_digest::Backend>,
6262
}
6363

6464
impl AttestationSockInit {
6565
/// Do any any remaining work of collecting VM RoT measurements in support
6666
/// of this VM's attestation server.
6767
pub async fn run(self) {
68-
let AttestationSockInit { log, vm_conf_send, uuid, volume_ref } = self;
68+
let AttestationSockInit { log, vm_conf_send, uuid, boot_backend_ref } =
69+
self;
6970

7071
let mut vm_conf = vm_attest::VmInstanceConf { uuid, boot_digest: None };
7172

72-
if let Some(volume) = volume_ref {
73-
// TODO: load-bearing sleep: we have a Crucible volume, but we can
74-
// be here and chomping at the bit to get a digest calculation
75-
// started well before the volume has been activated; in
76-
// `propolis-server` we need to wait for at least a subsequent
77-
// instance start. Similar to the scrub task for Crucible disks,
78-
// delay some number of seconds in the hopes that activation is done
79-
// promptly.
80-
//
81-
// This should be replaced by awaiting for some kind of actual
82-
// "activated" signal.
83-
//
84-
// see #1078
85-
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
86-
87-
let boot_digest =
88-
match crate::attestation::boot_digest::boot_disk_digest(
89-
volume, &log,
90-
)
91-
.await
92-
{
93-
Ok(digest) => digest,
94-
Err(e) => {
95-
// a panic here is unfortunate, but helps us debug for
96-
// now; if the digest calculation fails it may be some
97-
// retryable issue that a guest OS would survive. but
98-
// panicking here means we've stopped Propolis at the
99-
// actual error, rather than noticing the
100-
// `vm_conf_sender` having dropped elsewhere.
101-
panic!("failed to compute boot disk digest: {e:?}");
102-
}
103-
};
73+
if let Some(digest_backend) = boot_backend_ref {
74+
let boot_digest = match crate::attestation::boot_digest::compute(
75+
digest_backend,
76+
&log,
77+
)
78+
.await
79+
{
80+
Ok(digest) => digest,
81+
Err(e) => {
82+
// a panic here is unfortunate, but helps us debug for
83+
// now; if the digest calculation fails it may be some
84+
// retryable issue that a guest OS would survive. but
85+
// panicking here means we've stopped Propolis at the
86+
// actual error, rather than noticing the
87+
// `vm_conf_sender` having dropped elsewhere.
88+
panic!("failed to compute boot disk digest: {e:?}");
89+
}
90+
};
10491

10592
vm_conf.boot_digest = Some(boot_digest);
10693
} else {
@@ -287,7 +274,7 @@ impl AttestationSock {
287274
pub fn prepare_instance_conf(
288275
&mut self,
289276
uuid: uuid::Uuid,
290-
volume_ref: Option<crucible::Volume>,
277+
boot_backend_ref: Option<boot_digest::Backend>,
291278
) {
292279
let init_state = std::mem::replace(
293280
&mut self.init_state,
@@ -305,7 +292,7 @@ impl AttestationSock {
305292
let init = AttestationSockInit {
306293
log: self.log.clone(),
307294
uuid,
308-
volume_ref,
295+
boot_backend_ref,
309296
vm_conf_send,
310297
};
311298
let init_task = tokio::spawn(init.run());

0 commit comments

Comments
 (0)