Skip to content
This repository was archived by the owner on Oct 26, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions internal/shim-sev/src/attestation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: Apache-2.0

//! SEV attestation handling

use crate::hostlib::{BootInfo, SevSecret, SEV_SECRET_MAX_SIZE};
use crate::C_BIT_MASK;
use core::hint::unreachable_unchecked;
use core::sync::atomic::Ordering;
use spinning::RwLock;

/// A copy of the injected SEV secret.
#[derive(Copy, Clone, Debug)]
pub struct SevSecretCopy {
/// the secret byte blob
data: [u8; SEV_SECRET_MAX_SIZE],
}

/// The secret injected by the Hypervisor
pub static SEV_SECRET: RwLock<SevSecretCopy> = RwLock::<SevSecretCopy>::const_new(
spinning::RawRwLock::const_new(),
SevSecretCopy {
data: [0u8; SEV_SECRET_MAX_SIZE],
},
);

impl SevSecretCopy {
#[allow(clippy::integer_arithmetic)]
unsafe fn cbor_len(data: *const u8) -> Option<usize> {
let prefix = data.read();

// only accept CBOR BYTES type
if (prefix >> 5) != 2 {
return None;
}

// mask the minor
match prefix & 0b00011111 {
x @ 0..=23 => Some(1 + x as usize),
24 => Some(1 + 1 + data.add(1).read() as usize),
25 => {
let data = data.add(1) as *const [u8; 2];
Some(1 + 2 + u16::from_be_bytes(data.read()) as usize)
}
26 => {
let data = data.add(1) as *const [u8; 4];
Some(1 + 4 + u32::from_be_bytes(data.read()) as usize)
}
27 => {
let data = data.add(1) as *const [u8; 8];
Some(1 + 8 + u64::from_be_bytes(data.read()) as usize)
}
28 => None,
29 => None,
30 => None,
31 => None,
32..=255 => unreachable_unchecked(),
}
}

/// get the length of the secret
pub fn try_len(&self) -> Option<usize> {
unsafe { SevSecretCopy::cbor_len(self.data.as_ptr()) }
}

/// Backup the secret injected by the Hypervisor
///
/// # Safety
/// The caller has to ensure `boot_info` is pointing
/// to the initial BootInfo passed by the Hypervisor.
pub unsafe fn copy_from_bootinfo(&mut self, boot_info: *const BootInfo) {
if C_BIT_MASK.load(Ordering::Relaxed) == 0 {
return;
}

let secret_ptr = SevSecret::get_secret_ptr(boot_info);

let secret_len = match SevSecretCopy::cbor_len(secret_ptr as *const u8) {
None => return,
Some(len) => len,
};

if secret_len > SEV_SECRET_MAX_SIZE {
return;
}

core::ptr::copy_nonoverlapping::<u8>(
(*secret_ptr).data.as_ptr() as _,
self.data.as_mut_ptr(),
secret_len,
);
}

/// Get a slice of the secret
pub fn try_as_slice(&self) -> Option<&[u8]> {
self.try_len().map(|len| &self.data[..len])
}
}
24 changes: 24 additions & 0 deletions internal/shim-sev/src/hostlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
/// FIXME: might change to another mechanism in the future
pub const SYSCALL_TRIGGER_PORT: u16 = 0xFF;

use core::mem::{align_of, size_of, MaybeUninit};
use lset::{Line, Span};
use nbytes::bytes;
use primordial::Page;
Expand Down Expand Up @@ -65,6 +66,29 @@ fn above(rel: impl Into<Line<usize>>, size: usize, align: usize) -> Option<Span<
})
}

/// The maximum size of the injected secret for SEV keeps
#[allow(clippy::integer_arithmetic)]
pub const SEV_SECRET_MAX_SIZE: usize = bytes!(16; KiB);

/// A 16 byte aligned SevSecret with unknown content
#[repr(C, align(16))]
#[derive(Copy, Clone, Debug)]
pub struct SevSecret {
/// the secret byte blob
pub data: MaybeUninit<[u8; SEV_SECRET_MAX_SIZE]>,
}

impl SevSecret {
/// Get the pointer to the SEV secret relative to the BootInfo pointer
#[allow(dead_code)]
pub fn get_secret_ptr(boot_info: *const BootInfo) -> *const SevSecret {
unsafe {
let secret_ptr = (boot_info as *const u8).add(size_of::<BootInfo>());
secret_ptr.add(secret_ptr.align_offset(align_of::<SevSecret>())) as *const SevSecret
}
}
}

/// Basic information for the shim and the loader
#[repr(C)]
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
Expand Down
17 changes: 11 additions & 6 deletions internal/shim-sev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,36 @@
extern crate compiler_builtins;
extern crate rcrt1;

#[macro_use]
pub mod print;

pub mod addr;
pub mod asm;
pub mod attestation;
pub mod frame_allocator;
pub mod gdt;
pub mod hostcall;
/// Shared components for the shim and the loader
pub mod hostlib;
pub mod no_std;
pub mod pagetables;
pub mod paging;
pub mod payload;
pub mod shim_stack;
#[macro_use]
pub mod print;
pub mod pagetables;
pub mod random;
pub mod shim_stack;
pub mod syscall;
pub mod usermode;

