Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bbfdc66
Add encryption support in V2 crypt handle
jbaublitz Jul 16, 2024
27e3681
Add Engine interface for encrypting pool
jbaublitz Jul 16, 2024
b640659
Add D-Bus interface for encrypting pool
jbaublitz Jul 16, 2024
9857136
Unit test for online encryption
jbaublitz Jan 20, 2025
a330beb
Add reencryption support in both crypt handles
jbaublitz Sep 17, 2024
9e95298
Add Engine interface for reencrypting pool
jbaublitz Sep 17, 2024
d596f8a
Add D-Bus interface for reencrypting pool
jbaublitz Sep 17, 2024
8c45a9f
Unit test for online reencryption
jbaublitz Feb 4, 2025
42c114b
Add decryption support in V2 crypt handle
jbaublitz Jan 22, 2025
b531e67
Add Engine interface for decrypting pool
jbaublitz Jan 30, 2025
3e07d92
Add D-Bus interface for decrypting pool
jbaublitz Feb 3, 2025
0b58661
Unit test for online decryption
jbaublitz Feb 12, 2025
e17d464
Perform rollback for setup operations in reencryption
jbaublitz Feb 24, 2025
5098d07
Add last reencrypted timestamp to engine
jbaublitz Apr 29, 2025
8703183
Update timestamp on successful decryption and reencryption operations
jbaublitz May 1, 2025
21865ce
Add reencryption timestamp API to engine
jbaublitz May 1, 2025
a9bcb93
Add property to indicate when the pool was last reencrypted
jbaublitz May 6, 2025
5ee5e78
Add change signal for last encrypted timestamp
jbaublitz May 6, 2025
ababe1a
Refactor reencryption to use a read lock during operation
jbaublitz Jul 28, 2025
5858347
Add upgrade and downgrade to lock and use in reencryption
jbaublitz Aug 7, 2025
f446b7b
Refactor encryption to use a read lock during operation
jbaublitz Aug 7, 2025
4d6f48d
Refactor decryption to use a read lock during operation
jbaublitz Aug 15, 2025
9fafd3f
Add prechecks for all key description-related operations
jbaublitz Jan 20, 2026
f96864a
Allow parallel encryption, reencryption and decryption operations
jbaublitz Jan 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ jobs:
dnf install -y
asciidoc
clang
cryptsetup
cryptsetup-devel
dbus-daemon
dbus-tools
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ jobs:
apt-get install -y
asciidoc
clang
cryptsetup
curl
git
libblkid-dev
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/valgrind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
dnf install -y
asciidoc
clang
cryptsetup
cryptsetup-devel
curl
device-mapper-persistent-data
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ version = "1.2.3"
optional = true

[dependencies.chrono]
version = "0.4.20"
version = "0.4.31"
optional = true
default-features = false
features = ["clock", "std"]
Expand Down
249 changes: 249 additions & 0 deletions src/dbus/pool/pool_3_9/methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::sync::Arc;

use futures::executor::block_on;
use serde_json::from_str;
use tokio::sync::RwLock;
use zbus::Connection;

use crate::{
dbus::{
consts::OK_STRING,
manager::Manager,
types::DbusErrorEnum,
util::{
engine_to_dbus_err_tuple, send_clevis_info_signal, send_encrypted_signal,
send_keyring_signal, send_last_reencrypted_signal, tuple_to_option,
},
},
engine::{
CreateAction, DeleteAction, EncryptedDevice, Engine, InputEncryptionInfo, KeyDescription,
Lockable, PoolIdentifier, PoolUuid,
},
stratis::StratisError,
};

pub async fn encrypt_pool_method(
engine: &Arc<dyn Engine>,
connection: &Arc<Connection>,
manager: &Lockable<Arc<RwLock<Manager>>>,
pool_uuid: PoolUuid,
key_descs: Vec<((bool, u32), KeyDescription)>,
clevis_infos: Vec<((bool, u32), &str, &str)>,
) -> (bool, u16, String) {
let default_return = false;

let key_descs_parsed =
match key_descs
.into_iter()
.try_fold(Vec::new(), |mut vec, (ts_opt, kd)| {
let token_slot = tuple_to_option(ts_opt);
vec.push((token_slot, kd));
Ok(vec)
}) {
Ok(kds) => kds,
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return (default_return, rc, rs);
}
};

