Skip to content

Commit

Permalink
Merge pull request #101 from Freax13/enhancement/multi-thread-supervisor
Browse files Browse the repository at this point in the history
move to multi-threaded supervisor for SNP
  • Loading branch information
Freax13 authored Dec 25, 2024
2 parents a5228ed + 1d64e3f commit d1f6709
Show file tree
Hide file tree
Showing 61 changed files with 1,859 additions and 1,650 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This kernel runs at VMPL 0 on AMD SEV-SNP and runs as the L1 VM on Intel TDX. It

The code running in the VM has been split up into two parts, the workload kernel and the supervisor kernel, to reduce the amount security relevant code. It should be sufficient to audit the supervisor kernels as the the workload kernel should never come into contact with untrusted data.

The supervisor kernels are the only component directly talking to the host. The supervisor kernels are intentionally kept small and is hardended against exploits. On AMD SEV-SNP, it is entirely single-threaded.
The supervisor kernels are the only component directly talking to the host. The supervisor kernels are intentionally kept small and is hardended against exploits.

The workload kernel cannot access host shared memory and even though it's in theory not impossible for it to communicate to the host through some side-channels, it should be very unlikely that the host can influence the code running in the workload kernel.

Expand Down
5 changes: 0 additions & 5 deletions common/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common/constants/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ pub const MEMORY_PORT: u16 = 0x1337;
pub const KICK_AP_PORT: u16 = 0x7331;
pub const SCHEDULE_PORT: u16 = 0x1373;
pub const HALT_PORT: u16 = 0x7313;
pub const INSECURE_SUPERVISOR_CALL_PORT: u16 = 0x17;
pub const MEMORY_MSR: u32 = 0x7000_0000;
pub const UPDATE_OUTPUT_MSR: u32 = 0x7000_0001;
pub const FINISH_OUTPUT_MSR: u32 = 0x7000_0002;
Expand Down
8 changes: 1 addition & 7 deletions common/constants/src/physical_address.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::ops::Range;

use x86_64::{
structures::paging::{PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB},
structures::paging::{PageSize, PhysFrame, Size1GiB, Size2MiB},
PhysAddr,
};

Expand Down Expand Up @@ -53,7 +53,6 @@ pub mod kernel {
pub const RODATA_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff800001000000);
pub const DATA_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff800002000000);
pub const STACK_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff800004000000);
pub const SUPERVISOR_SERVICES_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff800006000000);
pub const LOG_BUFFER_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff800007000000);
pub const INIT_FILE_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff809000000000);
pub const INPUT_FILE_SHADOW: PhysFrame<Size2MiB> = shadow_addr(0xffff80a000000000);
Expand Down Expand Up @@ -108,11 +107,6 @@ pub const INIT_FILE: Range<PhysFrame<Size1GiB>> =
addr_range(0x0000_0300_0000_0000, 0x0000_030f_ffff_ffff);
pub const INPUT_FILE: Range<PhysFrame<Size1GiB>> =
addr_range(0x0000_0400_0000_0000, 0x0000_040f_ffff_ffff);
/// A shared buffer between the kernel and the supervisor to store output
/// chunks.
pub const OUTPUT: PhysFrame<Size4KiB> = addr(0x50000000000);
pub const SUPERVISOR_SERVICES: Range<PhysFrame<Size4KiB>> =
addr_range(0x50000000000, 0x5000000ffff);

