diff --git a/intel-sgx/report-test/enclave/Makefile b/intel-sgx/report-test/enclave/Makefile index 0a27f5bcb..e1b30d3a3 100644 --- a/intel-sgx/report-test/enclave/Makefile +++ b/intel-sgx/report-test/enclave/Makefile @@ -1,4 +1,4 @@ -TOOLS_DIR ?= ../../target/debug +TOOLS_DIR ?= ../../../target/debug all: report.sgxs diff --git a/intel-sgx/sgx-isa/src/lib.rs b/intel-sgx/sgx-isa/src/lib.rs index 9ab812271..7649d1f11 100644 --- a/intel-sgx/sgx-isa/src/lib.rs +++ b/intel-sgx/sgx-isa/src/lib.rs @@ -385,13 +385,14 @@ bitflags! { #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct AttributesFlags: u64 { - const INIT = 0b0000_0001; - const DEBUG = 0b0000_0010; - const MODE64BIT = 0b0000_0100; - const PROVISIONKEY = 0b0001_0000; - const EINITTOKENKEY = 0b0010_0000; - const CET = 0b0100_0000; - const KSS = 0b1000_0000; + const INIT = 0b0000_0000_0001; + const DEBUG = 0b0000_0000_0010; + const MODE64BIT = 0b0000_0000_0100; + const PROVISIONKEY = 0b0000_0001_0000; + const EINITTOKENKEY = 0b0000_0010_0000; + const CET = 0b0000_0100_0000; + const KSS = 0b0000_1000_0000; + const AEXNOTIFY = 0b0100_0000_0000; } } @@ -444,7 +445,8 @@ impl Tcs { bitflags! { #[repr(C)] pub struct TcsFlags: u64 { - const DBGOPTIN = 0b0000_0001; + const DBGOPTIN = 0b0000_0001; + const AEXNOTIFY = 0b0000_0010; } } diff --git a/intel-sgx/sgxs-tools/src/bin/sgxs-build.rs b/intel-sgx/sgxs-tools/src/bin/sgxs-build.rs index a1895288f..8a88e5d91 100644 --- a/intel-sgx/sgxs-tools/src/bin/sgxs-build.rs +++ b/intel-sgx/sgxs-tools/src/bin/sgxs-build.rs @@ -10,7 +10,7 @@ extern crate sgxs as sgxs_crate; use std::fs::{self, File}; use std::io::stdout; -use sgx_isa::{PageType, SecinfoFlags, Tcs}; +use sgx_isa::{PageType, SecinfoFlags, Tcs, TcsFlags}; use crate::sgxs_crate::sgxs::{self, CanonicalSgxsWriter, SecinfoTruncated}; use crate::sgxs_crate::util::{size_fit_natural, size_fit_page}; @@ -22,6 +22,7 @@ enum Block { }, TcsSsa { nssa: u32, + flags: TcsFlags }, } use crate::Block::*; @@ -47,16 +48,23 @@ fn main() { let mut blocks = vec![]; for arg in args { let mut arg_split = arg.splitn(2, "="); - let (k, v) = match (arg_split.next(), arg_split.next(), arg_split.next()) { + let (k, mut v) = match (arg_split.next(), arg_split.next(), arg_split.next()) { (Some(k), Some(v), None) => (k, v), _ => panic!("Invalid argument: «{}»", arg), }; if k == "ssaframesize" { panic!("ssaframesize must be the first argument if specified"); } else if k == "tcs" { + const FLAGS_SUFFIX: &str = ",flags=aexnotify"; + let flags = if v.ends_with(FLAGS_SUFFIX) { + v = v.split_at(v.len() - FLAGS_SUFFIX.len()).0; + TcsFlags::AEXNOTIFY + } else { + TcsFlags::empty() + }; if v.starts_with("nssa:") { let nssa = v[5..].parse::().expect("nssa must be a number"); - blocks.push(TcsSsa { nssa: nssa }); + blocks.push(TcsSsa { nssa, flags }); } else { panic!("tcs must be specified as tcs=nssa:N"); } @@ -83,7 +91,7 @@ fn main() { .iter() .map(|block| match block { &Blob { pages, .. } => pages, - &TcsSsa { nssa } => 1 + ((nssa * ssaframesize) as usize), + &TcsSsa { nssa, .. } => 1 + ((nssa * ssaframesize) as usize), }) .fold(0, std::ops::Add::add); @@ -106,7 +114,7 @@ fn main() { .write_pages(Some(&mut File::open(file).unwrap()), pages, None, secinfo) .unwrap(); } - TcsSsa { nssa } => { + TcsSsa { nssa, flags } => { let tcs = Tcs { ossa: writer.offset() + 0x1000, nssa: nssa, @@ -115,6 +123,7 @@ fn main() { ogsbasgx: 0, fslimit: 0xfff, gslimit: 0xfff, + flags, ..Tcs::default() }; let tcs = unsafe { std::mem::transmute::<_, [u8; 4096]>(tcs) }; diff --git a/intel-sgx/sgxs-tools/src/sgx_detect/interpret.rs b/intel-sgx/sgxs-tools/src/sgx_detect/interpret.rs index bbaeb3278..a5401e18f 100644 --- a/intel-sgx/sgxs-tools/src/sgx_detect/interpret.rs +++ b/intel-sgx/sgxs-tools/src/sgx_detect/interpret.rs @@ -46,6 +46,9 @@ pub struct Cpuid12h0 { pub sgx2: bool, pub enclv: bool, pub oversub: bool, + pub everifyreport2: bool, + pub eupdatesvn: bool, + pub edeccssa: bool, #[serde(with = "serde::miscselect")] pub miscselect_valid: Miscselect, pub max_enclave_size_32: u64, @@ -60,6 +63,9 @@ impl From for Cpuid12h0 { sgx2: check_bit_erase_32(&mut v.eax, 1), enclv: check_bit_erase_32(&mut v.eax, 5), oversub: check_bit_erase_32(&mut v.eax, 6), + everifyreport2: check_bit_erase_32(&mut v.eax, 7), + eupdatesvn: check_bit_erase_32(&mut v.eax, 10), + edeccssa: check_bit_erase_32(&mut v.eax, 11), miscselect_valid: Miscselect::from_bits_truncate(v.ebx), max_enclave_size_32: 1 << (v.edx as u8), max_enclave_size_64: 1 << ((v.edx >> 8) as u8), diff --git a/intel-sgx/sgxs-tools/src/sgx_detect/tests/debug.rs b/intel-sgx/sgxs-tools/src/sgx_detect/tests/debug.rs index b494db1e5..333a44da4 100644 --- a/intel-sgx/sgxs-tools/src/sgx_detect/tests/debug.rs +++ b/intel-sgx/sgxs-tools/src/sgx_detect/tests/debug.rs @@ -21,6 +21,17 @@ impl DebugSupport for SgxCpuSupport { } } +impl DebugSupport for AexNotify { + fn debug(&self, mut out: debug::Output, _items: &DetectItemMap) -> fmt::Result { + let mut supported = "ENCLU[EDECCSSA] instruction"; + let mut unsupported = "AEXNOTIFY attribute"; + if self.aexnotify.unwrap_or(false) { + std::mem::swap(&mut supported, &mut unsupported); + } + writeln!(out, "Invalid AEX notify configuration: the {} is supported, but the {} isn't. This could indicate a CPU or hypervisor bug.", supported, unsupported) + } +} + impl DebugSupport for SgxCpuConfiguration { fn debug(&self, mut out: debug::Output, _items: &DetectItemMap) -> fmt::Result { let mut debug_msr = true; diff --git a/intel-sgx/sgxs-tools/src/sgx_detect/tests/mod.rs b/intel-sgx/sgxs-tools/src/sgx_detect/tests/mod.rs index d62537f8b..2281e7f5a 100644 --- a/intel-sgx/sgxs-tools/src/sgx_detect/tests/mod.rs +++ b/intel-sgx/sgxs-tools/src/sgx_detect/tests/mod.rs @@ -74,6 +74,8 @@ struct SgxCpuConfiguration { exinfo: bool, enclv: bool, oversub: bool, + edeccssa: bool, + eupdatesvn: bool, cpuid_err: Option>, msr_3ah: Result>, efi_epcbios: Result>, @@ -94,6 +96,8 @@ impl Dependency for SgxCpuConfiguration { let exinfo; let enclv; let oversub; + let edeccssa; + let eupdatesvn; let cpuid_err; match (v, &support.cpuid_12h_0) { @@ -105,6 +109,8 @@ impl Dependency for SgxCpuConfiguration { exinfo = c.miscselect_valid.contains(Miscselect::EXINFO); enclv = c.enclv; oversub = c.oversub; + edeccssa = c.edeccssa; + eupdatesvn = c.eupdatesvn; cpuid_err = if sgx1 { None } else { @@ -118,6 +124,8 @@ impl Dependency for SgxCpuConfiguration { exinfo = false; enclv = false; oversub = false; + edeccssa = false; + eupdatesvn = false; cpuid_err = Some(if sgx { cpuid12.as_ref().unwrap_err().clone() } else { @@ -133,6 +141,8 @@ impl Dependency for SgxCpuConfiguration { exinfo, enclv, oversub, + edeccssa, + eupdatesvn, cpuid_err, msr_3ah: support.msr_3ah.clone(), efi_epcbios: support.efi_epcbios.clone(), @@ -156,6 +166,7 @@ impl Print for SgxCpuConfiguration { struct EnclaveAttributes { standard_attributes: bool, kss: bool, + aexnotify: bool, cpuid_12h_1: Result>, } @@ -173,11 +184,13 @@ impl Dependency for EnclaveAttributes { | AttributesFlags::EINITTOKENKEY, ) && (c.attributes_xfrm_valid & 0x3) == 0x3, kss: c.attributes_flags_valid.contains(AttributesFlags::KSS), + aexnotify: c.attributes_flags_valid.contains(AttributesFlags::AEXNOTIFY), cpuid_12h_1: Ok(*c), }), (Some(_), c) => Some(EnclaveAttributesInner { standard_attributes: false, kss: false, + aexnotify: false, cpuid_12h_1: c.clone(), }), (None, _) => None, @@ -281,10 +294,44 @@ impl Print for EnclavePageCache { #[derive(Default, DebugSupport, Print, Update)] struct SgxFeaturesCat; +#[derive(Default, Clone, Update)] +struct AexNotify { + edeccssa: Option, + aexnotify: Option, +} + +impl Print for AexNotify { + fn try_supported(&self) -> Option { + match (self.edeccssa?, self.aexnotify?) { + (false, false) => None, + (true, true) => Some(Status::Supported), + _ => Some(Status::Unknown), + } + } + + fn print(&self, _level: usize) { + } +} + +#[dependency] +impl Dependency for AexNotify { + fn update_dependency(&mut self, dependency: &SgxCpuConfiguration, _support: &SgxSupport) { + self.edeccssa = dependency.inner.clone().map(|c| c.edeccssa); + } +} + +#[dependency] +impl Dependency for AexNotify { + fn update_dependency(&mut self, dependency: &EnclaveAttributes, _support: &SgxSupport) { + self.aexnotify = dependency.inner.clone().map(|a| a.aexnotify); + } +} + #[derive(Default, DebugSupport, Update)] struct SgxFeatures { cpu_cfg: Option, encl_attr: Option, + aexnotify: Option, } #[dependency] @@ -303,6 +350,13 @@ impl Dependency for SgxFeatures { } } +#[dependency] +impl Dependency for SgxFeatures { + fn update_dependency(&mut self, dependency: &AexNotify, _support: &SgxSupport) { + self.aexnotify = Some(dependency.clone()); + } +} + impl Print for SgxFeatures { // used for visibility control fn try_supported(&self) -> Option { @@ -325,10 +379,18 @@ impl Print for SgxFeatures { "{}OVERSUB ", self.cpu_cfg.as_ref().map(|c| c.oversub).as_opt().paint() ); - println!( + print!( "{}KSS ", self.encl_attr.as_ref().map(|a| a.kss).as_opt().paint() ); + print!( + "{}AEXNOTIFY ", + self.aexnotify.as_ref().and_then(|a| a.try_supported()).unwrap_or(Status::Unsupported).paint() + ); + println!( + "{}EUPDATESVN ", + self.cpu_cfg.as_ref().map(|c| c.eupdatesvn).as_opt().paint() + ); } } @@ -1079,6 +1141,7 @@ impl Tests { @[control_visibility] "SGX features" => Test(SgxFeatures), "Total EPC size" => Test(EpcSize), + "AEX notify" => Test(AexNotify), }), }), "Flexible launch control" => Category(Flc, tests: {