let clevis_infos_parsed =
match clevis_infos
.into_iter()
.try_fold(Vec::new(), |mut vec, (ts_opt, pin, json_str)| {
let token_slot = tuple_to_option(ts_opt);
let json = from_str(json_str)?;
vec.push((token_slot, (pin.to_owned(), json)));
Ok(vec)
}) {
Ok(cis) => cis,
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return (default_return, rc, rs);
}
};

let iei = match InputEncryptionInfo::new(key_descs_parsed, clevis_infos_parsed) {
Ok(Some(info)) => info,
Ok(None) => {
return (
default_return,
DbusErrorEnum::ERROR as u16,
"No unlock methods provided".to_string(),
);
}
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return (default_return, rc, rs);
}
};

let guard_res = engine
.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))
.await
.ok_or_else(|| StratisError::Msg(format!("No pool associated with uuid {pool_uuid}")));
let cloned_engine = Arc::clone(engine);
match tokio::task::spawn_blocking(move || {
let mut guard = guard_res?;

handle_action!(guard
.start_encrypt_pool(pool_uuid, &iei)
.and_then(|action| match action {
CreateAction::Identity => Ok(CreateAction::Identity),
CreateAction::Created((sector_size, key_info)) => {
let guard = guard.downgrade();
guard
.do_encrypt_pool(pool_uuid, sector_size, key_info)
.map(|_| guard)
.and_then(|guard| {
let mut guard = block_on(cloned_engine.upgrade_pool(guard));
let (name, _, _) = guard.as_mut_tuple();
guard.finish_encrypt_pool(&name, pool_uuid)
})
.map(|_| CreateAction::Created(EncryptedDevice(pool_uuid)))
}
}))
})
.await
{
Ok(Ok(CreateAction::Created(_))) => {
match manager.read().await.pool_get_path(&pool_uuid) {
Some(p) => {
send_keyring_signal(connection, &p.as_ref(), true).await;
send_clevis_info_signal(connection, &p.as_ref(), true).await;
send_encrypted_signal(connection, &p.as_ref()).await;
}
None => {
warn!("No pool path associated with UUID {pool_uuid}; failed to send encryption related signals");
}
}
(true, DbusErrorEnum::OK as u16, OK_STRING.to_string())
}
Ok(Ok(CreateAction::Identity)) => (false, DbusErrorEnum::OK as u16, OK_STRING.to_string()),
Ok(Err(e)) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
(default_return, rc, rs)
}
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&StratisError::from(e));
(default_return, rc, rs)
}
}
}

pub async fn reencrypt_pool_method(
engine: &Arc<dyn Engine>,
connection: &Arc<Connection>,
manager: &Lockable<Arc<RwLock<Manager>>>,
pool_uuid: PoolUuid,
) -> (bool, u16, String) {
let default_return = false;

let guard_res = engine
.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))
.await
.ok_or_else(|| StratisError::Msg(format!("No pool associated with uuid {pool_uuid}")));
let cloned_engine = Arc::clone(engine);
match tokio::task::spawn_blocking(move || {
let mut guard = guard_res?;

let (name, _, _) = guard.as_mut_tuple();

let result = guard.start_reencrypt_pool();
let result = result.and_then(|key_info| {
let guard = guard.downgrade();
let result = guard.do_reencrypt_pool(pool_uuid, key_info);
result.map(|inner| (guard, inner))
});
let result = result.and_then(|(guard, _)| {
let mut guard = block_on(cloned_engine.upgrade_pool(guard));
guard.finish_reencrypt_pool(&name, pool_uuid)
});
handle_action!(result)
})
.await
{
Ok(Ok(_)) => {
match manager.read().await.pool_get_path(&pool_uuid) {
Some(p) => {
send_last_reencrypted_signal(connection, &p.as_ref()).await;
}
None => {
warn!("No pool path associated with UUID {pool_uuid}; failed to send encryption related signals");
}
}
(true, DbusErrorEnum::OK as u16, OK_STRING.to_string())
}
Ok(Err(e)) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
(default_return, rc, rs)
}
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&StratisError::from(e));
(default_return, rc, rs)
}
}
}

