mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Introduce ApplyLandlock trait
Introduce ApplyLandlock trait and add implementations to VmConfig elements with PathBufs. This trait adds config specific rules to landlock ruleset. Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
This commit is contained in:
committed by
Liu Wei
parent
1dd53c3d24
commit
b3e5738b40
@@ -26,6 +26,10 @@ pub enum LandlockError {
|
|||||||
/// Invalid Landlock access
|
/// Invalid Landlock access
|
||||||
#[error("Invalid Landlock access: {0}")]
|
#[error("Invalid Landlock access: {0}")]
|
||||||
InvalidLandlockAccess(String),
|
InvalidLandlockAccess(String),
|
||||||
|
|
||||||
|
/// Invalid Path
|
||||||
|
#[error("Invalid path")]
|
||||||
|
InvalidPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.rs/landlock/latest/landlock/enum.ABI.html for more info on ABI
|
// https://docs.rs/landlock/latest/landlock/enum.ABI.html for more info on ABI
|
||||||
|
|||||||
@@ -2,11 +2,20 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
use crate::{landlock::LandlockError, Landlock};
|
||||||
use net_util::MacAddr;
|
use net_util::MacAddr;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{net::Ipv4Addr, path::PathBuf};
|
use std::{fs, net::Ipv4Addr, path::PathBuf, result};
|
||||||
use virtio_devices::RateLimiterConfig;
|
use virtio_devices::RateLimiterConfig;
|
||||||
|
|
||||||
|
pub type LandlockResult<T> = result::Result<T, LandlockError>;
|
||||||
|
|
||||||
|
/// Trait to apply Landlock on VmConfig elements
|
||||||
|
pub(crate) trait ApplyLandlock {
|
||||||
|
/// Apply Landlock rules to file paths
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct CpuAffinity {
|
pub struct CpuAffinity {
|
||||||
pub vcpu: u8,
|
pub vcpu: u8,
|
||||||
@@ -132,6 +141,15 @@ pub struct MemoryZoneConfig {
|
|||||||
pub prefault: bool,
|
pub prefault: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for MemoryZoneConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
if let Some(file) = &self.file {
|
||||||
|
landlock.add_rule_with_access(file.to_path_buf(), "rw")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||||
pub enum HotplugMethod {
|
pub enum HotplugMethod {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -245,6 +263,15 @@ pub struct DiskConfig {
|
|||||||
pub queue_affinity: Option<Vec<VirtQueueAffinity>>,
|
pub queue_affinity: Option<Vec<VirtQueueAffinity>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for DiskConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
if let Some(path) = &self.path {
|
||||||
|
landlock.add_rule_with_access(path.to_path_buf(), "rw")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
|
pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
|
||||||
|
|
||||||
pub fn default_diskconfig_num_queues() -> usize {
|
pub fn default_diskconfig_num_queues() -> usize {
|
||||||
@@ -378,6 +405,14 @@ impl Default for RngConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for RngConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
// Rng Path only need read access
|
||||||
|
landlock.add_rule_with_access(self.src.to_path_buf(), "r")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct BalloonConfig {
|
pub struct BalloonConfig {
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
@@ -411,6 +446,13 @@ pub fn default_fsconfig_queue_size() -> u16 {
|
|||||||
1024
|
1024
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for FsConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.socket.to_path_buf(), "rw")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct PmemConfig {
|
pub struct PmemConfig {
|
||||||
pub file: PathBuf,
|
pub file: PathBuf,
|
||||||
@@ -426,6 +468,13 @@ pub struct PmemConfig {
|
|||||||
pub pci_segment: u16,
|
pub pci_segment: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for PmemConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.file.to_path_buf(), "rw")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub enum ConsoleOutputMode {
|
pub enum ConsoleOutputMode {
|
||||||
Off,
|
Off,
|
||||||
@@ -450,6 +499,18 @@ pub fn default_consoleconfig_file() -> Option<PathBuf> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for ConsoleConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
if let Some(file) = &self.file {
|
||||||
|
landlock.add_rule_with_access(file.to_path_buf(), "rw")?;
|
||||||
|
}
|
||||||
|
if let Some(socket) = &self.socket {
|
||||||
|
landlock.add_rule_with_access(socket.to_path_buf(), "rw")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct DebugConsoleConfig {
|
pub struct DebugConsoleConfig {
|
||||||
@@ -470,6 +531,15 @@ impl Default for DebugConsoleConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
impl ApplyLandlock for DebugConsoleConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
if let Some(file) = &self.file {
|
||||||
|
landlock.add_rule_with_access(file.to_path_buf(), "rw")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct DeviceConfig {
|
pub struct DeviceConfig {
|
||||||
@@ -484,6 +554,22 @@ pub struct DeviceConfig {
|
|||||||
pub x_nv_gpudirect_clique: Option<u8>,
|
pub x_nv_gpudirect_clique: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for DeviceConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
let device_path = fs::read_link(self.path.as_path()).map_err(LandlockError::OpenPath)?;
|
||||||
|
let iommu_group = device_path.file_name();
|
||||||
|
let iommu_group_str = iommu_group
|
||||||
|
.ok_or(LandlockError::InvalidPath)?
|
||||||
|
.to_str()
|
||||||
|
.ok_or(LandlockError::InvalidPath)?;
|
||||||
|
|
||||||
|
let vfio_group_path = "/dev/vfio/".to_owned() + iommu_group_str;
|
||||||
|
landlock.add_rule_with_access(vfio_group_path.into(), "rw")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct UserDeviceConfig {
|
pub struct UserDeviceConfig {
|
||||||
pub socket: PathBuf,
|
pub socket: PathBuf,
|
||||||
@@ -493,6 +579,13 @@ pub struct UserDeviceConfig {
|
|||||||
pub pci_segment: u16,
|
pub pci_segment: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for UserDeviceConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.socket.to_path_buf(), "rw")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct VdpaConfig {
|
pub struct VdpaConfig {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
@@ -510,6 +603,13 @@ pub fn default_vdpaconfig_num_queues() -> usize {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for VdpaConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.path.to_path_buf(), "rw")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct VsockConfig {
|
pub struct VsockConfig {
|
||||||
pub cid: u32,
|
pub cid: u32,
|
||||||
@@ -522,6 +622,13 @@ pub struct VsockConfig {
|
|||||||
pub pci_segment: u16,
|
pub pci_segment: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for VsockConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.socket.to_path_buf(), "rw")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct SgxEpcConfig {
|
pub struct SgxEpcConfig {
|
||||||
@@ -575,6 +682,30 @@ pub struct PayloadConfig {
|
|||||||
pub host_data: Option<String>,
|
pub host_data: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for PayloadConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
// Payload only needs read access
|
||||||
|
if let Some(firmware) = &self.firmware {
|
||||||
|
landlock.add_rule_with_access(firmware.to_path_buf(), "r")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(kernel) = &self.kernel {
|
||||||
|
landlock.add_rule_with_access(kernel.to_path_buf(), "r")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(initramfs) = &self.initramfs {
|
||||||
|
landlock.add_rule_with_access(initramfs.to_path_buf(), "r")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "igvm")]
|
||||||
|
if let Some(igvm) = &self.igvm {
|
||||||
|
landlock.add_rule_with_access(igvm.to_path_buf(), "r")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn default_serial() -> ConsoleConfig {
|
pub fn default_serial() -> ConsoleConfig {
|
||||||
ConsoleConfig {
|
ConsoleConfig {
|
||||||
file: None,
|
file: None,
|
||||||
@@ -598,12 +729,26 @@ pub struct TpmConfig {
|
|||||||
pub socket: PathBuf,
|
pub socket: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for TpmConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.socket.to_path_buf(), "rw")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct LandlockConfig {
|
pub struct LandlockConfig {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub access: String,
|
pub access: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for LandlockConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
landlock.add_rule_with_access(self.path.to_path_buf(), self.access.clone().as_str())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct VmConfig {
|
pub struct VmConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -655,3 +800,90 @@ pub struct VmConfig {
|
|||||||
pub landlock_enable: bool,
|
pub landlock_enable: bool,
|
||||||
pub landlock_config: Option<Vec<LandlockConfig>>,
|
pub landlock_config: Option<Vec<LandlockConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VmConfig {
|
||||||
|
pub fn apply_landlock(&self) -> LandlockResult<()> {
|
||||||
|
let mut landlock = Landlock::new()?;
|
||||||
|
|
||||||
|
if let Some(mem_zones) = &self.memory.zones {
|
||||||
|
for zone in mem_zones.iter() {
|
||||||
|
zone.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let disks = &self.disks;
|
||||||
|
if let Some(disks) = disks {
|
||||||
|
for disk in disks.iter() {
|
||||||
|
disk.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.rng.apply_landlock(&mut landlock)?;
|
||||||
|
|
||||||
|
if let Some(fs_configs) = &self.fs {
|
||||||
|
for fs_config in fs_configs.iter() {
|
||||||
|
fs_config.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pmem_configs) = &self.pmem {
|
||||||
|
for pmem_config in pmem_configs.iter() {
|
||||||
|
pmem_config.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.console.apply_landlock(&mut landlock)?;
|
||||||
|
self.serial.apply_landlock(&mut landlock)?;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
{
|
||||||
|
self.debug_console.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(devices) = &self.devices {
|
||||||
|
landlock.add_rule_with_access("/dev/vfio/vfio".into(), "rw")?;
|
||||||
|
|
||||||
|
for device in devices.iter() {
|
||||||
|
device.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(user_devices) = &self.user_devices {
|
||||||
|
for user_devices in user_devices.iter() {
|
||||||
|
user_devices.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(vdpa_configs) = &self.vdpa {
|
||||||
|
for vdpa_config in vdpa_configs.iter() {
|
||||||
|
vdpa_config.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(vsock_config) = &self.vsock {
|
||||||
|
vsock_config.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(payload) = &self.payload {
|
||||||
|
payload.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tpm_config) = &self.tpm {
|
||||||
|
tpm_config.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.net.is_some() {
|
||||||
|
landlock.add_rule_with_access("/dev/net/tun".into(), "rw")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(landlock_configs) = &self.landlock_config {
|
||||||
|
for landlock_config in landlock_configs.iter() {
|
||||||
|
landlock_config.apply_landlock(&mut landlock)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
landlock.restrict_self()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user