From be1603d4887f648131f7e92fc899bc2e1a4a4f2c Mon Sep 17 00:00:00 2001 From: "Yan Ka, Chiu" Date: Tue, 11 Jul 2023 13:16:38 -0400 Subject: [PATCH] add ALLOW, NOINIT, NODEINIT, SYSVIPC, MOUNT directives --- xc-bin/src/image.rs | 2 +- xc-bin/src/jailfile/directives/mod.rs | 102 ++++++++++++++++++++++++++ xc-bin/src/jailfile/mod.rs | 32 +++++++- xc-bin/src/main.rs | 15 +++- xc/src/image_store/sqlite.rs | 6 +- 5 files changed, 150 insertions(+), 7 deletions(-) diff --git a/xc-bin/src/image.rs b/xc-bin/src/image.rs index 3dd7920..69eec85 100644 --- a/xc-bin/src/image.rs +++ b/xc-bin/src/image.rs @@ -103,7 +103,7 @@ pub(crate) enum PatchActions { }, } -fn patch_image( +pub(crate) fn patch_image( conn: &mut UnixStream, image_reference: &ImageReference, f: F, diff --git a/xc-bin/src/jailfile/directives/mod.rs b/xc-bin/src/jailfile/directives/mod.rs index b943abc..4227f30 100644 --- a/xc-bin/src/jailfile/directives/mod.rs +++ b/xc-bin/src/jailfile/directives/mod.rs @@ -28,7 +28,109 @@ pub mod run; use super::JailContext; use crate::jailfile::parse::Action; +use anyhow::Context; +use xc::models::jail_image::{JailConfig, SpecialMount}; +use xc::models::SystemVPropValue; + pub(crate) trait Directive: Sized { fn from_action(action: &Action) -> Result; fn run_in_context(&self, context: &mut JailContext) -> Result<(), anyhow::Error>; } + +#[derive(Clone)] +pub(crate) enum ConfigMod { + Allow(Vec), + ReplaceAllow(Vec), + WorkDir, + Init, + NoInit, + Deinit, + NoDeinit, + Cmd, + Expose, + Volume, + Mount(String, String), + SysV(Vec), +} + +impl ConfigMod { + pub(crate) fn apply_config(&self, config: &mut JailConfig) { + match self { + Self::NoInit => config.init = Vec::new(), + Self::NoDeinit => config.deinit = Vec::new(), + Self::Allow(allows) => { + for allow in allows.iter() { + if let Some(param) = allow.strip_prefix('-') { + for i in (0..config.allow.len()).rev() { + if config.allow[i] == param { + config.allow.remove(i); + } + } + } else if !config.allow.contains(allow) { + config.allow.push(allow.to_string()); + } + } + } + Self::ReplaceAllow(allows) => { + for allow in allows.iter() { + if allow.strip_prefix('-').is_none() { + config.allow.push(allow.to_string()); + } + } + } + Self::Mount(mount_type, mount_point) => { + let special_mount = SpecialMount { + mount_type: mount_type.to_string(), + mount_point: mount_point.to_string(), + }; + if !config.special_mounts.contains(&special_mount) { + config.special_mounts.push(special_mount) + } + } + Self::SysV(sysvattrs) => { + for attr in sysvattrs.iter() { + match attr.as_str() { + "shm" => config.sysv_shm = SystemVPropValue::New, + "-shm" => config.sysv_shm = SystemVPropValue::Disable, + "msg" => config.sysv_msg = SystemVPropValue::New, + "-msg" => config.sysv_msg = SystemVPropValue::Disable, + "sem" => config.sysv_sem = SystemVPropValue::New, + "-sem" => config.sysv_sem = SystemVPropValue::Disable, + _ => continue, + } + } + } + _ => {} + } + } + + pub(crate) fn implemented_directives() -> &'static [&'static str] { + &["ALLOW", "NOINIT", "NODEINIT", "SYSVIPC", "MOUNT"] + } +} + +impl Directive for ConfigMod { + fn from_action(action: &Action) -> Result { + match action.directive_name.as_str() { + "ALLOW" => match action.directive_args.get("replace") { + Some(value) if value.as_str() == "true" => { + Ok(ConfigMod::ReplaceAllow(action.args.clone())) + } + _ => Ok(ConfigMod::Allow(action.args.clone())), + }, + "NOINIT" => Ok(ConfigMod::NoInit), + "NODEINIT" => Ok(ConfigMod::NoDeinit), + "SYSVIPC" => Ok(ConfigMod::SysV(action.args.clone())), + "MOUNT" => { + let fstype = action.args.get(0).context("cannot get fstype")?; + let mountpoint = action.args.get(1).context("cannot get mountpoint")?; + Ok(ConfigMod::Mount(fstype.to_string(), mountpoint.to_string())) + } + _ => unreachable!(), + } + } + fn run_in_context(&self, context: &mut JailContext) -> Result<(), anyhow::Error> { + context.config_mods.push(self.clone()); + Ok(()) + } +} diff --git a/xc-bin/src/jailfile/mod.rs b/xc-bin/src/jailfile/mod.rs index 47428a1..fcff13f 100644 --- a/xc-bin/src/jailfile/mod.rs +++ b/xc-bin/src/jailfile/mod.rs @@ -24,10 +24,12 @@ pub mod directives; pub mod parse; +use oci_util::image_reference::ImageReference; use std::collections::{HashMap, HashSet}; use std::os::unix::net::UnixStream; use tracing::error; use xc::container::request::NetworkAllocRequest; +use xc::models::jail_image::JailConfig; use xc::models::network::DnsSetting; use xcd::ipc::*; @@ -42,6 +44,8 @@ pub(crate) struct JailContext { pub(crate) dns: DnsSetting, pub(crate) network: Vec, + + pub(crate) config_mods: Vec, } impl JailContext { @@ -56,10 +60,34 @@ impl JailContext { containers: HashMap::new(), dns, network, + config_mods: Vec::new(), } } - pub(crate) fn release(mut self) -> anyhow::Result<()> { + pub(crate) fn apply_config(&self, config: &mut JailConfig) { + for config_mod in self.config_mods.iter() { + config_mod.apply_config(config); + } + } + + pub(crate) fn release(self, image_reference: ImageReference) -> anyhow::Result<()> { + let mut conn = self.conn; + let config_mods = self.config_mods; + let req = CommitRequest { + name: image_reference.name.to_string(), + tag: image_reference.tag.to_string(), + container_name: self.container_id.clone().unwrap(), + }; + + let _response = do_commit_container(&mut conn, req)?.unwrap(); + + crate::image::patch_image(&mut conn, &image_reference, |config| { + for config_mod in config_mods.iter() { + config_mod.apply_config(config); + } + // self.apply_config(config); + })?; + let mut containers = HashSet::new(); if let Some(container) = self.container_id { containers.insert(container); @@ -71,7 +99,7 @@ impl JailContext { let kill = KillContainerRequest { name: name.to_string(), }; - match do_kill_container(&mut self.conn, kill)? { + match do_kill_container(&mut conn, kill)? { Ok(_) => {} Err(error) => { error!("cannot kill container {name}: {error:?}"); diff --git a/xc-bin/src/main.rs b/xc-bin/src/main.rs index 8ea5640..ab20ed7 100644 --- a/xc-bin/src/main.rs +++ b/xc-bin/src/main.rs @@ -314,19 +314,30 @@ fn main() -> Result<(), ActionError> { } else if action.directive_name == "COPY" { let directive = CopyDirective::from_action(action)?; directive.run_in_context(&mut context)?; + } else if ConfigMod::implemented_directives() + .contains(&action.directive_name.as_str()) + { + let directive = ConfigMod::from_action(action)?; + directive.run_in_context(&mut context)?; } } debug!("before commit"); + /* let req = CommitRequest { - name: image_reference.name, + name: image_reference.name.to_string(), tag: image_reference.tag.to_string(), container_name: context.container_id.clone().unwrap(), }; let response = do_commit_container(&mut context.conn, req)?.unwrap(); eprintln!("{response:#?}"); - context.release()?; + crate::image::patch_image(&mut context.conn, &image_reference, |config| { + context.apply_config(config); + })?; + */ + + context.release(image_reference)?; // let response: CommitResponse = request(&mut conn, "commit", req)?; } Action::Channel(action) => { diff --git a/xc/src/image_store/sqlite.rs b/xc/src/image_store/sqlite.rs index a571021..20e7507 100644 --- a/xc/src/image_store/sqlite.rs +++ b/xc/src/image_store/sqlite.rs @@ -260,8 +260,10 @@ impl ImageStore for SqliteImageStore { fn register_manifest(&self, manifest: &JailImage) -> Result { let db = &self.db; - let mut stmt = - db.prepare_cached("insert into image_manifests (digest, manifest) values (?, ?)")?; + let mut stmt = db.prepare_cached( + "insert into image_manifests (digest, manifest) values (?, ?) + on conflict(digest) do nothing", + )?; let manifest_json = serde_json::to_string(manifest)?; let digest = manifest.digest(); stmt.execute([digest.as_str(), manifest_json.as_str()])?;