pub async fn decrypt_pool_method(
engine: &Arc<dyn Engine>,
connection: &Arc<Connection>,
manager: &Lockable<Arc<RwLock<Manager>>>,
pool_uuid: PoolUuid,
) -> (bool, u16, String) {
let default_return = false;

let guard_res = engine
.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))
.await
.ok_or_else(|| StratisError::Msg(format!("No pool associated with uuid {pool_uuid}")));
let cloned_engine = Arc::clone(engine);
match tokio::task::spawn_blocking(move || {
let mut guard = guard_res?;

handle_action!(match guard.decrypt_pool_idem_check(pool_uuid) {
Ok(DeleteAction::Identity) => Ok(DeleteAction::Identity),
Ok(DeleteAction::Deleted(d)) => {
let guard = guard.downgrade();
guard
.do_decrypt_pool(pool_uuid)
.and_then(|_| {
let mut guard = block_on(cloned_engine.upgrade_pool(guard));
let (name, _, _) = guard.as_mut_tuple();
guard.finish_decrypt_pool(pool_uuid, &name)
})
.map(|_| DeleteAction::Deleted(d))
}
Err(e) => Err(e),
})
})
.await
{
Ok(Ok(DeleteAction::Deleted(_))) => {
match manager.read().await.pool_get_path(&pool_uuid) {
Some(p) => {
send_keyring_signal(connection, &p.as_ref(), true).await;
send_clevis_info_signal(connection, &p.as_ref(), true).await;
send_encrypted_signal(connection, &p.as_ref()).await;
}
None => {
warn!("No pool path associated with UUID {pool_uuid}; failed to send encryption related signals");
}
}
(true, DbusErrorEnum::OK as u16, OK_STRING.to_string())
}
Ok(Ok(DeleteAction::Identity)) => (false, DbusErrorEnum::OK as u16, OK_STRING.to_string()),
Ok(Err(e)) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
(default_return, rc, rs)
}
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&StratisError::from(e));
(default_return, rc, rs)
}
}
}
37 changes: 36 additions & 1 deletion src/dbus/pool/pool_3_9/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ use crate::{
stratis::StratisResult,
};

mod methods;
mod props;

pub use methods::{decrypt_pool_method, encrypt_pool_method, reencrypt_pool_method};
pub use props::last_reencrypted_timestamp_prop;

pub struct PoolR9 {
connection: Arc<Connection>,
engine: Arc<dyn Engine>,
Expand Down Expand Up @@ -327,6 +333,30 @@ impl PoolR9 {
filesystem_metadata_method(&self.engine, self.uuid, fs_name, current).await
}

async fn encrypt_pool(
&self,
key_descs: Vec<((bool, u32), KeyDescription)>,
clevis_infos: Vec<((bool, u32), &str, &str)>,
) -> (bool, u16, String) {
encrypt_pool_method(
&self.engine,
&self.connection,
&self.manager,
self.uuid,
key_descs,
clevis_infos,
)
.await
}

async fn reencrypt_pool(&self) -> (bool, u16, String) {
reencrypt_pool_method(&self.engine, &self.connection, &self.manager, self.uuid).await
}

async fn decrypt_pool(&self) -> (bool, u16, String) {
decrypt_pool_method(&self.engine, &self.connection, &self.manager, self.uuid).await
}

#[zbus(property(emits_changed_signal = "const"))]
fn uuid(&self) -> String {
self.uuid.simple().to_string()
Expand All @@ -337,7 +367,7 @@ impl PoolR9 {
pool_prop(&self.engine, self.uuid, name_prop).await
}

#[zbus(property(emits_changed_signal = "const"))]
#[zbus(property(emits_changed_signal = "true"))]
async fn encrypted(&self) -> Result<bool, Error> {
pool_prop(&self.engine, self.uuid, encrypted_prop).await
}
Expand Down Expand Up @@ -434,4 +464,9 @@ impl PoolR9 {
async fn metadata_version(&self) -> Result<u64, Error> {
pool_prop(&self.engine, self.uuid, metadata_version_prop).await
}

#[zbus(property(emits_changed_signal = "true"))]
async fn last_reencrypted_timestamp(&self) -> Result<(bool, String), Error> {
pool_prop(&self.engine, self.uuid, last_reencrypted_timestamp_prop).await
}
}
21 changes: 21 additions & 0 deletions src/dbus/pool/pool_3_9/props.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use chrono::SecondsFormat;

use crate::{
dbus::util::option_to_tuple,
engine::{Pool, PoolUuid, SomeLockReadGuard},
};

pub fn last_reencrypted_timestamp_prop(
guard: SomeLockReadGuard<PoolUuid, dyn Pool>,
) -> (bool, String) {
option_to_tuple(
guard
.last_reencrypt()
.map(|t| t.to_rfc3339_opts(SecondsFormat::Secs, true)),
String::new(),
)
}
Loading
Loading