fix(vfs): V-03 — raii memory lock guard prevents premature memory unlock on fs clone
This commit is contained in:
+52
-27
@@ -94,6 +94,42 @@ impl DavDirEntry for SanctumDirEntry {
|
||||
}
|
||||
}
|
||||
|
||||
/// RAII-Guard für im physischen RAM verriegelte Schlüssel (VirtualLock / mlock).
|
||||
/// Entriegelt den Speicherbereich via VirtualUnlock / munlock erst beim Drop der letzten verbleibenden Referenz (V-03).
|
||||
#[derive(Debug)]
|
||||
pub struct MemoryLockGuard(Zeroizing<[u8; 32]>);
|
||||
|
||||
impl MemoryLockGuard {
|
||||
pub fn new(key: Zeroizing<[u8; 32]>) -> Self {
|
||||
crate::windows::lock_memory(key.as_ptr(), 32);
|
||||
Self(key)
|
||||
}
|
||||
|
||||
pub fn key(&self) -> &Zeroizing<[u8; 32]> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for MemoryLockGuard {
|
||||
type Target = Zeroizing<[u8; 32]>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for MemoryLockGuard {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemoryLockGuard {
|
||||
fn drop(&mut self) {
|
||||
crate::windows::unlock_memory(self.0.as_ptr(), 32);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Datei-Handle mit Streaming & Chunk-Pufferung
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -103,7 +139,7 @@ pub struct SanctumFile {
|
||||
file_size: u64,
|
||||
cursor: u64,
|
||||
db: Database,
|
||||
dek: Arc<Zeroizing<[u8; 32]>>,
|
||||
dek: Arc<MemoryLockGuard>,
|
||||
meta: SanctumMetaData,
|
||||
// (chunk_index, decrypted_payload, is_dirty)
|
||||
cached_chunk: Option<(u32, Vec<u8>, bool)>,
|
||||
@@ -126,7 +162,7 @@ impl SanctumFile {
|
||||
pub fn new(
|
||||
node: NodeRecord,
|
||||
db: Database,
|
||||
dek: Arc<Zeroizing<[u8; 32]>>,
|
||||
dek: Arc<MemoryLockGuard>,
|
||||
format_version: u32,
|
||||
last_activity: Arc<AtomicU64>,
|
||||
append: bool,
|
||||
@@ -445,9 +481,9 @@ impl DavFile for SanctumFile {
|
||||
#[derive(Clone)]
|
||||
pub struct SanctumFs {
|
||||
db: Database,
|
||||
dek: Arc<Zeroizing<[u8; 32]>>,
|
||||
dek: Arc<MemoryLockGuard>,
|
||||
#[allow(dead_code)]
|
||||
carrier_dek: Option<Arc<Zeroizing<[u8; 32]>>>,
|
||||
carrier_dek: Option<Arc<MemoryLockGuard>>,
|
||||
carrier_node_id: Option<i64>,
|
||||
carrier_fs: Option<CarrierFs>,
|
||||
format_version: u32,
|
||||
@@ -493,10 +529,10 @@ impl SanctumFs {
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
let dek_arc = Arc::new(dek);
|
||||
let carrier_dek_arc = carrier_dek.map(Arc::new);
|
||||
let dek_guard = Arc::new(MemoryLockGuard::new(dek));
|
||||
let carrier_dek_guard = carrier_dek.map(|k| Arc::new(MemoryLockGuard::new(k)));
|
||||
|
||||
let db = db.with_session(vault_id, (*dek_arc).clone());
|
||||
let db = db.with_session(vault_id, (*dek_guard.key()).clone());
|
||||
|
||||
// Im Decoy-Vault (Slot 0): Stelle sicher, dass carrier_node_id stets bekannt ist,
|
||||
// um die Trägerdatei vor versehentlichem Löschen oder Überschreiben zu schützen.
|
||||
@@ -509,12 +545,12 @@ impl SanctumFs {
|
||||
});
|
||||
|
||||
let carrier_fs = if vault_id == 1 {
|
||||
if let (Some(ref c_dek), Some(c_nid)) = (&carrier_dek_arc, carrier_node_id) {
|
||||
if let (Some(ref c_dek), Some(c_nid)) = (&carrier_dek_guard, carrier_node_id) {
|
||||
match CarrierFs::load(
|
||||
db.clone(),
|
||||
c_nid,
|
||||
c_dek.clone(),
|
||||
dek_arc.clone(),
|
||||
Arc::new((*c_dek.key()).clone()),
|
||||
Arc::new((*dek_guard.key()).clone()),
|
||||
format_version,
|
||||
anti_leak,
|
||||
) {
|
||||
@@ -531,16 +567,10 @@ impl SanctumFs {
|
||||
None
|
||||
};
|
||||
|
||||
// Forensischer RAM-Paging-Schutz via VirtualLock (verhindert Auslagerung in pagefile.sys)
|
||||
crate::windows::lock_memory(dek_arc.as_ptr(), 32);
|
||||
if let Some(ref c_dek) = carrier_dek_arc {
|
||||
crate::windows::lock_memory(c_dek.as_ptr(), 32);
|
||||
}
|
||||
|
||||
Self {
|
||||
db,
|
||||
dek: dek_arc,
|
||||
carrier_dek: carrier_dek_arc,
|
||||
dek: dek_guard,
|
||||
carrier_dek: carrier_dek_guard,
|
||||
carrier_node_id,
|
||||
carrier_fs,
|
||||
format_version,
|
||||
@@ -550,6 +580,10 @@ impl SanctumFs {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dek_strong_count(&self) -> usize {
|
||||
Arc::strong_count(&self.dek)
|
||||
}
|
||||
|
||||
pub fn vault_id(&self) -> u32 {
|
||||
self.vault_id
|
||||
}
|
||||
@@ -636,15 +670,6 @@ pub fn validate_path_safety(path: &str) -> Result<(), FsError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Drop for SanctumFs {
|
||||
fn drop(&mut self) {
|
||||
crate::windows::unlock_memory(self.dek.as_ptr(), 32);
|
||||
if let Some(ref c_dek) = self.carrier_dek {
|
||||
crate::windows::unlock_memory(c_dek.as_ptr(), 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DavFileSystem for SanctumFs {
|
||||
fn open<'a>(
|
||||
&'a self,
|
||||
|
||||
Reference in New Issue
Block a user