add ALLOW, NOINIT, NODEINIT, SYSVIPC, MOUNT directives

This commit is contained in:
Yan Ka, Chiu
2023-07-11 13:16:38 -04:00
parent 60738c5555
commit be1603d488
5 changed files with 150 additions and 7 deletions

View File

@@ -103,7 +103,7 @@ pub(crate) enum PatchActions {
},
}
fn patch_image<F>(
pub(crate) fn patch_image<F>(
conn: &mut UnixStream,
image_reference: &ImageReference,
f: F,

View File

@@ -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<Self, anyhow::Error>;
fn run_in_context(&self, context: &mut JailContext) -> Result<(), anyhow::Error>;
}
#[derive(Clone)]
pub(crate) enum ConfigMod {
Allow(Vec<String>),
ReplaceAllow(Vec<String>),
WorkDir,
Init,
NoInit,
Deinit,
NoDeinit,
Cmd,
Expose,
Volume,
Mount(String, String),
SysV(Vec<String>),
}
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<Self, anyhow::Error> {
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(())
}
}

View File

@@ -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<NetworkAllocRequest>,
pub(crate) config_mods: Vec<self::directives::ConfigMod>,
}
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:?}");

View File

@@ -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) => {

View File

@@ -260,8 +260,10 @@ impl ImageStore for SqliteImageStore {
fn register_manifest(&self, manifest: &JailImage) -> Result<OciDigest, ImageStoreError> {
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()])?;