mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-16 07:05:14 +00:00
Merge pull request #1215 from jiangliu/liujiang/validator
improve rustjail validator
This commit is contained in:
commit
0e215ece36
@ -4,12 +4,20 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
use crate::container::Config;
|
use crate::container::Config;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Context, Error, Result};
|
||||||
use nix::errno::Errno;
|
use nix::errno::Errno;
|
||||||
use oci::{LinuxIDMapping, LinuxNamespace, Spec};
|
use oci::{Linux, LinuxIDMapping, LinuxNamespace, Spec};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::{Component, PathBuf};
|
use std::path::{Component, PathBuf};
|
||||||
|
|
||||||
|
fn einval() -> Error {
|
||||||
|
anyhow!(nix::Error::from_errno(Errno::EINVAL))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_linux(oci: &Spec) -> Result<&Linux> {
|
||||||
|
oci.linux.as_ref().ok_or_else(einval)
|
||||||
|
}
|
||||||
|
|
||||||
fn contain_namespace(nses: &[LinuxNamespace], key: &str) -> bool {
|
fn contain_namespace(nses: &[LinuxNamespace], key: &str) -> bool {
|
||||||
for ns in nses {
|
for ns in nses {
|
||||||
if ns.r#type.as_str() == key {
|
if ns.r#type.as_str() == key {
|
||||||
@ -27,14 +35,14 @@ fn get_namespace_path(nses: &[LinuxNamespace], key: &str) -> Result<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)))
|
Err(einval())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rootfs(root: &str) -> Result<()> {
|
fn rootfs(root: &str) -> Result<()> {
|
||||||
let path = PathBuf::from(root);
|
let path = PathBuf::from(root);
|
||||||
// not absolute path or not exists
|
// not absolute path or not exists
|
||||||
if !path.exists() || !path.is_absolute() {
|
if !path.exists() || !path.is_absolute() {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
// symbolic link? ..?
|
// symbolic link? ..?
|
||||||
@ -49,7 +57,11 @@ fn rootfs(root: &str) -> Result<()> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.push(c.as_os_str().to_str().unwrap().to_string());
|
if let Some(v) = c.as_os_str().to_str() {
|
||||||
|
stack.push(v.to_string());
|
||||||
|
} else {
|
||||||
|
return Err(einval());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cleaned = PathBuf::from("/");
|
let mut cleaned = PathBuf::from("/");
|
||||||
@ -57,10 +69,10 @@ fn rootfs(root: &str) -> Result<()> {
|
|||||||
cleaned.push(e);
|
cleaned.push(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let canon = path.canonicalize()?;
|
let canon = path.canonicalize().context("canonicalize")?;
|
||||||
if cleaned != canon {
|
if cleaned != canon {
|
||||||
// There is symbolic in path
|
// There is symbolic in path
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -75,25 +87,23 @@ fn hostname(oci: &Spec) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if oci.linux.is_none() {
|
let linux = get_linux(oci)?;
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
|
||||||
}
|
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
|
||||||
if !contain_namespace(&linux.namespaces, "uts") {
|
if !contain_namespace(&linux.namespaces, "uts") {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn security(oci: &Spec) -> Result<()> {
|
fn security(oci: &Spec) -> Result<()> {
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
let linux = get_linux(oci)?;
|
||||||
|
|
||||||
if linux.masked_paths.is_empty() && linux.readonly_paths.is_empty() {
|
if linux.masked_paths.is_empty() && linux.readonly_paths.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !contain_namespace(&linux.namespaces, "mount") {
|
if !contain_namespace(&linux.namespaces, "mount") {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't care about selinux at present
|
// don't care about selinux at present
|
||||||
@ -108,11 +118,12 @@ fn idmapping(maps: &[LinuxIDMapping]) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)))
|
Err(einval())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usernamespace(oci: &Spec) -> Result<()> {
|
fn usernamespace(oci: &Spec) -> Result<()> {
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
let linux = get_linux(oci)?;
|
||||||
|
|
||||||
if contain_namespace(&linux.namespaces, "user") {
|
if contain_namespace(&linux.namespaces, "user") {
|
||||||
let user_ns = PathBuf::from("/proc/self/ns/user");
|
let user_ns = PathBuf::from("/proc/self/ns/user");
|
||||||
if !user_ns.exists() {
|
if !user_ns.exists() {
|
||||||
@ -120,12 +131,12 @@ fn usernamespace(oci: &Spec) -> Result<()> {
|
|||||||
}
|
}
|
||||||
// check if idmappings is correct, at least I saw idmaps
|
// check if idmappings is correct, at least I saw idmaps
|
||||||
// with zero size was passed to agent
|
// with zero size was passed to agent
|
||||||
idmapping(&linux.uid_mappings)?;
|
idmapping(&linux.uid_mappings).context("idmapping uid")?;
|
||||||
idmapping(&linux.gid_mappings)?;
|
idmapping(&linux.gid_mappings).context("idmapping gid")?;
|
||||||
} else {
|
} else {
|
||||||
// no user namespace but idmap
|
// no user namespace but idmap
|
||||||
if !linux.uid_mappings.is_empty() || !linux.gid_mappings.is_empty() {
|
if !linux.uid_mappings.is_empty() || !linux.gid_mappings.is_empty() {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +144,8 @@ fn usernamespace(oci: &Spec) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cgroupnamespace(oci: &Spec) -> Result<()> {
|
fn cgroupnamespace(oci: &Spec) -> Result<()> {
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
let linux = get_linux(oci)?;
|
||||||
|
|
||||||
if contain_namespace(&linux.namespaces, "cgroup") {
|
if contain_namespace(&linux.namespaces, "cgroup") {
|
||||||
let path = PathBuf::from("/proc/self/ns/cgroup");
|
let path = PathBuf::from("/proc/self/ns/cgroup");
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
@ -162,29 +174,36 @@ fn check_host_ns(path: &str) -> Result<()> {
|
|||||||
let cpath = PathBuf::from(path);
|
let cpath = PathBuf::from(path);
|
||||||
let hpath = PathBuf::from("/proc/self/ns/net");
|
let hpath = PathBuf::from("/proc/self/ns/net");
|
||||||
|
|
||||||
let real_hpath = hpath.read_link()?;
|
let real_hpath = hpath
|
||||||
let meta = cpath.symlink_metadata()?;
|
.read_link()
|
||||||
|
.context(format!("read link {:?}", hpath))?;
|
||||||
|
let meta = cpath
|
||||||
|
.symlink_metadata()
|
||||||
|
.context(format!("symlink metadata {:?}", cpath))?;
|
||||||
let file_type = meta.file_type();
|
let file_type = meta.file_type();
|
||||||
|
|
||||||
if !file_type.is_symlink() {
|
if !file_type.is_symlink() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let real_cpath = cpath.read_link()?;
|
let real_cpath = cpath
|
||||||
|
.read_link()
|
||||||
|
.context(format!("read link {:?}", cpath))?;
|
||||||
if real_cpath == real_hpath {
|
if real_cpath == real_hpath {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sysctl(oci: &Spec) -> Result<()> {
|
fn sysctl(oci: &Spec) -> Result<()> {
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
let linux = get_linux(oci)?;
|
||||||
|
|
||||||
for (key, _) in linux.sysctl.iter() {
|
for (key, _) in linux.sysctl.iter() {
|
||||||
if SYSCTLS.contains_key(key.as_str()) || key.starts_with("fs.mqueue.") {
|
if SYSCTLS.contains_key(key.as_str()) || key.starts_with("fs.mqueue.") {
|
||||||
if contain_namespace(&linux.namespaces, "ipc") {
|
if contain_namespace(&linux.namespaces, "ipc") {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,24 +213,25 @@ fn sysctl(oci: &Spec) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if key == "kernel.hostname" {
|
if key == "kernel.hostname" {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rootless_euid_mapping(oci: &Spec) -> Result<()> {
|
fn rootless_euid_mapping(oci: &Spec) -> Result<()> {
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
let linux = get_linux(oci)?;
|
||||||
|
|
||||||
if !contain_namespace(&linux.namespaces, "user") {
|
if !contain_namespace(&linux.namespaces, "user") {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
if linux.uid_mappings.is_empty() || linux.gid_mappings.is_empty() {
|
if linux.uid_mappings.is_empty() || linux.gid_mappings.is_empty() {
|
||||||
// rootless containers requires at least one UID/GID mapping
|
// rootless containers requires at least one UID/GID mapping
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -227,7 +247,7 @@ fn has_idmapping(maps: &[LinuxIDMapping], id: u32) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rootless_euid_mount(oci: &Spec) -> Result<()> {
|
fn rootless_euid_mount(oci: &Spec) -> Result<()> {
|
||||||
let linux = oci.linux.as_ref().unwrap();
|
let linux = get_linux(oci)?;
|
||||||
|
|
||||||
for mnt in oci.mounts.iter() {
|
for mnt in oci.mounts.iter() {
|
||||||
for opt in mnt.options.iter() {
|
for opt in mnt.options.iter() {
|
||||||
@ -235,17 +255,20 @@ fn rootless_euid_mount(oci: &Spec) -> Result<()> {
|
|||||||
let fields: Vec<&str> = opt.split('=').collect();
|
let fields: Vec<&str> = opt.split('=').collect();
|
||||||
|
|
||||||
if fields.len() != 2 {
|
if fields.len() != 2 {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = fields[1].trim().parse::<u32>()?;
|
let id = fields[1]
|
||||||
|
.trim()
|
||||||
|
.parse::<u32>()
|
||||||
|
.context(format!("parse field {}", &fields[1]))?;
|
||||||
|
|
||||||
if opt.starts_with("uid=") && !has_idmapping(&linux.uid_mappings, id) {
|
if opt.starts_with("uid=") && !has_idmapping(&linux.uid_mappings, id) {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.starts_with("gid=") && !has_idmapping(&linux.gid_mappings, id) {
|
if opt.starts_with("gid=") && !has_idmapping(&linux.gid_mappings, id) {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,35 +277,306 @@ fn rootless_euid_mount(oci: &Spec) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rootless_euid(oci: &Spec) -> Result<()> {
|
fn rootless_euid(oci: &Spec) -> Result<()> {
|
||||||
rootless_euid_mapping(oci)?;
|
rootless_euid_mapping(oci).context("rootless euid mapping")?;
|
||||||
rootless_euid_mount(oci)?;
|
rootless_euid_mount(oci).context("rotless euid mount")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(conf: &Config) -> Result<()> {
|
pub fn validate(conf: &Config) -> Result<()> {
|
||||||
lazy_static::initialize(&SYSCTLS);
|
lazy_static::initialize(&SYSCTLS);
|
||||||
let oci = conf.spec.as_ref().unwrap();
|
let oci = conf.spec.as_ref().ok_or_else(einval)?;
|
||||||
|
|
||||||
if oci.linux.is_none() {
|
if oci.linux.is_none() {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
return Err(einval());
|
||||||
}
|
}
|
||||||
|
|
||||||
if oci.root.is_none() {
|
let root = match oci.root.as_ref() {
|
||||||
return Err(anyhow!(nix::Error::from_errno(Errno::EINVAL)));
|
Some(v) => v.path.as_str(),
|
||||||
}
|
None => return Err(einval()),
|
||||||
let root = oci.root.as_ref().unwrap().path.as_str();
|
};
|
||||||
|
|
||||||
rootfs(root)?;
|
rootfs(root).context("rootfs")?;
|
||||||
network(oci)?;
|
network(oci).context("network")?;
|
||||||
hostname(oci)?;
|
hostname(oci).context("hostname")?;
|
||||||
security(oci)?;
|
security(oci).context("security")?;
|
||||||
usernamespace(oci)?;
|
usernamespace(oci).context("usernamespace")?;
|
||||||
cgroupnamespace(oci)?;
|
cgroupnamespace(oci).context("cgroupnamespace")?;
|
||||||
sysctl(&oci)?;
|
sysctl(&oci).context("sysctl")?;
|
||||||
|
|
||||||
if conf.rootless_euid {
|
if conf.rootless_euid {
|
||||||
rootless_euid(oci)?;
|
rootless_euid(oci).context("rootless euid")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use oci::Mount;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_namespace() {
|
||||||
|
let namespaces = [
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
},
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "uts".to_owned(),
|
||||||
|
path: "/sys/cgroups/uts".to_owned(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(contain_namespace(&namespaces, "net"), true);
|
||||||
|
assert_eq!(contain_namespace(&namespaces, "uts"), true);
|
||||||
|
|
||||||
|
assert_eq!(contain_namespace(&namespaces, ""), false);
|
||||||
|
assert_eq!(contain_namespace(&namespaces, "Net"), false);
|
||||||
|
assert_eq!(contain_namespace(&namespaces, "ipc"), false);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_namespace_path(&namespaces, "net").unwrap(),
|
||||||
|
"/sys/cgroups/net"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_namespace_path(&namespaces, "uts").unwrap(),
|
||||||
|
"/sys/cgroups/uts"
|
||||||
|
);
|
||||||
|
|
||||||
|
get_namespace_path(&namespaces, "").unwrap_err();
|
||||||
|
get_namespace_path(&namespaces, "Uts").unwrap_err();
|
||||||
|
get_namespace_path(&namespaces, "ipc").unwrap_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rootfs() {
|
||||||
|
rootfs("/_no_exit_fs_xxxxxxxxxxx").unwrap_err();
|
||||||
|
rootfs("sys").unwrap_err();
|
||||||
|
rootfs("/proc/self/root").unwrap_err();
|
||||||
|
rootfs("/proc/self/root/sys").unwrap_err();
|
||||||
|
|
||||||
|
rootfs("/proc/self").unwrap_err();
|
||||||
|
rootfs("/./proc/self").unwrap_err();
|
||||||
|
rootfs("/proc/././self").unwrap_err();
|
||||||
|
rootfs("/proc/.././self").unwrap_err();
|
||||||
|
|
||||||
|
rootfs("/proc/uptime").unwrap();
|
||||||
|
rootfs("/../proc/uptime").unwrap();
|
||||||
|
rootfs("/../../proc/uptime").unwrap();
|
||||||
|
rootfs("/proc/../proc/uptime").unwrap();
|
||||||
|
rootfs("/proc/../../proc/uptime").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hostname() {
|
||||||
|
let mut spec = Spec::default();
|
||||||
|
|
||||||
|
hostname(&spec).unwrap();
|
||||||
|
|
||||||
|
spec.hostname = "a.test.com".to_owned();
|
||||||
|
hostname(&spec).unwrap_err();
|
||||||
|
|
||||||
|
let mut linux = Linux::default();
|
||||||
|
linux.namespaces = vec![
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
},
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "uts".to_owned(),
|
||||||
|
path: "/sys/cgroups/uts".to_owned(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
hostname(&spec).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_security() {
|
||||||
|
let mut spec = Spec::default();
|
||||||
|
|
||||||
|
let linux = Linux::default();
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
security(&spec).unwrap();
|
||||||
|
|
||||||
|
let mut linux = Linux::default();
|
||||||
|
linux.masked_paths.push("/test".to_owned());
|
||||||
|
linux.namespaces = vec![
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
},
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "uts".to_owned(),
|
||||||
|
path: "/sys/cgroups/uts".to_owned(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
security(&spec).unwrap_err();
|
||||||
|
|
||||||
|
let mut linux = Linux::default();
|
||||||
|
linux.masked_paths.push("/test".to_owned());
|
||||||
|
linux.namespaces = vec![
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
},
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "mount".to_owned(),
|
||||||
|
path: "/sys/cgroups/mount".to_owned(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
security(&spec).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_usernamespace() {
|
||||||
|
let mut spec = Spec::default();
|
||||||
|
usernamespace(&spec).unwrap_err();
|
||||||
|
|
||||||
|
let linux = Linux::default();
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
usernamespace(&spec).unwrap();
|
||||||
|
|
||||||
|
let mut linux = Linux::default();
|
||||||
|
linux.uid_mappings = vec![LinuxIDMapping {
|
||||||
|
container_id: 0,
|
||||||
|
host_id: 1000,
|
||||||
|
size: 0,
|
||||||
|
}];
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
usernamespace(&spec).unwrap_err();
|
||||||
|
|
||||||
|
let mut linux = Linux::default();
|
||||||
|
linux.uid_mappings = vec![LinuxIDMapping {
|
||||||
|
container_id: 0,
|
||||||
|
host_id: 1000,
|
||||||
|
size: 100,
|
||||||
|
}];
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
usernamespace(&spec).unwrap_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rootless_euid() {
|
||||||
|
let mut spec = Spec::default();
|
||||||
|
|
||||||
|
// Test case: without linux
|
||||||
|
rootless_euid_mapping(&spec).unwrap_err();
|
||||||
|
rootless_euid_mount(&spec).unwrap_err();
|
||||||
|
|
||||||
|
// Test case: without user namespace
|
||||||
|
let linux = Linux::default();
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
rootless_euid_mapping(&spec).unwrap_err();
|
||||||
|
|
||||||
|
// Test case: without user namespace
|
||||||
|
let linux = spec.linux.as_mut().unwrap();
|
||||||
|
linux.namespaces = vec![
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
},
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "uts".to_owned(),
|
||||||
|
path: "/sys/cgroups/uts".to_owned(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
rootless_euid_mapping(&spec).unwrap_err();
|
||||||
|
|
||||||
|
let linux = spec.linux.as_mut().unwrap();
|
||||||
|
linux.namespaces = vec![
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
},
|
||||||
|
LinuxNamespace {
|
||||||
|
r#type: "user".to_owned(),
|
||||||
|
path: "/sys/cgroups/user".to_owned(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
linux.uid_mappings = vec![LinuxIDMapping {
|
||||||
|
container_id: 0,
|
||||||
|
host_id: 1000,
|
||||||
|
size: 1000,
|
||||||
|
}];
|
||||||
|
linux.gid_mappings = vec![LinuxIDMapping {
|
||||||
|
container_id: 0,
|
||||||
|
host_id: 1000,
|
||||||
|
size: 1000,
|
||||||
|
}];
|
||||||
|
rootless_euid_mapping(&spec).unwrap();
|
||||||
|
|
||||||
|
spec.mounts.push(Mount {
|
||||||
|
destination: "/app".to_owned(),
|
||||||
|
r#type: "tmpfs".to_owned(),
|
||||||
|
source: "".to_owned(),
|
||||||
|
options: vec!["uid=10000".to_owned()],
|
||||||
|
});
|
||||||
|
rootless_euid_mount(&spec).unwrap_err();
|
||||||
|
|
||||||
|
spec.mounts = vec![
|
||||||
|
(Mount {
|
||||||
|
destination: "/app".to_owned(),
|
||||||
|
r#type: "tmpfs".to_owned(),
|
||||||
|
source: "".to_owned(),
|
||||||
|
options: vec!["uid=500".to_owned(), "gid=500".to_owned()],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
rootless_euid(&spec).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_host_ns() {
|
||||||
|
check_host_ns("/proc/self/ns/net").unwrap_err();
|
||||||
|
check_host_ns("/proc/sys/net/ipv4/tcp_sack").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sysctl() {
|
||||||
|
let mut spec = Spec::default();
|
||||||
|
|
||||||
|
let mut linux = Linux::default();
|
||||||
|
linux.namespaces = vec![LinuxNamespace {
|
||||||
|
r#type: "net".to_owned(),
|
||||||
|
path: "/sys/cgroups/net".to_owned(),
|
||||||
|
}];
|
||||||
|
linux
|
||||||
|
.sysctl
|
||||||
|
.insert("kernel.domainname".to_owned(), "test.com".to_owned());
|
||||||
|
spec.linux = Some(linux);
|
||||||
|
sysctl(&spec).unwrap_err();
|
||||||
|
|
||||||
|
spec.linux
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.namespaces
|
||||||
|
.push(LinuxNamespace {
|
||||||
|
r#type: "uts".to_owned(),
|
||||||
|
path: "/sys/cgroups/uts".to_owned(),
|
||||||
|
});
|
||||||
|
sysctl(&spec).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_validate() {
|
||||||
|
let spec = Spec::default();
|
||||||
|
let mut config = Config {
|
||||||
|
cgroup_name: "container1".to_owned(),
|
||||||
|
use_systemd_cgroup: false,
|
||||||
|
no_pivot_root: true,
|
||||||
|
no_new_keyring: true,
|
||||||
|
rootless_euid: false,
|
||||||
|
rootless_cgroup: false,
|
||||||
|
spec: Some(spec),
|
||||||
|
};
|
||||||
|
|
||||||
|
validate(&config).unwrap_err();
|
||||||
|
|
||||||
|
let linux = Linux::default();
|
||||||
|
config.spec.as_mut().unwrap().linux = Some(linux);
|
||||||
|
validate(&config).unwrap_err();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user