rustjail
是 Kata 容器代理程序中的一个模块,负责在 Rust 中实现容器的隔离和安全功能。这个模块使用 Linux 的各种安全和隔离机制,如 seccomp、命名空间、cgroups 和挂载命名空间,来确保容器内的进程与宿主机及其他容器的隔离。
主要功能
- Seccomp 安全策略:
rustjail
使用 seccomp 来限制容器内进程可以调用的系统调用,增强安全性。这通过解析 OCI (Open Container Initiative) 规范中定义的 seccomp 配置来实现。- 例如,
get_filter_attr_from_flag
和get_rule_conditions
函数用于解析和应用 seccomp 规则。
fn get_filter_attr_from_flag(flag: &str) -> Result<ScmpFilterAttr> {
match flag {
"SECCOMP_FILTER_FLAG_TSYNC" => Ok(ScmpFilterAttr::CtlTsync),
"SECCOMP_FILTER_FLAG_LOG" => Ok(ScmpFilterAttr::CtlLog),
"SECCOMP_FILTER_FLAG_SPEC_ALLOW" => Ok(ScmpFilterAttr::CtlSsb),
_ => Err(anyhow!("Invalid seccomp flag")),
}
}
// get_rule_conditions gets rule conditions for a system call from the args.
fn get_rule_conditions(args: &[LinuxSeccompArg]) -> Result<Vec<ScmpArgCompare>> {
let mut conditions: Vec<ScmpArgCompare> = Vec::new();
for arg in args {
let mut op = ScmpCompareOp::from_str(&arg.op().to_string())?;
let mut value = arg.value();
// For SCMP_CMP_MASKED_EQ, arg.value is the mask and arg.value_two is the value
if op == ScmpCompareOp::MaskedEqual(u64::default()) {
op = ScmpCompareOp::MaskedEqual(arg.value());
value = arg.value_two().unwrap_or(0);
}
let cond = ScmpArgCompare::new(arg.index() as u32, op, value);
conditions.push(cond);
}
Ok(conditions)
}
-
命名空间操作:
rustjail
管理 Linux 命名空间,提供隔离的运行环境。这包括 IPC、UTS、PID 等命名空间的创建和管理。
-
挂载管理:
- 容器启动时,
rustjail
负责设置和管理文件系统挂载点。这包括将宿主机的特定目录或设备挂载到容器的文件系统中。 - 例如,
mount.rs
文件中的mount_from
和check_proc_mount
函数用于处理挂载点的安全性和配置。
- 容器启动时,
mount(None::<&str>, "/", None::<&str>, flags, None::<&str>)?;
rootfs_parent_mount_private(rootfs)?;
mount(
Some(rootfs),
rootfs,
None::<&str>,
MsFlags::MS_BIND | MsFlags::MS_REC,
None::<&str>,
)?;
let mut bind_mount_dev = false;
let default_mnts = vec![];
for m in spec.mounts().as_ref().unwrap_or(&default_mnts) {
let (mut flags, pgflags, data) = parse_mount(m);
let mount_dest = &m.destination().display().to_string();
if !mount_dest.starts_with('/') || mount_dest.contains("..") {
return Err(anyhow!("the mount destination {} is invalid", mount_dest));
}
// From https://github.com/opencontainers/runtime-spec/blob/main/config.md#mounts
// type (string, OPTIONAL) The type of the filesystem to be mounted.
// bind may be only specified in the oci spec options -> flags update r#type
let m = &{
let mut mbind = m.clone();
if mbind.typ().is_none() && flags & MsFlags::MS_BIND == MsFlags::MS_BIND {
mbind.set_typ(Some("bind".to_string()));
}
mbind
};
let default_typ = String::new();
let mount_typ = m.typ().as_ref().unwrap_or(&default_typ);
if mount_typ == "cgroup" {
mount_cgroups(cfd_log, m, rootfs, flags, &data, cpath, mounts)?;
} else {
if mount_dest.clone().as_str() == "/dev" {
if mount_typ == "bind" {
bind_mount_dev = true;
}
flags &= !MsFlags::MS_RDONLY;
}
if mount_typ == "bind" {
check_proc_mount(m)?;
}
- 同步机制:
- 在容器的创建和管理过程中,
rustjail
使用同步机制来确保操作的正确性和顺序。这涉及到进程间的通信和状态同步。 - 例如,
read_sync
和write_sync
函数用于在不同阶段同步容器状态。
- 在容器的创建和管理过程中,
pub fn read_sync(fd: RawFd) -> Result<Vec<u8>> {
let buf = read_count(fd, MSG_SIZE)?;
if buf.len() != MSG_SIZE {
return Err(anyhow!(
"process: {} failed to receive sync message from peer: got msg length: {}, expected: {}",
std::process::id(),
buf.len(),
MSG_SIZE
));
}
let buf_array: [u8; MSG_SIZE] = [buf[0], buf[1], buf[2], buf[3]];
let msg: i32 = i32::from_be_bytes(buf_array);
match msg {
SYNC_SUCCESS => Ok(Vec::new()),
SYNC_DATA => {
let buf = read_count(fd, MSG_SIZE)?;
let buf_array: [u8; MSG_SIZE] = [buf[0], buf[1], buf[2], buf[3]];
let msg_length: i32 = i32::from_be_bytes(buf_array);
let data_buf = read_count(fd, msg_length as usize)?;
Ok(data_buf)
}
SYNC_FAILED => {
let mut error_buf = vec![];
loop {
let buf = read_count(fd, DATA_SIZE)?;
error_buf.extend(&buf);
if DATA_SIZE == buf.len() {
continue;
} else {
break;
}
}
let error_str = match std::str::from_utf8(&error_buf) {
Ok(v) => String::from(v),
Err(e) => {
return Err(
anyhow!(e).context("receive error message from child process failed")
);
}
};
Err(anyhow!(error_str))
}
_ => Err(anyhow!("error in receive sync message")),
}
}
pub fn write_sync(fd: RawFd, msg_type: i32, data_str: &str) -> Result<()> {
let buf = msg_type.to_be_bytes();
let count = write_count(fd, &buf, MSG_SIZE)?;
if count != MSG_SIZE {
return Err(anyhow!("error in send sync message"));
}
总结
rustjail
是 Kata 容器代理的核心组件之一,它利用多种 Linux 安全和隔离技术来确保容器的安全运行。通过这些机制,rustjail
能够有效地隔离容器环境,防止恶意行为和系统漏洞的利用,同时提供必要的操作和配置接口来满足不同的运行时需求。