Skip to content

Commit dea14fc

Browse files
committed
feat(vmm): add vendor check of CPU template
Check whether the vendor is matched between the static CPU template and the actual CPU. Static CPU templates for x86-64 are specific to vendor (Intel or AMD). `include_leaves_from()` method does this check now, but will be removed in a successive commit. Instead of this method, we do this check in `get_cpu_template()`. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent 2197b78 commit dea14fc

File tree

3 files changed

+110
-38
lines changed

3 files changed

+110
-38
lines changed

src/vmm/src/guest_config/templates/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ pub use common_types::*;
3434
/// Error for GetCpuTemplate trait.
3535
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
3636
pub enum GetCpuTemplateError {
37+
#[cfg(target_arch = "x86_64")]
38+
/// Failed to get CPU vendor information.
39+
#[error("Failed to get CPU vendor information: {0}")]
40+
GetCpuVendor(crate::guest_config::cpuid::common::GetCpuidError),
41+
/// CPU Vendor mismatched between the actual CPU and CPU template.
42+
#[error("CPU vendor mismatched between actual CPU and CPU template.")]
43+
CpuVendorMismatched,
3744
/// Invalid static CPU template.
3845
#[error("Invalid static CPU template: {0}")]
3946
InvalidStaticCpuTemplate(StaticCpuTemplate),

src/vmm/src/guest_config/templates/x86_64.rs

+102-35
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,56 @@ use serde::de::Error as SerdeError;
1111
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1212

1313
use super::{CpuTemplateType, GetCpuTemplate, GetCpuTemplateError, StaticCpuTemplate};
14+
use crate::guest_config::cpuid::common::get_vendor_id_from_host;
1415
use crate::guest_config::cpuid::cpuid_ffi::KvmCpuidFlags;
16+
use crate::guest_config::cpuid::{VENDOR_ID_AMD, VENDOR_ID_INTEL};
1517
use crate::guest_config::x86_64::static_cpu_templates_new::{c3, t2, t2a, t2cl, t2s};
1618

1719
impl GetCpuTemplate for Option<CpuTemplateType> {
1820
fn get_cpu_template(&self) -> Result<Cow<CustomCpuTemplate>, GetCpuTemplateError> {
21+
use GetCpuTemplateError::*;
22+
1923
match self {
2024
Some(template_type) => match template_type {
2125
CpuTemplateType::Custom(template) => Ok(Cow::Borrowed(template)),
22-
CpuTemplateType::Static(template) => match template {
23-
StaticCpuTemplate::C3 => Ok(Cow::Owned(c3::c3())),
24-
StaticCpuTemplate::T2 => Ok(Cow::Owned(t2::t2())),
25-
StaticCpuTemplate::T2S => Ok(Cow::Owned(t2s::t2s())),
26-
StaticCpuTemplate::T2CL => Ok(Cow::Owned(t2cl::t2cl())),
27-
StaticCpuTemplate::T2A => Ok(Cow::Owned(t2a::t2a())),
28-
StaticCpuTemplate::None => Err(GetCpuTemplateError::InvalidStaticCpuTemplate(
29-
StaticCpuTemplate::None,
30-
)),
31-
},
26+
CpuTemplateType::Static(template) => {
27+
let vendor_id = get_vendor_id_from_host().map_err(GetCpuVendor)?;
28+
match template {
29+
StaticCpuTemplate::C3 => {
30+
if &vendor_id != VENDOR_ID_INTEL {
31+
return Err(CpuVendorMismatched);
32+
}
33+
Ok(Cow::Owned(c3::c3()))
34+
}
35+
StaticCpuTemplate::T2 => {
36+
if &vendor_id != VENDOR_ID_INTEL {
37+
return Err(CpuVendorMismatched);
38+
}
39+
Ok(Cow::Owned(t2::t2()))
40+
}
41+
StaticCpuTemplate::T2S => {
42+
if &vendor_id != VENDOR_ID_INTEL {
43+
return Err(CpuVendorMismatched);
44+
}
45+
Ok(Cow::Owned(t2s::t2s()))
46+
}
47+
StaticCpuTemplate::T2CL => {
48+
if &vendor_id != VENDOR_ID_INTEL {
49+
return Err(CpuVendorMismatched);
50+
}
51+
Ok(Cow::Owned(t2cl::t2cl()))
52+
}
53+
StaticCpuTemplate::T2A => {
54+
if &vendor_id != VENDOR_ID_AMD {
55+
return Err(CpuVendorMismatched);
56+
}
57+
Ok(Cow::Owned(t2a::t2a()))
58+
}
59+
StaticCpuTemplate::None => {
60+
Err(InvalidStaticCpuTemplate(StaticCpuTemplate::None))
61+
}
62+
}
63+
}
3264
},
3365
None => Ok(Cow::Owned(CustomCpuTemplate::default())),
3466
}
@@ -478,56 +510,91 @@ mod tests {
478510
#[test]
479511
fn test_get_cpu_template_with_c3_static_template() {
480512
// Test `get_cpu_template()` when C3 static CPU template is specified. The owned
481-
// `CustomCpuTemplate` should be returned.
513+
// `CustomCpuTemplate` should be returned if CPU vendor is Intel. Otherwise, it should fail.
482514
let cpu_template = Some(CpuTemplateType::Static(StaticCpuTemplate::C3));
483-
assert_eq!(
484-
cpu_template.get_cpu_template().unwrap(),
485-
Cow::Owned(c3::c3())
486-
);
515+
if &get_vendor_id_from_host().unwrap() == VENDOR_ID_INTEL {
516+
assert_eq!(
517+
cpu_template.get_cpu_template().unwrap(),
518+
Cow::Owned(c3::c3())
519+
);
520+
} else {
521+
assert_eq!(
522+
cpu_template.get_cpu_template().unwrap_err(),
523+
GetCpuTemplateError::CpuVendorMismatched,
524+
);
525+
}
487526
}
488527

489528
#[test]
490529
fn test_get_cpu_template_with_t2_static_template() {
491530
// Test `get_cpu_template()` when T2 static CPU template is specified. The owned
492-
// `CustomCpuTemplate` should be returned.
531+
// `CustomCpuTemplate` should be returned if CPU vendor is Intel. Otherwise, it should fail.
493532
let cpu_template = Some(CpuTemplateType::Static(StaticCpuTemplate::T2));
494-
assert_eq!(
495-
cpu_template.get_cpu_template().unwrap(),
496-
Cow::Owned(t2::t2())
497-
);
533+
if &get_vendor_id_from_host().unwrap() == VENDOR_ID_INTEL {
534+
assert_eq!(
535+
cpu_template.get_cpu_template().unwrap(),
536+
Cow::Owned(t2::t2())
537+
);
538+
} else {
539+
assert_eq!(
540+
cpu_template.get_cpu_template().unwrap_err(),
541+
GetCpuTemplateError::CpuVendorMismatched,
542+
);
543+
}
498544
}
499545

500546
#[test]
501547
fn test_get_cpu_template_with_t2s_static_template() {
502548
// Test `get_cpu_template()` when T2S static CPU template is specified. The owned
503-
// `CustomCpuTemplate` should be returned.
549+
// `CustomCpuTemplate` should be returned if CPU vendor is Intel. Otherwise, it should fail.
504550
let cpu_template = Some(CpuTemplateType::Static(StaticCpuTemplate::T2S));
505-
assert_eq!(
506-
cpu_template.get_cpu_template().unwrap(),
507-
Cow::Owned(t2s::t2s())
508-
);
551+
if &get_vendor_id_from_host().unwrap() == VENDOR_ID_INTEL {
552+
assert_eq!(
553+
cpu_template.get_cpu_template().unwrap(),
554+
Cow::Owned(t2s::t2s())
555+
);
556+
} else {
557+
assert_eq!(
558+
cpu_template.get_cpu_template().unwrap_err(),
559+
GetCpuTemplateError::CpuVendorMismatched,
560+
);
561+
}
509562
}
510563

511564
#[test]
512565
fn test_get_cpu_template_with_t2cl_static_template() {
513566
// Test `get_cpu_template()` when T2CL static CPU template is specified. The owned
514-
// `CustomCpuTemplate` should be returned.
567+
// `CustomCpuTemplate` should be returned if CPU vendor is Intel. Otherwise, it should fail.
515568
let cpu_template = Some(CpuTemplateType::Static(StaticCpuTemplate::T2CL));
516-
assert_eq!(
517-
cpu_template.get_cpu_template().unwrap(),
518-
Cow::Owned(t2cl::t2cl())
519-
);
569+
if &get_vendor_id_from_host().unwrap() == VENDOR_ID_INTEL {
570+
assert_eq!(
571+
cpu_template.get_cpu_template().unwrap(),
572+
Cow::Owned(t2cl::t2cl())
573+
);
574+
} else {
575+
assert_eq!(
576+
cpu_template.get_cpu_template().unwrap_err(),
577+
GetCpuTemplateError::CpuVendorMismatched,
578+
);
579+
}
520580
}
521581

522582
#[test]
523583
fn test_get_cpu_template_with_t2a_static_template() {
524584
// Test `get_cpu_template()` when T2A static CPU template is specified. The owned
525-
// `CustomCpuTemplate` should be returned.
585+
// `CustomCpuTemplate` should be returned if CPU vendor is AMD. Otherwise it should fail.
526586
let cpu_template = Some(CpuTemplateType::Static(StaticCpuTemplate::T2A));
527-
assert_eq!(
528-
cpu_template.get_cpu_template().unwrap(),
529-
Cow::Owned(t2a::t2a())
530-
);
587+
if &get_vendor_id_from_host().unwrap() == VENDOR_ID_AMD {
588+
assert_eq!(
589+
cpu_template.get_cpu_template().unwrap(),
590+
Cow::Owned(t2a::t2a())
591+
);
592+
} else {
593+
assert_eq!(
594+
cpu_template.get_cpu_template().unwrap_err(),
595+
GetCpuTemplateError::CpuVendorMismatched,
596+
);
597+
}
531598
}
532599

533600
#[test]

tests/integration_tests/functional/test_api.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,7 @@ def test_api_machine_config(test_microvm_with_api):
476476
response = test_microvm.actions.put(action_type="InstanceStart")
477477
if utils.get_cpu_vendor() == utils.CpuVendor.AMD:
478478
# We shouldn't be able to apply Intel templates on AMD hosts
479-
fail_msg = (
480-
"Unable to successfully create cpu configuration usable for guest vCPUs:"
481-
)
479+
fail_msg = "CPU vendor mismatched between actual CPU and CPU template"
482480
assert test_microvm.api_session.is_status_bad_request(response.status_code)
483481
assert fail_msg in response.text
484482
else:

0 commit comments

Comments
 (0)