fix(vfs): V-03 — raii memory lock guard prevents premature memory unlock on fs clone

This commit is contained in:
2026-09-19 09:10:35 +02:00
parent f9733dfc73
commit 52859623c2
3 changed files with 136 additions and 33 deletions
+65
View File
@@ -154,3 +154,68 @@ fn test_mount_security_multi_auth_and_no_token_in_url() {
"Saubere URI darf kein Token enthalten"
);
}
#[tokio::test]
async fn test_vfs_memory_lock_retention_on_clone_v03() {
use dav_server::davpath::DavPath;
use dav_server::fs::{DavFileSystem, ReadDirMeta};
use futures_util::StreamExt;
use sanctum::vfs::SanctumFs;
let temp_dir = std::env::temp_dir();
let container_path: PathBuf =
temp_dir.join(format!("test_v03_lock_{}.sanctum", std::process::id()));
if container_path.exists() {
let _ = std::fs::remove_file(&container_path);
}
let salt = generate_salt();
let kdf_params = KdfParams {
memory_cost: MIN_MEMORY_COST_KIB,
time_cost: MIN_TIME_COST,
parallelism: 1,
};
let kek = derive_kek("TestPassV03!", &salt, &kdf_params).unwrap();
let dek = generate_dek();
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
let db = Database::open(&container_path).unwrap();
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag)
.unwrap();
// 1. Initialisiere SanctumFs
let fs = SanctumFs::new(db.clone(), dek, sanctum::crypto::FORMAT_VERSION);
assert_eq!(
fs.dek_strong_count(),
1,
"Anfangs muss genau 1 Referenz auf den verriegelten DEK existieren"
);
// 2. Klone SanctumFs (wie bei jeder HTTP/WebDAV-Anfrage im Server)
let fs_clone = fs.clone();
assert_eq!(
fs.dek_strong_count(),
2,
"Nach dem Klonen müssen 2 Referenzen existieren"
);
// 3. Droppe den Klon
drop(fs_clone);
// 4. V-03: Der Refcount muss nun wieder 1 sein. Der Speicherbereich darf NICHT
// vorzeitig über Drop eines Klons entriegelt worden sein!
assert_eq!(
fs.dek_strong_count(),
1,
"Nach Drop des Klons muss genau 1 Referenz erhalten bleiben"
);
// Verifiziere funktionale Nutzbarkeit nach Drop des Klons
let root_path = DavPath::new("/").unwrap();
let mut entries = fs.read_dir(&root_path, ReadDirMeta::None).await.unwrap();
assert!(entries.next().await.is_none());
drop(fs);
let _ = std::fs::remove_file(&container_path);
}