mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-19 00:17:54 +00:00
Merge 3d326df628
into 9379a18c8a
This commit is contained in:
commit
1fde5bdc90
@ -934,6 +934,10 @@ pub struct SecurityInfo {
|
||||
rename = "tdx_quote_generation_service_socket_port"
|
||||
)]
|
||||
pub qgs_port: u32,
|
||||
|
||||
/// selinux_label defines SELinux label for the guest
|
||||
#[serde(default)]
|
||||
pub selinux_label: Option<String>,
|
||||
}
|
||||
|
||||
fn default_qgs_port() -> u32 {
|
||||
@ -1251,12 +1255,20 @@ pub struct Hypervisor {
|
||||
/// Disable applying SELinux on the container process.
|
||||
#[serde(default = "yes")]
|
||||
pub disable_guest_selinux: bool,
|
||||
|
||||
/// Disable applying SELinux on the VMM process.
|
||||
#[serde(default = "no")]
|
||||
pub disable_selinux: bool,
|
||||
}
|
||||
|
||||
fn yes() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn no() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
impl Hypervisor {
|
||||
/// Validate path of hypervisor executable.
|
||||
pub fn validate_hypervisor_path<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
|
@ -531,7 +531,7 @@ impl CloudHypervisorInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, netns: Option<String>) -> Result<()> {
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, netns: Option<String>, _selinux_label: Option<String>) -> Result<()> {
|
||||
self.id = id.to_string();
|
||||
self.state = VmmState::NotReady;
|
||||
|
||||
|
@ -65,9 +65,10 @@ impl Hypervisor for CloudHypervisor {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
_annotations: &HashMap<String, String>,
|
||||
selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.prepare_vm(id, netns).await
|
||||
inner.prepare_vm(id, netns, selinux_label).await
|
||||
}
|
||||
|
||||
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||
};
|
||||
|
||||
impl DragonballInner {
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, netns: Option<String>) -> Result<()> {
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, netns: Option<String>, _selinux_label: Option<String>) -> Result<()> {
|
||||
self.id = id.to_string();
|
||||
self.state = VmmState::NotReady;
|
||||
|
||||
|
@ -75,9 +75,10 @@ impl Hypervisor for Dragonball {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
_annotations: &HashMap<String, String>,
|
||||
selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.prepare_vm(id, netns).await
|
||||
inner.prepare_vm(id, netns, selinux_label).await
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
|
@ -19,7 +19,7 @@ pub const ROOT: &str = "root";
|
||||
const HYBRID_VSOCK_SCHEME: &str = "hvsock";
|
||||
|
||||
impl FcInner {
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, _netns: Option<String>) -> Result<()> {
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, _netns: Option<String>, _selinux_label: Option<String>) -> Result<()> {
|
||||
debug!(sl(), "Preparing Firecracker");
|
||||
|
||||
self.id = id.to_string();
|
||||
|
@ -64,9 +64,10 @@ impl Hypervisor for Firecracker {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
_annotations: &HashMap<String, String>,
|
||||
selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.prepare_vm(id, netns).await
|
||||
inner.prepare_vm(id, netns, selinux_label).await
|
||||
}
|
||||
|
||||
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||
|
@ -18,6 +18,7 @@ pub mod dragonball;
|
||||
pub mod firecracker;
|
||||
mod kernel_param;
|
||||
pub mod qemu;
|
||||
pub mod selinux;
|
||||
pub mod remote;
|
||||
pub use kernel_param::Param;
|
||||
pub mod utils;
|
||||
@ -103,6 +104,7 @@ pub trait Hypervisor: std::fmt::Debug + Send + Sync {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
annotations: &HashMap<String, String>,
|
||||
selinux_label: Option<String>,
|
||||
) -> Result<()>;
|
||||
async fn start_vm(&self, timeout: i32) -> Result<()>;
|
||||
async fn stop_vm(&self) -> Result<()>;
|
||||
|
@ -7,8 +7,8 @@ use super::cmdline_generator::{get_network_device, QemuCmdLine, QMP_SOCKET_FILE}
|
||||
use super::qmp::Qmp;
|
||||
use crate::device::topology::PCIePort;
|
||||
use crate::{
|
||||
device::driver::ProtectionDeviceConfig, hypervisor_persist::HypervisorState, HypervisorConfig,
|
||||
MemoryConfig, VcpuThreadIds, VsockDevice, HYPERVISOR_QEMU,
|
||||
device::driver::ProtectionDeviceConfig, hypervisor_persist::HypervisorState, selinux,
|
||||
HypervisorConfig, MemoryConfig, VcpuThreadIds, VsockDevice, HYPERVISOR_QEMU,
|
||||
};
|
||||
|
||||
use crate::utils::{bytes_to_megs, enter_netns, megs_to_bytes};
|
||||
@ -62,11 +62,24 @@ impl QemuInner {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, netns: Option<String>) -> Result<()> {
|
||||
pub(crate) async fn prepare_vm(
|
||||
&mut self,
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
info!(sl!(), "Preparing QEMU VM");
|
||||
self.id = id.to_string();
|
||||
self.netns = netns;
|
||||
|
||||
if !self.hypervisor_config().disable_selinux {
|
||||
if let Some(label) = selinux_label.as_ref() {
|
||||
self.config.security_info.selinux_label = Some(label.to_string());
|
||||
selinux::set_exec_label(&selinux_label.unwrap())
|
||||
.context("failed to set SELinux process label ")?;
|
||||
}
|
||||
}
|
||||
|
||||
let vm_path = [KATA_PATH, self.id.as_str()].join("/");
|
||||
std::fs::create_dir_all(vm_path)?;
|
||||
|
||||
@ -193,11 +206,23 @@ impl QemuInner {
|
||||
|
||||
info!(sl!(), "qemu cmd: {:?}", command);
|
||||
|
||||
// we need move the qemu process into Network Namespace.
|
||||
// we need move the qemu process into Network Namespace and set SELinux label.
|
||||
unsafe {
|
||||
let selinux_label = self.config.security_info.selinux_label.clone();
|
||||
let _pre_exec = command.pre_exec(move || {
|
||||
let _ = enter_netns(&netns);
|
||||
|
||||
if let Some(label) = selinux_label.as_ref() {
|
||||
if let Err(e) = selinux::set_exec_label(&label) {
|
||||
error!(sl!(), "Failed to set SELinux label in child process: {}", e);
|
||||
// Don't return error here to avoid breaking the process startup
|
||||
// Log the error and continue
|
||||
} else {
|
||||
info!(
|
||||
sl!(),
|
||||
"Successfully set SELinux label in child process: {}", &label
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
@ -58,9 +58,10 @@ impl Hypervisor for Qemu {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
_annotations: &HashMap<String, String>,
|
||||
selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.prepare_vm(id, netns).await
|
||||
inner.prepare_vm(id, netns, selinux_label).await
|
||||
}
|
||||
|
||||
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||
|
@ -146,6 +146,7 @@ impl RemoteInner {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
annotations: &HashMap<String, String>,
|
||||
_selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
info!(sl!(), "Preparing REMOTE VM");
|
||||
self.id = id.to_string();
|
||||
|
@ -48,9 +48,10 @@ impl Hypervisor for Remote {
|
||||
id: &str,
|
||||
netns: Option<String>,
|
||||
annotations: &HashMap<String, String>,
|
||||
_selinux_label: Option<String>,
|
||||
) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.prepare_vm(id, netns, annotations).await
|
||||
inner.prepare_vm(id, netns, annotations, _selinux_label).await
|
||||
}
|
||||
|
||||
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||
|
71
src/runtime-rs/crates/hypervisor/src/selinux.rs
Normal file
71
src/runtime-rs/crates/hypervisor/src/selinux.rs
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright 2024 The Kata Containers community
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use nix::unistd::gettid;
|
||||
|
||||
/// Check if SELinux is enabled on the system
|
||||
pub fn is_selinux_enabled() -> bool {
|
||||
let buf = match fs::read_to_string("/proc/mounts") {
|
||||
Ok(content) => content,
|
||||
Err(_) => return false,
|
||||
};
|
||||
buf.contains("selinuxfs")
|
||||
}
|
||||
|
||||
pub fn set_exec_label(label: &str) -> Result<()> {
|
||||
let mut attr_path = Path::new("/proc/thread-self/attr/exec").to_path_buf();
|
||||
if !attr_path.exists() {
|
||||
// Fall back to the old convention
|
||||
attr_path = Path::new("/proc/self/task")
|
||||
.join(gettid().to_string())
|
||||
.join("attr/exec")
|
||||
}
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(attr_path)?;
|
||||
file.write_all(label.as_bytes())
|
||||
.with_context(|| "failed to apply SELinux label")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const TEST_LABEL: &str = "system_u:system_r:unconfined_t:s0";
|
||||
|
||||
#[test]
|
||||
fn test_is_selinux_enabled() {
|
||||
let str = fs::read_to_string("/proc/mounts").unwrap();
|
||||
let expected = str.contains("selinuxfs");
|
||||
assert_eq!(is_selinux_enabled(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_exec_label() {
|
||||
let ret = set_exec_label(TEST_LABEL);
|
||||
if is_selinux_enabled() {
|
||||
assert!(ret.is_ok(), "Expecting Ok, Got {:?}", ret);
|
||||
// 检查 label 是否被正确设置
|
||||
let mut attr_path = std::path::Path::new("/proc/thread-self/attr/exec").to_path_buf();
|
||||
if !attr_path.exists() {
|
||||
attr_path = std::path::Path::new("/proc/self/task")
|
||||
.join(nix::unistd::gettid().to_string())
|
||||
.join("attr/exec");
|
||||
}
|
||||
let label = std::fs::read_to_string(attr_path).unwrap();
|
||||
assert_eq!(label.trim_end_matches('\0'), TEST_LABEL);
|
||||
} else {
|
||||
assert!(ret.is_err(), "Expecting error, Got {:?}", ret);
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||
use kata_types::config::hypervisor::HYPERVISOR_NAME_CH;
|
||||
use kata_types::config::TomlConfig;
|
||||
use kata_types::initdata::{calculate_initdata_digest, ProtectedPlatform};
|
||||
use kata_sys_util::spec::load_oci_spec;
|
||||
use oci_spec::runtime as oci;
|
||||
use persist::{self, sandbox_persist::Persist};
|
||||
use protobuf::SpecialFields;
|
||||
@ -510,12 +511,20 @@ impl Sandbox for VirtSandbox {
|
||||
warn!(sl!(), "sandbox is started");
|
||||
return Ok(());
|
||||
}
|
||||
let selinux_label = load_oci_spec()
|
||||
.ok()
|
||||
.and_then(|spec| {
|
||||
spec.process()
|
||||
.as_ref()
|
||||
.and_then(|process| process.selinux_label().clone())
|
||||
});
|
||||
|
||||
self.hypervisor
|
||||
.prepare_vm(
|
||||
id,
|
||||
sandbox_config.network_env.netns.clone(),
|
||||
&sandbox_config.annotations,
|
||||
selinux_label,
|
||||
)
|
||||
.await
|
||||
.context("prepare vm")?;
|
||||
|
Loading…
Reference in New Issue
Block a user