Skip to content

Commit

Permalink
Merge pull request #100 from Freax13/feature/svsm-linux
Browse files Browse the repository at this point in the history
switch to SVSM based Linux branch & clean up VMSA code
  • Loading branch information
Freax13 authored Nov 30, 2024
2 parents ca57941 + 19f7932 commit a5228ed
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 177 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ jobs:
key: build-cli-stable
workspaces: |
host
- name: "Update stable toolchain"
run: rustup update stable
- name: "Build"
run: cargo +stable build --all-features
working-directory: host/mushroom
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ mushroom could be the basis of a secure remote build system: mushroom could be u

## Usage

KVM host support for AMD SEV-SNP has been partially upstreamed into the Linux kernel, but [additional patches](https://github.com/Freax13/linux/tree/snp-guest-req-v1b-mushroom) are needed. KVM host support for Intel TDX has not yet been upstreamed. A [tree](https://github.com/Freax13/linux/tree/mushroom-tdx) based on Intel's partitioning patches can be used.
KVM host support for AMD SEV-SNP has been partially upstreamed into the Linux kernel, but [additional patches](https://github.com/Freax13/linux/tree/svsm_vmpl_vmsa_restinj-mushroom) are needed. KVM host support for Intel TDX has not yet been upstreamed. A [tree](https://github.com/Freax13/linux/tree/mushroom-tdx) based on Intel's partitioning patches can be used.

The host folder contains cargo-make files to simplify the process of running a workload.

Expand Down
13 changes: 11 additions & 2 deletions common/loader/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub fn load(
let execute = ph.p_flags.get_bit(0);
let write = ph.p_flags.get_bit(1);
let read = ph.p_flags.get_bit(2);
let vmsa_page = ph.p_flags.get_bit(27);
let cpuid_page = ph.p_flags.get_bit(28);
let secrets_page = ph.p_flags.get_bit(29);
let shared_page = ph.p_flags.get_bit(30);
Expand All @@ -62,7 +63,8 @@ pub fn load(

PhysFrame::range_inclusive(start_frame, end_inclusive_frame)
.into_iter()
.map(move |frame| {
.enumerate()
.map(move |(i, frame)| {
assert!(!(cpuid_page & secrets_page));
assert!(!(cpuid_page & shared_page));
assert!(!(secrets_page & shared_page));
Expand Down Expand Up @@ -94,14 +96,20 @@ pub fn load(
.copy_from_slice(&elf_bytes[offset_start..=offset_end_inclusive]);
}

if shared_page {
if vmsa_page {
LoadCommandPayload::Vmsa(bytes)
} else if shared_page {
LoadCommandPayload::Shared(bytes)
} else {
LoadCommandPayload::Normal(bytes)
}
};

let vcpu_id = if vmsa_page { i as u32 } else { 0 };

LoadCommand {
physical_address: frame,
vcpu_id,
vmpl1_perms,
payload,
}
Expand Down Expand Up @@ -173,6 +181,7 @@ pub fn load_shadow_mapping(

Some(LoadCommand {
physical_address: mapping_frame,
vcpu_id: 0,
vmpl1_perms,
payload: LoadCommandPayload::Normal(payload),
})
Expand Down
1 change: 1 addition & 0 deletions common/loader/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub fn load_init(init: &[u8]) -> impl Iterator<Item = LoadCommand> + '_ {
.zip(frames)
.map(|((vmpl1_perms, payload), physical_address)| LoadCommand {
physical_address,
vcpu_id: 0,
vmpl1_perms,
payload,
})
Expand Down
1 change: 1 addition & 0 deletions common/loader/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub fn load_input(
.zip(payloads)
.map(|(physical_address, payload)| LoadCommand {
physical_address,
vcpu_id: 0,
vmpl1_perms: VmplPermissions::empty(),
payload,
}),
Expand Down
4 changes: 4 additions & 0 deletions common/loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub use io::input::HashType;
#[derive(Debug)]
pub struct LoadCommand {
pub physical_address: PhysFrame,
pub vcpu_id: u32,
pub vmpl1_perms: VmplPermissions,
pub payload: LoadCommandPayload,
}
Expand All @@ -24,6 +25,7 @@ pub struct LoadCommand {
#[derive(Debug, Clone, Copy)]
pub enum LoadCommandPayload {
Normal([u8; 0x1000]),
Vmsa([u8; 0x1000]),
Zero,
Secrets,
Cpuid(CpuidPage),
Expand All @@ -34,6 +36,7 @@ impl LoadCommandPayload {
pub fn page_type(&self) -> Option<PageType> {
match self {
LoadCommandPayload::Normal(_) => Some(PageType::Normal),
LoadCommandPayload::Vmsa(..) => Some(PageType::Vmsa),
LoadCommandPayload::Zero => Some(PageType::Zero),
LoadCommandPayload::Secrets => Some(PageType::Secrets),
LoadCommandPayload::Cpuid(_) => Some(PageType::Cpuid),
Expand All @@ -44,6 +47,7 @@ impl LoadCommandPayload {
pub fn bytes(&self) -> [u8; 0x1000] {
match self {
LoadCommandPayload::Normal(bytes) => *bytes,
LoadCommandPayload::Vmsa(bytes) => *bytes,
LoadCommandPayload::Zero => [0; 0x1000],
LoadCommandPayload::Secrets => [0; 0x1000],
LoadCommandPayload::Cpuid(cpuid) => cast(*cpuid),
Expand Down
131 changes: 85 additions & 46 deletions common/snp-types/src/vmsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
use bit_field::BitArray;
use bitflags::bitflags;
use bytemuck::{bytes_of, bytes_of_mut, cast, offset_of, CheckedBitPattern, Pod, Zeroable};
use bytemuck::{bytes_of_mut, CheckedBitPattern, Pod, Zeroable};
use paste::paste;
use x86_64::registers::control::Cr4Flags;
use x86_64::registers::{
control::{Cr0Flags, Cr4Flags, EferFlags},
debug::{Dr6Flags, Dr7Flags},
mxcsr::MxCsr,
rflags::RFlags,
xcontrol::XCr0Flags,
};

use crate::{Reserved, Uninteresting};

use core::{
fmt::{self, Debug},
mem::size_of,
mem::{offset_of, size_of},
};

macro_rules! vmsa_def {
Expand All @@ -24,17 +30,23 @@ macro_rules! vmsa_def {
}

paste! {
#[allow(dead_code)]
#[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 fn $ident(&self, tweak_bitmap: &VmsaTweakBitmap) -> $ty {
$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);
bytemuck::checked::cast(buffer)
unsafe { core::mem::transmute(buffer) }
}

$vis fn [<set_ $ident>](&mut self, value: $ty, tweak_bitmap: &VmsaTweakBitmap) {
let buffer: [u8; size_of::<$ty>()] = cast(value);
$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);
}
)*
Expand All @@ -43,9 +55,7 @@ macro_rules! vmsa_def {

impl Default for Vmsa {
fn default() -> Self {
Self {
$($ident: cast::<$ty, _>($default),)*
}
Self::new()
}
}

Expand All @@ -68,24 +78,46 @@ macro_rules! vmsa_def {

impl Vmsa {
/// Read bytes from the VMSA and deobfuscate protected registers.
fn read(&self, offset: usize, buffer: &mut [u8], tweak_bitmap: &VmsaTweakBitmap) {
for (b, offset) in buffer.iter_mut().zip(offset..) {
*b = bytes_of(self)[offset];

if tweak_bitmap.bitmap.get_bit(offset / 8) {
*b ^= self.reg_prot_nonce[offset % 8];
}
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() };
self.apply_reg_prot_nonce(offset, b, tweak_bitmap);
buffer = new_buffer;
offset += 1;
}
}

/// Write bytes to the VMSA and deobfuscate protected registers.
fn write(&mut self, offset: usize, buffer: &[u8], tweak_bitmap: &VmsaTweakBitmap) {
for (mut b, offset) in buffer.iter().copied().zip(offset..) {
if tweak_bitmap.bitmap.get_bit(offset / 8) {
b ^= self.reg_prot_nonce[offset % 8];
/// Write bytes to the VMSA and obfuscate protected registers.
const fn write(
&mut self,
mut offset: usize,
mut buffer: &[u8],
tweak_bitmap: &VmsaTweakBitmap,
) {
while let Some((b, new_buffer)) = buffer.split_first() {
let mut b = *b;
self.apply_reg_prot_nonce(offset, &mut b, tweak_bitmap);
unsafe {
core::ptr::from_mut(self).cast::<u8>().add(offset).write(b);
}
buffer = new_buffer;
offset += 1;
}
}

bytes_of_mut(self)[offset] = b;
const fn apply_reg_prot_nonce(
&self,
offset: usize,
value: &mut u8,
tweak_bitmap: &VmsaTweakBitmap,
) {
let bitmap_idx = offset / 8;
let byte_idx = bitmap_idx / 8;
let bit_offset = bitmap_idx % 8;
let bitmap_byte = tweak_bitmap.bitmap[byte_idx];
let bit = (bitmap_byte >> bit_offset) & 1 != 0;
if bit {
*value ^= self.reg_prot_nonce[offset % 8];
}
}

Expand All @@ -110,7 +142,7 @@ impl Vmsa {

vmsa_def! {
pub es: Segment = Segment::DATA,
pub cs: Segment = Segment::CODE,
pub cs: Segment = Segment::CODE16,
pub ss: Segment = Segment::DATA,
pub ds: Segment = Segment::DATA,
pub fs: Segment = Segment::FS_GS,
Expand All @@ -124,20 +156,20 @@ vmsa_def! {
pub pl2_ssp: u64 = 0,
pub pl3_ssp: u64 = 0,
pub ucet: u64 = 0,
reserved1: Reserved<2> = Reserved::ZERO,
reserved1: Reserved<2, false> = Reserved::ZERO,
pub vmpl: u8 = 0,
pub cpl: u8 = 0,
reserved2: Reserved<4> = Reserved::ZERO,
pub efer: u64 = 0,
reserved3: Reserved<104> = Reserved::ZERO,
reserved2: Reserved<4, false> = Reserved::ZERO,
pub efer: EferFlags = EferFlags::SECURE_VIRTUAL_MACHINE_ENABLE,
reserved3: Reserved<104, false> = Reserved::ZERO,
pub xss: u64 = 0,
pub cr4: u64 = Cr4Flags::TIMESTAMP_DISABLE.bits(),
pub cr4: Cr4Flags = Cr4Flags::MACHINE_CHECK_EXCEPTION,
pub cr3: u64 = 0,
pub cr0: u64 = 0,
pub dr7: u64 = 0x400,
pub dr6: u64 = 0xffff0ff0,
pub rflags: u64 = 2,
pub rip: u64 = 0,
pub cr0: Cr0Flags = Cr0Flags::EXTENSION_TYPE,
pub dr7: Dr7Flags = Dr7Flags::GENERAL_DETECT_ENABLE,
pub dr6: Dr6Flags = Dr6Flags::from_bits_retain(0xffff0ff0),
pub rflags: RFlags = RFlags::from_bits_retain(2),
pub rip: u64 = 0xfff0,
pub dr0: u64 = 0,
pub dr1: u64 = 0,
pub dr2: u64 = 0,
Expand All @@ -146,7 +178,7 @@ vmsa_def! {
pub dr1_addr_mask: u64 = 0,
pub dr2_addr_mask: u64 = 0,
pub dr3_addr_mask: u64 = 0,
reserved4: Reserved<24> = Reserved::ZERO,
reserved4: Reserved<24, false> = Reserved::ZERO,
pub rsp: u64 = 0,
pub s_cet: u64 = 0,
pub ssp: u64 = 0,
Expand All @@ -161,15 +193,15 @@ vmsa_def! {
pub sysenter_esp: u64 = 0,
pub sysenter_eip: u64 = 0,
pub cr2: u64 = 0,
reserved5: Reserved<32> = Reserved::ZERO,
reserved5: Reserved<32, false> = Reserved::ZERO,
pub g_pat: u64 = 0x7040600070406,
pub dbgctl: u64 = 0,
pub br_from: u64 = 0,
pub br_to: u64 = 0,
pub lsat_excp_from: u64 = 0,
pub last_excp_to: u64 = 0,
reserved6: Reserved<72> = Reserved::ZERO,
reserved7: Reserved<8> = Reserved::ZERO,
reserved6: Reserved<72, false> = Reserved::ZERO,
reserved7: Reserved<8, false> = Reserved::ZERO,
pub pkru: u32 = 0,
pub tsc_aux: u32 = 0,
pub guest_tsc_scale: u64 = 0,
Expand All @@ -178,7 +210,7 @@ vmsa_def! {
pub rcx: u64 = 0,
pub rdx: u64 = 0,
pub rbx: u64 = 0,
reserved8: Reserved<8> = Reserved::ZERO,
reserved8: Reserved<8, false> = Reserved::ZERO,
pub rbp: u64 = 0,
pub rsi: u64 = 0,
pub rdi: u64 = 0,
Expand All @@ -202,13 +234,13 @@ vmsa_def! {
pub tlb_id: u64 = 0,
pub pcpu_id: u64 = 0,
pub event_inj: u64 = 0,
pub xcr0: u64 = 1,
reserved10: Reserved<16> = Reserved::ZERO,
pub xcr0: XCr0Flags = XCr0Flags::X87,
reserved10: Reserved<16, false> = Reserved::ZERO,
pub x87_dp: u64 = 0,
pub mxcsr: u32 = 0x1f80,
pub mxcsr: MxCsr = MxCsr::from_bits_retain(0x1f80),
pub x87_ftw: u16 = 0,
pub x87_fsw: u16 = 0,
pub x87_fcw: u16 = 0x40,
pub x87_fcw: u16 = 0x37f,
pub x87_fop: u16 = 0,
pub x87_ds: u16 = 0,
pub x87_cs: u16 = 0,
Expand All @@ -228,7 +260,7 @@ vmsa_def! {
pub ibs_dc_linaddr: u64 = 0,
pub bp_ibstgt_rip: u64 = 0,
pub ic_ibs_extd_ctl: u64 = 0,
padding: Reserved<2104> = Reserved::ZERO,
padding: Reserved<2104, false> = Reserved::ZERO,
}

#[derive(Clone, Copy, Debug, Pod, Zeroable)]
Expand All @@ -248,7 +280,14 @@ impl Segment {
base: 0,
};

const CODE: Self = Self {
const CODE16: Self = Self {
selector: 0xf000,
attrib: 0x9a,
limit: 0xffff,
base: 0xffff0000,
};

pub const CODE64: Self = Self {
selector: 0x08,
attrib: 0x29b,
limit: 0xffffffff,
Expand Down
Loading

0 comments on commit a5228ed

Please sign in to comment.