Skip to content

Commit

Permalink
Updated launch library to use current IOCTls and gmem
Browse files Browse the repository at this point in the history
Updated the launch library to use INIT2 IOCTL and deprecate the old INIT
IOCTLs. Created new functions to register encrypted memory for SNP.
Updated SEV test to use INIT2. Updated the SNP launch test to use GMEM and support KVM GMEM for launch.

Signed-off-by: DGonzalezVillal <[email protected]>
  • Loading branch information
DGonzalezVillal authored and tylerfanelli committed Oct 9, 2024
1 parent 14132cc commit 0dfe735
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 162 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ rdrand = { version = "^0.8", optional = true }
kvm-ioctls = ">=0.16"

[dev-dependencies]
kvm-bindings = ">=0.7"
kvm-bindings = ">=0.9.1"
serial_test = "3.0"
73 changes: 59 additions & 14 deletions src/launch/linux/ioctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use crate::launch::linux::sev;
#[cfg(feature = "snp")]
use crate::launch::linux::snp;

#[cfg(all(feature = "sev", feature = "snp"))]
use crate::launch::linux::shared;

use std::{
marker::PhantomData,
os::{raw::c_ulong, unix::io::AsRawFd},
Expand All @@ -22,7 +25,7 @@ use std::{
use iocuddle::*;

// These enum ordinal values are defined in the Linux kernel
// source code: include/uapi/linux/kvm.h
// source code: arch/x86/include/uapi/asm/kvm.h
#[cfg(all(feature = "sev", feature = "snp"))]
impl_const_id! {
/// The ioctl sub number
Expand All @@ -38,10 +41,11 @@ impl_const_id! {
sev::LaunchFinish = 7,
sev::LaunchAttestation<'_> = 20,

snp::Init = 22,
snp::LaunchStart<'_> = 23,
snp::LaunchUpdate<'_> = 24,
snp::LaunchFinish<'_> = 25,
shared::Init2 = 22,

snp::LaunchStart = 100,
snp::LaunchUpdate<'_> = 101,
snp::LaunchFinish<'_> = 102,
}

#[cfg(all(feature = "sev", not(feature = "snp")))]
Expand All @@ -58,21 +62,25 @@ impl_const_id! {
sev::LaunchMeasure<'_> = 6,
sev::LaunchFinish = 7,
sev::LaunchAttestation<'_> = 20,

shared::Init2 = 22
}

#[cfg(all(not(feature = "sev"), feature = "snp"))]
impl_const_id! {
/// The ioctl sub number
pub Id => u32;

snp::Init = 22,
snp::LaunchStart<'_> = 23,
snp::LaunchUpdate<'_> = 24,
snp::LaunchFinish<'_> = 25,
shared::Init2 = 22,

snp::LaunchStart = 100,
snp::LaunchUpdate<'_> = 101,
snp::LaunchFinish<'_> = 102,
}

const KVM: Group = Group::new(0xAE);
const ENC_OP: Ioctl<WriteRead, &c_ulong> = unsafe { KVM.write_read(0xBA) };
pub const KVM_MEMORY_ATTRIBUTE_PRIVATE: u64 = 1 << 3;

// Note: the iocuddle::Ioctl::lie() constructor has been used here because
// KVM_MEMORY_ENCRYPT_OP ioctl was defined like this:
Expand All @@ -88,11 +96,13 @@ const ENC_OP: Ioctl<WriteRead, &c_ulong> = unsafe { KVM.write_read(0xBA) };

/// Initialize the SEV platform context.
#[cfg(feature = "sev")]
pub const INIT: Ioctl<WriteRead, &Command<sev::Init>> = unsafe { ENC_OP.lie() };
#[deprecated(note = "Init2 should be used instead")]
pub const _INIT: Ioctl<WriteRead, &Command<sev::Init>> = unsafe { ENC_OP.lie() };

/// Initialize the SEV-ES platform context.
#[cfg(feature = "sev")]
pub const ES_INIT: Ioctl<WriteRead, &Command<sev::EsInit>> = unsafe { ENC_OP.lie() };
#[deprecated(note = "Init2 should be used instead")]
pub const _ES_INIT: Ioctl<WriteRead, &Command<sev::EsInit>> = unsafe { ENC_OP.lie() };

/// Create encrypted guest context.
#[cfg(feature = "sev")]
Expand Down Expand Up @@ -132,9 +142,14 @@ pub const LAUNCH_ATTESTATION: Ioctl<WriteRead, &Command<sev::LaunchAttestation>>
pub const ENC_REG_REGION: Ioctl<Write, &KvmEncRegion> =
unsafe { KVM.read::<KvmEncRegion>(0xBB).lie() };

/// Initialize the SEV-SNP platform in KVM.
#[cfg(feature = "snp")]
pub const SNP_INIT: Ioctl<WriteRead, &Command<snp::Init>> = unsafe { ENC_OP.lie() };
/// Corresponds to the `KVM_SET_MEMORY_ATTRIBUTES` ioctl
#[cfg(any(feature = "sev", feature = "snp"))]
pub const SET_MEMORY_ATTRIBUTES: Ioctl<Write, &KvmSetMemoryAttributes> =
unsafe { KVM.write::<KvmSetMemoryAttributes>(0xd2) };

/// Use the KVM_SEV_INIT2 ioctl to initialize the SEV platform context.
#[cfg(any(feature = "sev", feature = "snp"))]
pub const INIT2: Ioctl<WriteRead, &Command<shared::Init2>> = unsafe { ENC_OP.lie() };

/// Initialize the flow to launch a guest.
#[cfg(feature = "snp")]
Expand Down Expand Up @@ -175,6 +190,36 @@ impl<'a> KvmEncRegion<'a> {
}
}

/// Corresponds to the kernel struct `kvm_memory_attributes`
#[repr(C)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
pub struct KvmSetMemoryAttributes {
addr: u64,
size: u64,
attributes: u64,
flags: u64,
}

impl KvmSetMemoryAttributes {
/// Create a new `KvmEncRegion` referencing some memory assigned to the virtual machine.
pub fn new(data: u64, len: u64, attributes: u64) -> Self {
Self {
addr: data,
size: len,
attributes,
flags: 0,
}
}

/// Register the encrypted memory region to a virtual machine
pub fn set_attributes(
&mut self,
vm_fd: &mut impl AsRawFd,
) -> std::io::Result<std::os::raw::c_uint> {
SET_MEMORY_ATTRIBUTES.ioctl(vm_fd, self)
}
}

/// A generic SEV command
#[repr(C)]
pub struct Command<'a, T: Id> {
Expand Down
3 changes: 3 additions & 0 deletions src/launch/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ pub(crate) mod sev;

#[cfg(feature = "snp")]
pub(crate) mod snp;

#[cfg(all(feature = "sev", feature = "snp"))]
pub(crate) mod shared;
56 changes: 56 additions & 0 deletions src/launch/linux/shared.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: Apache-2.0

//! SEV and SEV-SNP shared types for interacting with the KVM SEV guest management API.

/// Structure passed into KVM_SEV_INIT2 command.
#[derive(Default)]
#[repr(C, packed)]
pub struct Init2 {
/// Initial value of features field in VMSA. (Must be 0 for SEV)
vmsa_features: u64,

/// Always set to 0
flags: u32,

/// Maximum guest GHCB version allowed. (Currently 0 for SEV and 1 for SEV-ES and SEV-SNP)
ghcb_version: u16,

pad1: u16,

pad2: [u32; 8],
}

impl Init2 {
/// Default INIT2 values for SEV
pub fn init_default_sev() -> Self {
Self {
vmsa_features: 0,
flags: 0,
ghcb_version: 0,
pad1: Default::default(),
pad2: Default::default(),
}
}

/// Default INIT2 values for SEV-ES
pub fn init_default_es() -> Self {
Self {
vmsa_features: 0x1,
flags: 0,
ghcb_version: 1,
pad1: Default::default(),
pad2: Default::default(),
}
}

/// Default INIT2 values for SEV-SNP
pub fn init_default_snp() -> Self {
Self {
vmsa_features: 0,
flags: 0,
ghcb_version: 2,
pad1: Default::default(),
pad2: Default::default(),
}
}
}
66 changes: 23 additions & 43 deletions src/launch/linux/snp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,31 @@ pub struct Init {
flags: u64,
}

/// Initialize the flow to launch a guest.
#[repr(C)]
pub struct LaunchStart<'a> {
pub struct LaunchStart {
/// Guest policy. See Table 7 of the AMD SEV-SNP Firmware
/// specification for a description of the guest policy structure.
policy: u64,

/// Userspace address of migration agent
ma_uaddr: u64,

/// 1 if this guest is associated with a migration agent. Otherwise 0.
ma_en: u8,

/// 1 if this launch flow is launching an IMI for the purpose of
/// guest-assisted migration. Otherwise 0.
imi_en: u8,

/// Hypervisor provided value to indicate guest OS visible workarounds.
/// The format is hypervisor defined.
gosvw: [u8; 16],

pad: [u8; 6],
flags: u16,

_phantom: PhantomData<&'a [u8]>,
pad0: [u8; 6],

pad1: [u64; 4],
}

impl From<Start<'_>> for LaunchStart<'_> {
impl From<Start> for LaunchStart {
fn from(start: Start) -> Self {
Self {
policy: start.policy.into(),
ma_uaddr: if let Some(addr) = start.ma_uaddr {
addr.as_ptr() as u64
} else {
0
},
ma_en: u8::from(start.ma_uaddr.is_some()),
imi_en: start.imi_en as _,
gosvw: start.gosvw,
pad: [0u8; 6],
_phantom: PhantomData,
flags: 0,
pad0: [0u8; 6],
pad1: [0u64; 4],
}
}
}
Expand All @@ -62,32 +47,27 @@ impl From<Start<'_>> for LaunchStart<'_> {
#[repr(C)]
pub struct LaunchUpdate<'a> {
/// guest start frame number.
start_gfn: u64,
pub start_gfn: u64,

/// Userspace address of the page needed to be encrypted.
uaddr: u64,
pub uaddr: u64,

/// Length of the page needed to be encrypted:
/// (end encryption uaddr = uaddr + len).
len: u32,

/// Indicates that this page is part of the IMI of the guest.
imi_page: u8,
pub len: u64,

/// Encoded page type. See Table 58 if the SNP Firmware specification.
page_type: u8,
pub page_type: u8,

/// VMPL permission mask for VMPL3. See Table 59 of the SNP Firmware
/// specification for the definition of the mask.
vmpl3_perms: u8,
pad0: u8,

/// VMPL permission mask for VMPL2.
vmpl2_perms: u8,
flags: u16,

/// VMPL permission mask for VMPL1.
vmpl1_perms: u8,
pad1: u32,

_phantom: PhantomData<&'a ()>,
pad2: [u64; 4],

_phantom: PhantomData<&'a [u8]>,
}

impl From<Update<'_>> for LaunchUpdate<'_> {
Expand All @@ -96,11 +76,11 @@ impl From<Update<'_>> for LaunchUpdate<'_> {
start_gfn: update.start_gfn,
uaddr: update.uaddr.as_ptr() as _,
len: update.uaddr.len() as _,
imi_page: u8::from(update.imi_page),
page_type: update.page_type as _,
vmpl3_perms: update.vmpl3_perms.bits(),
vmpl2_perms: update.vmpl2_perms.bits(),
vmpl1_perms: update.vmpl1_perms.bits(),
pad0: 0,
flags: 0,
pad1: 0,
pad2: [0u64; 4],
_phantom: PhantomData,
}
}
Expand Down
16 changes: 11 additions & 5 deletions src/launch/sev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::error::{Error::InvalidLen, Indeterminate};
#[cfg(target_os = "linux")]
use crate::launch::linux::ioctl::*;
#[cfg(target_os = "linux")]
use crate::launch::linux::sev::*;
use crate::launch::linux::{sev::*, shared::*};
use crate::*;

use std::convert::TryFrom;
Expand Down Expand Up @@ -56,8 +56,12 @@ impl<U: AsRawFd, V: AsRawFd> Launcher<New, U, V> {
state: New,
};

let mut cmd = Command::from(&launcher.sev, &Init);
INIT.ioctl(&mut launcher.vm_fd, &mut cmd)
let init = Init2::init_default_sev();

let mut cmd = Command::from(&launcher.sev, &init);

INIT2
.ioctl(&mut launcher.vm_fd, &mut cmd)
.map_err(|e| cmd.encapsulate(e))?;

Ok(launcher)
Expand All @@ -71,8 +75,10 @@ impl<U: AsRawFd, V: AsRawFd> Launcher<New, U, V> {
state: New,
};

let mut cmd = Command::from(&launcher.sev, &EsInit);
ES_INIT
let init = Init2::init_default_es();

let mut cmd = Command::from(&launcher.sev, &init);
INIT2
.ioctl(&mut launcher.vm_fd, &mut cmd)
.map_err(|e| cmd.encapsulate(e))?;

Expand Down
Loading

0 comments on commit 0dfe735

Please sign in to comment.