mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-11 14:24:11 +00:00
Merge pull request #6379 from cmaf/kata-ctl-check-kvm-1
kata-ctl: add generic kvm check & unit test
This commit is contained in:
commit
13f9ba2298
@ -13,7 +13,7 @@ mod arch_specific {
|
|||||||
use crate::check::{GuestProtection, ProtectionError};
|
use crate::check::{GuestProtection, ProtectionError};
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use nix::unistd::Uid;
|
use nix::unistd::Uid;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -41,6 +41,12 @@ mod arch_specific {
|
|||||||
fp: check_kernel_modules,
|
fp: check_kernel_modules,
|
||||||
perm: PermissionType::NonPrivileged,
|
perm: PermissionType::NonPrivileged,
|
||||||
},
|
},
|
||||||
|
CheckItem {
|
||||||
|
name: CheckType::KvmIsUsable,
|
||||||
|
descr: "This parameter performs check to see if KVM is usable",
|
||||||
|
fp: check_kvm_is_usable,
|
||||||
|
perm: PermissionType::Privileged,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
static MODULE_LIST: &[KernelModule] = &[
|
static MODULE_LIST: &[KernelModule] = &[
|
||||||
@ -114,6 +120,15 @@ mod arch_specific {
|
|||||||
utils::get_generic_cpu_details(check::PROC_CPUINFO)
|
utils::get_generic_cpu_details(check::PROC_CPUINFO)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if kvm is usable
|
||||||
|
fn check_kvm_is_usable(_args: &str) -> Result<()> {
|
||||||
|
println!("INFO: check if kvm is usable: x86_64");
|
||||||
|
|
||||||
|
let result = check::check_kvm_is_usable_generic();
|
||||||
|
|
||||||
|
result.context("KVM check failed")
|
||||||
|
}
|
||||||
|
|
||||||
pub const TDX_SYS_FIRMWARE_DIR: &str = "/sys/firmware/tdx_seam/";
|
pub const TDX_SYS_FIRMWARE_DIR: &str = "/sys/firmware/tdx_seam/";
|
||||||
pub const TDX_CPU_FLAG: &str = "tdx";
|
pub const TDX_CPU_FLAG: &str = "tdx";
|
||||||
pub const SEV_KVM_PARAMETER_PATH: &str = "/sys/module/kvm_amd/parameters/sev";
|
pub const SEV_KVM_PARAMETER_PATH: &str = "/sys/module/kvm_amd/parameters/sev";
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
// Contains checks that are not architecture-specific
|
// Contains checks that are not architecture-specific
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use nix::fcntl::{open, OFlag};
|
||||||
|
use nix::sys::stat::Mode;
|
||||||
|
use nix::unistd::close;
|
||||||
|
use nix::{ioctl_write_int_bad, request_code_none};
|
||||||
use reqwest::header::{CONTENT_TYPE, USER_AGENT};
|
use reqwest::header::{CONTENT_TYPE, USER_AGENT};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -176,6 +180,65 @@ pub fn run_network_checks() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set of basic checks for kvm. Architectures should implement more specific checks if needed
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn check_kvm_is_usable_generic() -> Result<()> {
|
||||||
|
// check for root user
|
||||||
|
if !nix::unistd::Uid::effective().is_root() {
|
||||||
|
return Err(anyhow!("Will not perform kvm checks as non root user"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// we do not want to create syscalls to any device besides /dev/kvm
|
||||||
|
const KVM_DEVICE: &str = "/dev/kvm";
|
||||||
|
|
||||||
|
// constants specific to kvm ioctls found in kvm.h
|
||||||
|
const KVM_IOCTL_ID: u8 = 0xAE;
|
||||||
|
const KVM_CREATE_VM: u8 = 0x01;
|
||||||
|
const KVM_GET_API_VERSION: u8 = 0x00;
|
||||||
|
// per kvm api documentation, this number should always be 12
|
||||||
|
// https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-get-api-version
|
||||||
|
const API_VERSION: i32 = 12;
|
||||||
|
|
||||||
|
// open kvm device
|
||||||
|
// since file is not being created, mode argument is not relevant
|
||||||
|
let mode = Mode::empty();
|
||||||
|
let flags = OFlag::O_RDWR | OFlag::O_CLOEXEC;
|
||||||
|
let fd = open(KVM_DEVICE, flags, mode)?;
|
||||||
|
|
||||||
|
// check kvm api version
|
||||||
|
ioctl_write_int_bad!(
|
||||||
|
kvm_api_version,
|
||||||
|
request_code_none!(KVM_IOCTL_ID, KVM_GET_API_VERSION)
|
||||||
|
);
|
||||||
|
// 0 is not used but required to produce output
|
||||||
|
let v = unsafe { kvm_api_version(fd, 0)? };
|
||||||
|
if v != API_VERSION {
|
||||||
|
return Err(anyhow!("KVM API version is not correct"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if you can create vm
|
||||||
|
ioctl_write_int_bad!(
|
||||||
|
kvm_create_vm,
|
||||||
|
request_code_none!(KVM_IOCTL_ID, KVM_CREATE_VM)
|
||||||
|
);
|
||||||
|
// 0 is default machine type
|
||||||
|
let vmfd = unsafe { kvm_create_vm(fd, 0) };
|
||||||
|
let _vmfd = match vmfd {
|
||||||
|
Ok(vm) => vm,
|
||||||
|
Err(ref error) if error.to_string() == "EBUSY: Device or resource busy" => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Another hypervisor is running. KVM_CREATE_VM error: {:?}",
|
||||||
|
error
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Err(error) => return Err(anyhow!("Other KVM_CREATE_VM error: {:?}", error)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = close(fd);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_kata_all_releases_by_url(url: &str) -> std::result::Result<Vec<Release>, reqwest::Error> {
|
fn get_kata_all_releases_by_url(url: &str) -> std::result::Result<Vec<Release>, reqwest::Error> {
|
||||||
let releases: Vec<Release> = reqwest::blocking::Client::new()
|
let releases: Vec<Release> = reqwest::blocking::Client::new()
|
||||||
.get(url)
|
.get(url)
|
||||||
@ -332,6 +395,7 @@ mod tests {
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
use test_utils::skip_if_root;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_single_cpu_info() {
|
fn test_get_single_cpu_info() {
|
||||||
@ -459,6 +523,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_kvm_is_usable_generic() {
|
||||||
|
skip_if_root!();
|
||||||
|
#[allow(dead_code)]
|
||||||
|
let result = check_kvm_is_usable_generic();
|
||||||
|
assert!(
|
||||||
|
result.err().unwrap().to_string() == "Will not perform kvm checks as non root user"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_kata_all_releases_by_url() {
|
fn test_get_kata_all_releases_by_url() {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -80,6 +80,9 @@ pub fn handle_check(checkcmd: CheckArgument) -> Result<()> {
|
|||||||
|
|
||||||
// run kernel module checks
|
// run kernel module checks
|
||||||
handle_builtin_check(CheckType::KernelModules, "")?;
|
handle_builtin_check(CheckType::KernelModules, "")?;
|
||||||
|
|
||||||
|
// run kvm checks
|
||||||
|
handle_builtin_check(CheckType::KvmIsUsable, "")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckSubCommand::NoNetworkChecks => {
|
CheckSubCommand::NoNetworkChecks => {
|
||||||
|
@ -15,6 +15,7 @@ pub enum CheckType {
|
|||||||
Cpu,
|
Cpu,
|
||||||
Network,
|
Network,
|
||||||
KernelModules,
|
KernelModules,
|
||||||
|
KvmIsUsable,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionType is used to show whether a check needs to run with elevated (super-user)
|
// PermissionType is used to show whether a check needs to run with elevated (super-user)
|
||||||
|
Loading…
Reference in New Issue
Block a user