Normalize inactive State Anchor work storage
This commit is contained in:
parent
7cd8a90af0
commit
42e197510e
4 changed files with 133 additions and 11 deletions
|
|
@ -33,10 +33,10 @@ use rustix::fs::{
|
|||
use rustix::io::dup;
|
||||
use rustix::thread::{ThreadNameSpaceType, move_into_thread_name_spaces};
|
||||
use storage::{
|
||||
atomic_replace_at, create_directory, create_regular_file, descriptor_child_path,
|
||||
descriptor_path, host_path, inspect_directory, move_all_entries, move_selected_entries,
|
||||
open_directory, open_exact_directory_path, open_mounted_directory, open_or_create_quarantine,
|
||||
open_regular_file, path_from_host, remove_directory_contents,
|
||||
atomic_replace_at, clear_work_directory, create_directory, create_regular_file,
|
||||
descriptor_child_path, descriptor_path, host_path, inspect_directory, move_all_entries,
|
||||
move_selected_entries, open_directory, open_exact_directory_path, open_mounted_directory,
|
||||
open_or_create_quarantine, open_regular_file, path_from_host, remove_directory_contents,
|
||||
require_directory_descriptor_identity, require_maintenance_work_shape, require_same_descriptor,
|
||||
validate_relative_path,
|
||||
};
|
||||
|
|
@ -272,6 +272,15 @@ impl<'configuration> StateAnchorLayout<'configuration> {
|
|||
self.revalidate()
|
||||
}
|
||||
|
||||
/// Clears the private fuse-overlayfs work directory after proving the anchor inactive.
|
||||
///
|
||||
/// # Errors
|
||||
/// Refuses changed authority, a remaining mount, or descriptor-confined cleanup failure.
|
||||
pub fn normalize_inactive_work_directory(&self) -> Result<(), StateAnchorError> {
|
||||
self.require_unmounted()?;
|
||||
clear_work_directory(&self.work_descriptor)
|
||||
}
|
||||
|
||||
/// Atomically replaces sandbox runtime files in host-private transient storage.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use super::storage::{
|
||||
descriptor_child_path, descriptor_path, inherit_for_exec, open_directory,
|
||||
clear_work_directory, descriptor_child_path, descriptor_path, inherit_for_exec, open_directory,
|
||||
open_exact_directory_path, open_mounted_directory, overlay_options, path_from_host,
|
||||
reopen_inherited_directory, require_directory_descriptor_identity, rootless_unmount_path,
|
||||
reopen_inherited_directory, require_directory_descriptor_identity, require_same_descriptor,
|
||||
rootless_unmount_path,
|
||||
};
|
||||
use super::{
|
||||
AsFd, AsRawFd, FileType, HostProcessOwnershipSlot, Instant, MOUNT_POLL_INTERVAL, MOUNT_TIMEOUT,
|
||||
|
|
@ -161,6 +162,7 @@ pub struct RuntimeStateAnchorAuthority {
|
|||
lower: OwnedFd,
|
||||
persistent_anchor: OwnedFd,
|
||||
upper: OwnedFd,
|
||||
work: OwnedFd,
|
||||
runtime_anchor: OwnedFd,
|
||||
merged_label: PathBuf,
|
||||
merged_descriptor: OwnedFd,
|
||||
|
|
@ -233,13 +235,14 @@ impl RuntimeStateAnchorAuthority {
|
|||
inherited.runtime_anchor_label,
|
||||
(retained.st_dev, retained.st_ino),
|
||||
)?;
|
||||
drop(open_directory(&persistent_anchor, Path::new("work"))?);
|
||||
let work = open_directory(&persistent_anchor, Path::new("work"))?;
|
||||
let merged_descriptor = open_directory(&runtime_anchor, Path::new("merged"))?;
|
||||
let merged_label = inherited.runtime_anchor_label.join("merged");
|
||||
Ok(Self {
|
||||
lower,
|
||||
persistent_anchor,
|
||||
upper,
|
||||
work,
|
||||
runtime_anchor,
|
||||
merged_label,
|
||||
merged_descriptor,
|
||||
|
|
@ -495,6 +498,9 @@ impl RuntimeStateAnchorMount {
|
|||
return Err(StateAnchorError::OwnershipMismatch);
|
||||
}
|
||||
child_broker().reap(process)?;
|
||||
let observed_work = open_directory(&authority.persistent_anchor, Path::new("work"))?;
|
||||
require_same_descriptor(&observed_work, &authority.work)?;
|
||||
clear_work_directory(&authority.work)?;
|
||||
Ok(RuntimeStateAnchorAbsenceAuthority {
|
||||
runtime_anchor: authority.runtime_anchor,
|
||||
mount,
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ impl<'layout, 'configuration> FuseOverlayfsMount<'layout, 'configuration> {
|
|||
}
|
||||
self.layout.require_unmounted()?;
|
||||
child_broker().reap(self.process)?;
|
||||
self.layout.normalize_inactive_work_directory()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +166,7 @@ impl<'layout, 'configuration> FuseOverlayfsMount<'layout, 'configuration> {
|
|||
}
|
||||
self.layout.require_unmounted()?;
|
||||
child_broker().reap(self.process)?;
|
||||
self.layout.normalize_inactive_work_directory()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use super::{
|
|||
mount_identity, openat2, renameat, renameat_with, statat, unlinkat,
|
||||
};
|
||||
|
||||
const FUSE_OVERLAYFS_NESTED_WORK: &str = "work";
|
||||
|
||||
/// Independently verifies that no mount is attached at the exact merged path.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
@ -240,18 +242,34 @@ pub(super) fn require_maintenance_work_shape(directory: impl AsFd) -> Result<(),
|
|||
if names.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
if names.as_slice() != [OsString::from("work")] {
|
||||
if names.as_slice() != [OsString::from(FUSE_OVERLAYFS_NESTED_WORK)] {
|
||||
return Err(StateAnchorError::InvalidLayout(
|
||||
"State Anchor work directory has unsupported entries",
|
||||
));
|
||||
}
|
||||
let nested = open_directory(&directory, Path::new("work"))?;
|
||||
let nested = open_directory(&directory, Path::new(FUSE_OVERLAYFS_NESTED_WORK))?;
|
||||
require_nested_work_authority(&directory, &nested)?;
|
||||
if directory_has_entries(&nested)? {
|
||||
return Err(StateAnchorError::InvalidLayout(
|
||||
"State Anchor work directory has unsupported entries",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn clear_work_directory(directory: impl AsFd) -> Result<(), StateAnchorError> {
|
||||
remove_directory_contents(directory)
|
||||
}
|
||||
|
||||
fn require_nested_work_authority(
|
||||
directory: impl AsFd,
|
||||
nested: impl AsFd,
|
||||
) -> Result<(), StateAnchorError> {
|
||||
let parent = rustix::fs::fstat(&directory).map_err(io::Error::from)?;
|
||||
let child = rustix::fs::fstat(&nested).map_err(io::Error::from)?;
|
||||
if child.st_mode & 0o7777 != 0o700
|
||||
|| child.st_uid != parent.st_uid
|
||||
|| child.st_gid != parent.st_gid
|
||||
|| directory_has_entries(&nested)?
|
||||
{
|
||||
return Err(StateAnchorError::InvalidLayout(
|
||||
"State Anchor work directory has unsupported entries",
|
||||
|
|
|
|||
Loading…
Reference in a new issue