// Regions for kernel-guest communication during profiling.
pub const PROFILER_CONTROL: Range<PhysFrame<Size2MiB>> = addr_range(0x80000000000, 0x80000ffffff);
Expand Down
37 changes: 37 additions & 0 deletions common/snp-types/src/ghcb/msr_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ pub enum GhcbInfo {
SnpPageStateChangeResponse {
error_code: Option<NonZeroU32>,
},
SnpRunVmplRequest {
vmpl: u8,
},
SnpRunVmplResponse {
error_code: Option<NonZeroU32>,
},
HypervisorFeatureSupportRequest,
#[non_exhaustive]
HypervisorFeatureSupportResponse {
Expand Down Expand Up @@ -151,6 +157,19 @@ impl From<GhcbInfo> for u64 {
msr_value.set_bits(12..=31, 0); // Reserved, must be zero
msr_value.set_bits(32..=63, u64::from(error_code));
}
GhcbInfo::SnpRunVmplRequest { vmpl } => {
msr_value.set_bits(0..=11, 0x016); // GHCBInfo
msr_value.set_bits(12..=31, 0); // Reserved, must be zero
msr_value.set_bits(32..=39, u64::from(vmpl));
msr_value.set_bits(40..=63, 0); // Reserved, must be zero
}
GhcbInfo::SnpRunVmplResponse { error_code } => {
let error_code = error_code.map(NonZeroU32::get).unwrap_or(0);

msr_value.set_bits(0..=11, 0x017); // GHCBInfo
msr_value.set_bits(12..=31, 0); // Reserved, must be zero
msr_value.set_bits(32..=63, u64::from(error_code));
}
GhcbInfo::HypervisorFeatureSupportRequest => {
msr_value.set_bits(0..=11, 0x080); // GHCBInfo
msr_value.set_bits(12..=63, 0); // Reserved, must be zero
Expand Down Expand Up @@ -303,6 +322,24 @@ impl TryFrom<u64> for GhcbInfo {
let error_code = NonZeroU32::new(error_code);
Ok(Self::SnpPageStateChangeResponse { error_code })
}
0x016 => {
if msr_value.get_bits(12..=31) != 0 {
return Err(ParseError(()));
}
let vmpl = msr_value.get_bits(32..=39) as u8;
if msr_value.get_bits(40..=63) != 0 {
return Err(ParseError(()));
}
Ok(Self::SnpRunVmplRequest { vmpl })
}
0x017 => {
if msr_value.get_bits(12..=31) != 0 {
return Err(ParseError(()));
}
let error_code = msr_value.get_bits(32..=63) as u32;
let error_code = NonZeroU32::new(error_code);
Ok(Self::SnpRunVmplResponse { error_code })
}
0x080 => {
if msr_value.get_bits(12..=63) != 0 {
return Err(ParseError(()));
Expand Down
9 changes: 9 additions & 0 deletions common/snp-types/src/intercept.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
pub const VMEXIT_INTR: u64 = 0x60;
pub const VMEXIT_NMI: u64 = 0x61;
pub const VMEXIT_SMI: u64 = 0x62;
pub const VMEXIT_INIT: u64 = 0x63;
pub const VMEXIT_CPUID: u64 = 0x72;
pub const VMEXIT_PAUSE: u64 = 0x77;
pub const VMEXIT_IOIO: u64 = 0x7b;
pub const VMEXIT_MSR: u64 = 0x7c;
pub const VMEXIT_VMMCALL: u64 = 0x81;
pub const VMEXIT_NPF: u64 = 0x400;
pub const VMEXIT_VMGEXIT: u64 = 0x403;
// FIXME: This name is not official.
pub const VMEXIT_UNVALIDATED: u64 = 0x404;
pub const VMEXIT_INVALID: u64 = !0;
89 changes: 69 additions & 20 deletions common/snp-types/src/vmsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,57 @@ use core::{
mem::{offset_of, size_of},
};

macro_rules! vmsa_field_accessor {
($ident:ident: $ty:ty) => {
// Don't emit anything if $vis is empty (default -> private).
};
// Setters for these fields should be unsafe.
($vis:vis vmpl: $ty:ty) => { vmsa_field_unsafe_accessor!($vis vmpl: $ty); };
($vis:vis sev_features: $ty:ty) => { vmsa_field_unsafe_accessor!($vis sev_features: $ty); };
($vis:vis efer: $ty:ty) => { vmsa_field_unsafe_accessor!($vis efer: $ty); };
// Emit safe accessors for all other fields.
($vis:vis $ident:ident: $ty:ty) => { vmsa_field_safe_accessor!($vis $ident: $ty); };
}

macro_rules! vmsa_field_safe_accessor {
($vis:vis $ident:ident: $ty:ty) => {
paste! {
#[inline(always)]
$vis const fn $ident(&self, tweak_bitmap: &VmsaTweakBitmap) -> $ty {
let mut buffer = [0; size_of::<$ty>()];
self.read(offset_of!(Self, $ident), &mut buffer, tweak_bitmap);
unsafe { core::mem::transmute(buffer) }
}

#[inline(always)]
$vis const fn [<set_ $ident>](&mut self, value: $ty, tweak_bitmap: &VmsaTweakBitmap) {
let buffer: [u8; size_of::<$ty>()] = unsafe { core::mem::transmute(value) };
self.write(offset_of!(Self, $ident), &buffer, tweak_bitmap);
}
}
};
}

macro_rules! vmsa_field_unsafe_accessor {
($vis:vis $ident:ident: $ty:ty) => {
paste! {
#[inline(always)]
$vis const fn $ident(&self, tweak_bitmap: &VmsaTweakBitmap) -> $ty {
let mut buffer = [0; size_of::<$ty>()];
self.read(offset_of!(Self, $ident), &mut buffer, tweak_bitmap);
unsafe { core::mem::transmute(buffer) }
}

#[inline(always)]
#[allow(clippy::missing_safety_doc)]
$vis const unsafe fn [<set_ $ident>](&mut self, value: $ty, tweak_bitmap: &VmsaTweakBitmap) {
let buffer: [u8; size_of::<$ty>()] = unsafe { core::mem::transmute(value) };
self.write(offset_of!(Self, $ident), &buffer, tweak_bitmap);
}
}
};
}

macro_rules! vmsa_def {
(
$($vis:vis $ident:ident: $ty:ty = $default:expr,)*
Expand All @@ -29,28 +80,17 @@ macro_rules! vmsa_def {
$($ident: [u8; size_of::<$ty>()],)*
}

paste! {
#[expect(dead_code, clippy::missing_transmute_annotations, clippy::transmute_num_to_bytes)]
impl Vmsa {
pub const fn new() -> Self {
Self {
$($ident: unsafe { core::mem::transmute::<$ty, _>($default) },)*
}
#[expect(dead_code, clippy::missing_transmute_annotations, clippy::transmute_num_to_bytes)]
impl Vmsa {
pub const fn new() -> Self {
Self {
$($ident: unsafe { core::mem::transmute::<$ty, _>($default) },)*
}

$(
$vis const fn $ident(&self, tweak_bitmap: &VmsaTweakBitmap) -> $ty {
let mut buffer = [0; size_of::<$ty>()];
self.read(offset_of!(Self, $ident), &mut buffer, tweak_bitmap);
unsafe { core::mem::transmute(buffer) }
}

$vis const fn [<set_ $ident>](&mut self, value: $ty, tweak_bitmap: &VmsaTweakBitmap) {
let buffer: [u8; size_of::<$ty>()] = unsafe { core::mem::transmute(value) };
self.write(offset_of!(Self, $ident), &buffer, tweak_bitmap);
}
)*
}

$(
vmsa_field_accessor!($vis $ident: $ty);
)*
}

impl Default for Vmsa {
Expand Down Expand Up @@ -78,6 +118,7 @@ macro_rules! vmsa_def {

impl Vmsa {
/// Read bytes from the VMSA and deobfuscate protected registers.
#[inline(always)]
const fn read(&self, mut offset: usize, mut buffer: &mut [u8], tweak_bitmap: &VmsaTweakBitmap) {
while let Some((b, new_buffer)) = buffer.split_first_mut() {
*b = unsafe { core::ptr::from_ref(self).cast::<u8>().add(offset).read() };
Expand All @@ -88,6 +129,7 @@ impl Vmsa {
}

/// Write bytes to the VMSA and obfuscate protected registers.
#[inline(always)]
const fn write(
&mut self,
mut offset: usize,
Expand All @@ -105,6 +147,7 @@ impl Vmsa {
}
}

#[inline(always)]
const fn apply_reg_prot_nonce(
&self,
offset: usize,
Expand Down Expand Up @@ -343,4 +386,10 @@ pub struct VmsaTweakBitmap {

impl VmsaTweakBitmap {
pub const ZERO: Self = Self { bitmap: [0; 0x40] };

/// Returns if the field at `offset` is tweaked with the register
/// protection nonce.
pub fn is_tweaked(&self, offset: usize) -> bool {
self.bitmap.get_bit(offset / 8)
}
}
8 changes: 0 additions & 8 deletions common/supervisor-services/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,4 @@ name = "supervisor-services"
version = "0.1.0"
edition = "2021"

[features]
default = ["supervisor", "kernel"]
supervisor = []
kernel = []

[dependencies]
bit_field = "0.10.2"
bytemuck = { version = "1.15.0", features = ["derive"] }
constants = { workspace = true }
77 changes: 0 additions & 77 deletions common/supervisor-services/src/allocation_buffer.rs

This file was deleted.

Loading

0 comments on commit d1f6709

Please sign in to comment.