use crate::addr::{ShimVirtAddr, SHIM_VIRT_OFFSET};
use crate::attestation::SEV_SECRET;
use crate::hostcall::HOST_CALL;
use crate::hostlib::BootInfo;
use crate::pagetables::switch_sallyport_to_unencrypted;
use crate::paging::SHIM_PAGETABLE;
use crate::payload::PAYLOAD_VIRT_ADDR;
use core::convert::TryFrom;
use core::mem::size_of;
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
pub use hostlib::BootInfo;
use primordial::Address;
use sallyport::Block;
use spinning::RwLock;
Expand Down Expand Up @@ -113,7 +116,9 @@ macro_rules! entry_point {
);

// make a local copy of boot_info, before the shared page gets overwritten
BOOT_INFO.write().replace(boot_info.read_volatile());
BOOT_INFO.write().replace(boot_info.read());

SEV_SECRET.write().copy_from_bootinfo(boot_info);

switch_sallyport_to_unencrypted(c_bit_mask);

Expand Down
28 changes: 23 additions & 5 deletions internal/shim-sev/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::addr::{HostVirtAddr, ShimPhysUnencryptedAddr};
use crate::asm::_enarx_asm_triple_fault;
use crate::attestation::SEV_SECRET;
use crate::eprintln;
use crate::frame_allocator::FRAME_ALLOCATOR;
use crate::hostcall::{self, HostCall, HOST_CALL};
Expand All @@ -16,7 +17,7 @@ use primordial::{Address, Register};
use sallyport::{Cursor, Request};
use spinning::MutexGuard;
use syscall::{SyscallHandler, ARCH_GET_FS, ARCH_GET_GS, ARCH_SET_FS, ARCH_SET_GS, SEV_TECH};
use untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, Validate};
use untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, Validate, ValidateSlice};
use x86_64::registers::{rdfsbase, rdgsbase, wrfsbase, wrgsbase};
use x86_64::structures::paging::{Page, PageTableFlags, Size4KiB};
use x86_64::{align_up, VirtAddr};
Expand Down Expand Up @@ -205,11 +206,28 @@ impl SyscallHandler for Handler {
&mut self,
_nonce: UntrustedRef<u8>,
_nonce_len: libc::size_t,
_buf: UntrustedRefMut<u8>,
_buf_len: libc::size_t,
buf: UntrustedRefMut<u8>,
buf_len: libc::size_t,
) -> sallyport::Result {
self.trace("get_att", 0);
Ok([0.into(), SEV_TECH.into()])
self.trace("get_attestation", 4);

let secret = SEV_SECRET.read();

match secret.try_len() {
Some(mut result_len) => {
if buf_len != 0 {
result_len = result_len.min(buf_len);
let buf = buf.validate_slice(buf_len, self).ok_or(libc::EFAULT)?;

buf[..result_len].copy_from_slice(
&(SEV_SECRET.read()).try_as_slice().unwrap()[..result_len],
);
}

Ok([result_len.into(), SEV_TECH.into()])
}
None => Err(libc::ENOSYS),
}
}

fn exit(&mut self, status: i32) -> ! {
Expand Down
2 changes: 1 addition & 1 deletion src/backend/kvm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0

mod builder;
mod shim;
pub mod shim;
mod vm;

pub const SHIM: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/bin/shim-sev"));
Expand Down
9 changes: 7 additions & 2 deletions src/backend/kvm/vm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ pub trait Hook {
Ok(())
}

fn code_loaded(&mut self, _vm: &mut VmFd, _addr_space: &[u8]) -> Result<()> {
fn code_loaded(
&mut self,
_vm: &mut VmFd,
_saddr_space: &[u8],
_syscall_blocks: VirtAddr,
) -> Result<()> {
Ok(())
}

Expand Down Expand Up @@ -101,7 +106,7 @@ impl<T: Hook> Builder<T> {

let code_offset = boot_info.code.start;
Self::load_component(addr, &mut self.code, code_offset);
self.hook.code_loaded(&mut fd, &map)?;
self.hook.code_loaded(&mut fd, &map, arch.syscall_blocks)?;

let vm = Vm {
kvm,
Expand Down
18 changes: 13 additions & 5 deletions src/backend/sev/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0

use crate::backend::kvm;
use crate::backend::kvm::shim::{BootInfo, SevSecret};

use sev::firmware::Firmware;
use sev::launch::{Launcher, Secret};
Expand All @@ -25,7 +26,12 @@ impl Sev {
}

impl kvm::Hook for Sev {
fn code_loaded(&mut self, vm: &mut VmFd, addr_space: &[u8]) -> Result<()> {
fn code_loaded(
&mut self,
vm: &mut VmFd,
addr_space: &[u8],
syscall_blocks: VirtAddr,
) -> Result<()> {
let mut sev = Firmware::open()?;
let build = sev.platform_status().unwrap().build;

Expand Down Expand Up @@ -69,7 +75,7 @@ impl kvm::Hook for Sev {
session: serde_flavor::from_reader(start_packet.session.as_slice())?,
};

let (launcher, measurement) = {
let (mut launcher, measurement) = {
let launcher = Launcher::new(vm, &mut sev)?;
let mut launcher = launcher.start(start)?;
launcher.update_data(addr_space)?;
Expand All @@ -93,9 +99,11 @@ impl kvm::Hook for Sev {
};

if !secret.is_empty() {
let _secret: Secret = serde_flavor::from_reader(secret.as_slice())?;
// TODO: https://github.com/enarx/enarx-keepldr/issues/159
// Inject the secret!
let secret: Secret = serde_flavor::from_reader(secret.as_slice())?;

let secret_ptr = SevSecret::get_secret_ptr(syscall_blocks.as_ptr::<BootInfo>());

launcher.inject(secret, secret_ptr as _)?;
}

let finish_packet = Message::Finish(Finish);
Expand Down