Close hostile recovery and concurrency gaps

This commit is contained in:
ms2k 2026-07-18 05:47:15 +09:00
commit 3f9b1b3543
2 changed files with 306 additions and 113 deletions

View file

@ -1597,7 +1597,10 @@ fn ensure_owned_directory(path: &Path, uid: u32) -> Result<PathBuf, Configuratio
let mut current = open_absolute_directory(&existing_canonical)?;
let mut canonical = existing_canonical;
for component in missing.into_iter().rev() {
rustix::fs::mkdirat(&current, &component, Mode::RWXU).map_err(io_error)?;
match rustix::fs::mkdirat(&current, &component, Mode::RWXU) {
Ok(()) | Err(rustix::io::Errno::EXIST) => {}
Err(error) => return Err(io_error(error)),
}
let next = openat2(
&current,
&component,

View file

@ -3,6 +3,7 @@ use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt, symlink};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Barrier};
use lazaret_core::codec::{CodecError, decode, encode};
use lazaret_core::configuration::{
@ -645,6 +646,31 @@ fn volume_symlinks_and_lazaret_owned_mode_drift_are_rejected() {
);
}
#[test]
fn concurrent_loaders_share_exact_owned_directory_creation() {
let tree = TestTree::new();
let config = write_configuration(&tree, &valid_configuration(&tree));
let barrier = Arc::new(Barrier::new(8));
std::thread::scope(|scope| {
let handles = (0..8)
.map(|_| {
let barrier = Arc::clone(&barrier);
let config = config.clone();
let tree = &tree;
scope.spawn(move || {
let mut environment = BTreeMap::new();
environment.insert("HOST_TOKEN".into(), "value".into());
barrier.wait();
load_trusted_configuration(request(tree, config, environment))
})
})
.collect::<Vec<_>>();
for handle in handles {
handle.join().unwrap().unwrap();
}
});
}
#[test]
fn configuration_source_permissions_links_and_size_are_bounded() {
for mutation in 0..3 {