Bound and configure the per-Domain runsc dcache

This commit is contained in:
ms2k 2026-07-24 23:34:02 +09:00
commit db9a561d0c
4 changed files with 157 additions and 11 deletions

View file

@ -10,8 +10,8 @@ use sha2::{Digest, Sha256};
use crate::identity::{ConfigurationFingerprint, DeviceId, DomainId, HostPath, InodeId, MountId};
use crate::records::{
ConfigurationFingerprintRecordV1, MailboxRequest, ResolvedAutoApprovalRule, ResolvedVolume,
TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1, VolumeKind,
ConfigurationFingerprintRecordV1, MAX_RUNSC_DCACHE, MailboxRequest, ResolvedAutoApprovalRule,
ResolvedVolume, TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1, VolumeKind,
};
use confined_io::{io_error, open_absolute_directory, validate_executable};
use validation::validate_sandbox_path;
@ -27,6 +27,7 @@ pub enum ConfigurationErrorKind {
InvalidProfile,
InvalidPath,
PathConflict,
InvalidRuntime,
InvalidNetwork,
MissingEnvironment,
InvalidVolume,
@ -72,6 +73,7 @@ const fn error_label(kind: ConfigurationErrorKind) -> &'static str {
ConfigurationErrorKind::InvalidProfile => "invalid profile",
ConfigurationErrorKind::InvalidPath => "invalid path",
ConfigurationErrorKind::PathConflict => "path conflict",
ConfigurationErrorKind::InvalidRuntime => "invalid runtime configuration",
ConfigurationErrorKind::InvalidNetwork => "invalid network policy",
ConfigurationErrorKind::MissingEnvironment => "invalid environment reference",
ConfigurationErrorKind::InvalidVolume => "invalid volume",
@ -679,6 +681,11 @@ impl ResolvedDomainConfiguration {
&self.fingerprint_record
}
#[must_use]
pub const fn runsc_dcache(&self) -> u32 {
self.fingerprint_record.runsc_dcache
}
#[must_use]
pub fn effective_allow_prefixes(&self) -> &[Ipv4Prefix] {
&self.effective_allow_prefixes

View file

@ -343,6 +343,7 @@ pub fn load_trusted_configuration(
selected_profile: request.selected_profile.clone(),
storage_root: host_path(&storage_canonical),
runtime_root: host_path(&runtime_canonical),
runsc_dcache: configuration.runtime().runsc_dcache,
image: selected.image.clone(),
isolate_gitignored: selected.isolate_gitignored,
persistent_dirs,

View file

@ -4,7 +4,7 @@ use super::confined_io::{
};
use super::{
ConfigurationError, ConfigurationErrorKind, ConfigurationFingerprint,
ConfigurationFingerprintRecordV1, Digest, DomainId, Sha256,
ConfigurationFingerprintRecordV1, Digest, DomainId, MAX_RUNSC_DCACHE, Sha256,
TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1,
};
@ -33,6 +33,7 @@ pub fn derive_configuration_fingerprint(
push_bytes(&mut preimage, record.selected_profile.as_bytes())?;
push_bytes(&mut preimage, record.storage_root.as_bytes())?;
push_bytes(&mut preimage, record.runtime_root.as_bytes())?;
preimage.extend_from_slice(&record.runsc_dcache.to_be_bytes());
push_bytes(&mut preimage, record.image.as_bytes())?;
push_bool(&mut preimage, record.isolate_gitignored);
@ -87,6 +88,12 @@ pub(super) fn validate_structural_configuration(
"unknown configuration schema",
));
}
if configuration.runtime().runsc_dcache > MAX_RUNSC_DCACHE {
return Err(ConfigurationError::new(
ConfigurationErrorKind::InvalidRuntime,
format!("runsc_dcache exceeds {MAX_RUNSC_DCACHE} entries"),
));
}
for (name, profile) in configuration.profiles() {
validate_profile_name(name)?;
validate_text(&profile.image, "profile image")?;

View file

@ -6,6 +6,8 @@ pub const DOMAIN_STORE_SCHEMA_VERSION: u32 = 1;
pub const STORAGE_CATALOG_SCHEMA_VERSION: u32 = 1;
pub const TRUSTED_HOST_CONFIGURATION_SCHEMA_ID: &str = "lazaret-trusted-host-config-v1";
pub const DEFAULT_PERSISTENT_DIRS: [&str; 5] = ["/root", "/usr", "/var", "/etc", "/opt"];
pub const DEFAULT_RUNSC_DCACHE: u32 = 50_000;
pub const MAX_RUNSC_DCACHE: u32 = 262_144;
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
@ -23,6 +25,25 @@ pub struct NetworkConfigurationV1 {
pub default_deny: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct RuntimeConfigurationV1 {
#[serde(default = "default_runsc_dcache")]
pub runsc_dcache: u32,
}
impl Default for RuntimeConfigurationV1 {
fn default() -> Self {
Self {
runsc_dcache: DEFAULT_RUNSC_DCACHE,
}
}
}
const fn default_runsc_dcache() -> u32 {
DEFAULT_RUNSC_DCACHE
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum VolumeKind {
@ -103,6 +124,7 @@ pub struct TrustedHostConfigurationV1 {
schema_id: String,
storage: StorageConfigurationV1,
network: NetworkConfigurationV1,
runtime: RuntimeConfigurationV1,
profiles: BTreeMap<String, ProfileConfigurationV1>,
}
@ -122,6 +144,11 @@ impl TrustedHostConfigurationV1 {
&self.network
}
#[must_use]
pub const fn runtime(&self) -> &RuntimeConfigurationV1 {
&self.runtime
}
#[must_use]
pub const fn profiles(&self) -> &BTreeMap<String, ProfileConfigurationV1> {
&self.profiles
@ -142,6 +169,8 @@ impl<'de> Deserialize<'de> for TrustedHostConfigurationV1 {
storage: StorageConfigurationV1,
#[serde(default)]
network: NetworkConfigurationV1,
#[serde(default)]
runtime: RuntimeConfigurationV1,
profiles: BTreeMap<String, ProfileConfigurationV1>,
}
@ -160,6 +189,7 @@ impl<'de> Deserialize<'de> for TrustedHostConfigurationV1 {
schema_id: fields.schema_id,
storage: fields.storage,
network: fields.network,
runtime: fields.runtime,
profiles: fields.profiles,
})
}
@ -192,6 +222,7 @@ pub struct ConfigurationFingerprintRecordV1 {
pub selected_profile: String,
pub storage_root: HostPath,
pub runtime_root: HostPath,
pub runsc_dcache: u32,
pub image: String,
pub isolate_gitignored: bool,
pub persistent_dirs: Vec<String>,