mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-19 08:28:19 +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"
|
rename = "tdx_quote_generation_service_socket_port"
|
||||||
)]
|
)]
|
||||||
pub qgs_port: u32,
|
pub qgs_port: u32,
|
||||||
|
|
||||||
|
/// selinux_label defines SELinux label for the guest
|
||||||
|
#[serde(default)]
|
||||||
|
pub selinux_label: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_qgs_port() -> u32 {
|
fn default_qgs_port() -> u32 {
|
||||||
@ -1251,12 +1255,20 @@ pub struct Hypervisor {
|
|||||||
/// Disable applying SELinux on the container process.
|
/// Disable applying SELinux on the container process.
|
||||||
#[serde(default = "yes")]
|
#[serde(default = "yes")]
|
||||||
pub disable_guest_selinux: bool,
|
pub disable_guest_selinux: bool,
|
||||||
|
|
||||||
|
/// Disable applying SELinux on the VMM process.
|
||||||
|
#[serde(default = "no")]
|
||||||
|
pub disable_selinux: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yes() -> bool {
|
fn yes() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn no() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
impl Hypervisor {
|
impl Hypervisor {
|
||||||
/// Validate path of hypervisor executable.
|
/// Validate path of hypervisor executable.
|
||||||
pub fn validate_hypervisor_path<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
pub fn validate_hypervisor_path<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||||
|
@ -531,7 +531,7 @@ impl CloudHypervisorInner {
|
|||||||
Ok(())
|
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.id = id.to_string();
|
||||||
self.state = VmmState::NotReady;
|
self.state = VmmState::NotReady;
|
||||||
|
|
||||||
|
@ -65,9 +65,10 @@ impl Hypervisor for CloudHypervisor {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
_annotations: &HashMap<String, String>,
|
_annotations: &HashMap<String, String>,
|
||||||
|
selinux_label: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut inner = self.inner.write().await;
|
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<()> {
|
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
impl DragonballInner {
|
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.id = id.to_string();
|
||||||
self.state = VmmState::NotReady;
|
self.state = VmmState::NotReady;
|
||||||
|
|
||||||
|
@ -75,9 +75,10 @@ impl Hypervisor for Dragonball {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
_annotations: &HashMap<String, String>,
|
_annotations: &HashMap<String, String>,
|
||||||
|
selinux_label: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut inner = self.inner.write().await;
|
let mut inner = self.inner.write().await;
|
||||||
inner.prepare_vm(id, netns).await
|
inner.prepare_vm(id, netns, selinux_label).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
|
@ -19,7 +19,7 @@ pub const ROOT: &str = "root";
|
|||||||
const HYBRID_VSOCK_SCHEME: &str = "hvsock";
|
const HYBRID_VSOCK_SCHEME: &str = "hvsock";
|
||||||
|
|
||||||
impl FcInner {
|
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");
|
debug!(sl(), "Preparing Firecracker");
|
||||||
|
|
||||||
self.id = id.to_string();
|
self.id = id.to_string();
|
||||||
|
@ -64,9 +64,10 @@ impl Hypervisor for Firecracker {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
_annotations: &HashMap<String, String>,
|
_annotations: &HashMap<String, String>,
|
||||||
|
selinux_label: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut inner = self.inner.write().await;
|
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<()> {
|
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||||
|
@ -18,6 +18,7 @@ pub mod dragonball;
|
|||||||
pub mod firecracker;
|
pub mod firecracker;
|
||||||
mod kernel_param;
|
mod kernel_param;
|
||||||
pub mod qemu;
|
pub mod qemu;
|
||||||
|
pub mod selinux;
|
||||||
pub mod remote;
|
pub mod remote;
|
||||||
pub use kernel_param::Param;
|
pub use kernel_param::Param;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
@ -103,6 +104,7 @@ pub trait Hypervisor: std::fmt::Debug + Send + Sync {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
annotations: &HashMap<String, String>,
|
annotations: &HashMap<String, String>,
|
||||||
|
selinux_label: Option<String>,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
async fn start_vm(&self, timeout: i32) -> Result<()>;
|
async fn start_vm(&self, timeout: i32) -> Result<()>;
|
||||||
async fn stop_vm(&self) -> 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 super::qmp::Qmp;
|
||||||
use crate::device::topology::PCIePort;
|
use crate::device::topology::PCIePort;
|
||||||
use crate::{
|
use crate::{
|
||||||
device::driver::ProtectionDeviceConfig, hypervisor_persist::HypervisorState, HypervisorConfig,
|
device::driver::ProtectionDeviceConfig, hypervisor_persist::HypervisorState, selinux,
|
||||||
MemoryConfig, VcpuThreadIds, VsockDevice, HYPERVISOR_QEMU,
|
HypervisorConfig, MemoryConfig, VcpuThreadIds, VsockDevice, HYPERVISOR_QEMU,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::utils::{bytes_to_megs, enter_netns, megs_to_bytes};
|
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");
|
info!(sl!(), "Preparing QEMU VM");
|
||||||
self.id = id.to_string();
|
self.id = id.to_string();
|
||||||
self.netns = netns;
|
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("/");
|
let vm_path = [KATA_PATH, self.id.as_str()].join("/");
|
||||||
std::fs::create_dir_all(vm_path)?;
|
std::fs::create_dir_all(vm_path)?;
|
||||||
|
|
||||||
@ -193,11 +206,23 @@ impl QemuInner {
|
|||||||
|
|
||||||
info!(sl!(), "qemu cmd: {:?}", command);
|
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 {
|
unsafe {
|
||||||
|
let selinux_label = self.config.security_info.selinux_label.clone();
|
||||||
let _pre_exec = command.pre_exec(move || {
|
let _pre_exec = command.pre_exec(move || {
|
||||||
let _ = enter_netns(&netns);
|
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(())
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -58,9 +58,10 @@ impl Hypervisor for Qemu {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
_annotations: &HashMap<String, String>,
|
_annotations: &HashMap<String, String>,
|
||||||
|
selinux_label: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut inner = self.inner.write().await;
|
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<()> {
|
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||||
|
@ -146,6 +146,7 @@ impl RemoteInner {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
annotations: &HashMap<String, String>,
|
annotations: &HashMap<String, String>,
|
||||||
|
_selinux_label: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!(sl!(), "Preparing REMOTE VM");
|
info!(sl!(), "Preparing REMOTE VM");
|
||||||
self.id = id.to_string();
|
self.id = id.to_string();
|
||||||
|
@ -48,9 +48,10 @@ impl Hypervisor for Remote {
|
|||||||
id: &str,
|
id: &str,
|
||||||
netns: Option<String>,
|
netns: Option<String>,
|
||||||
annotations: &HashMap<String, String>,
|
annotations: &HashMap<String, String>,
|
||||||
|
_selinux_label: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut inner = self.inner.write().await;
|
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<()> {
|
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::hypervisor::HYPERVISOR_NAME_CH;
|
||||||
use kata_types::config::TomlConfig;
|
use kata_types::config::TomlConfig;
|
||||||
use kata_types::initdata::{calculate_initdata_digest, ProtectedPlatform};
|
use kata_types::initdata::{calculate_initdata_digest, ProtectedPlatform};
|
||||||
|
use kata_sys_util::spec::load_oci_spec;
|
||||||
use oci_spec::runtime as oci;
|
use oci_spec::runtime as oci;
|
||||||
use persist::{self, sandbox_persist::Persist};
|
use persist::{self, sandbox_persist::Persist};
|
||||||
use protobuf::SpecialFields;
|
use protobuf::SpecialFields;
|
||||||
@ -510,12 +511,20 @@ impl Sandbox for VirtSandbox {
|
|||||||
warn!(sl!(), "sandbox is started");
|
warn!(sl!(), "sandbox is started");
|
||||||
return Ok(());
|
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
|
self.hypervisor
|
||||||
.prepare_vm(
|
.prepare_vm(
|
||||||
id,
|
id,
|
||||||
sandbox_config.network_env.netns.clone(),
|
sandbox_config.network_env.netns.clone(),
|
||||||
&sandbox_config.annotations,
|
&sandbox_config.annotations,
|
||||||
|
selinux_label,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("prepare vm")?;
|
.context("prepare vm")?;
|
||||||
|
Loading…
Reference in New Issue
Block a user