Skip to content

Conversation

@cclaudio
Copy link
Owner

No description provided.

After updating to rustc 1.71, the SVSM build started to fail:

$ rm .prereq
$ make prereq
$ make
...
cryptlib.c:(.text.unlikely+0x8): undefined reference to `abort'
assert.c:(.text+0x22): undefined reference to `abort'
...

The abort function is implemented in Rust and exported for external
libraries. The option "-Wl,-u,abort" prevents it from being removed from
the svsm.elf.

Signed-off-by: Claudio Carvalho <[email protected]>
@cclaudio cclaudio force-pushed the svsm-report-ossl-preview branch 13 times, most recently from 40a02ce to c7adf74 Compare July 1, 2023 00:40
@cclaudio cclaudio force-pushed the svsm-report-ossl-preview branch from c7adf74 to 373841b Compare July 3, 2023 17:24
cclaudio added 15 commits July 4, 2023 13:12
There is no need to use the cty package; as of Rust 1.30, the C
primitive types are available in either core::ffi or alloc::ffi.

The cty package and the ffi crate provide similar functionality.

Signed-off-by: Claudio Carvalho <[email protected]>
This removes all the test logic in the wrappers crate and exclude
it entirely from tests.

The wrappers export C functions that already exist in the glibc. It
should not be included in the tests.

Signed-off-by: Claudio Carvalho <[email protected]>
Add bindgen to automatically produce Rust FFI (Foreign Functions
Interface) bindings out of C headers to be used in other crates.

This also renames the target x86_64-unknown-none as bindgen uses it to
properly generate bindings.

Signed-off-by: Claudio Carvalho <[email protected]>
With the attestation report support, the SnpSecrets is now accessed from
multiple places.

Signed-off-by: Claudio Carvalho <[email protected]>
When we request an attestation report to the PSP, the guest crashes with
the following error due to stack overflow.

Launching VM ...
  /tmp/cmdline.866937
char device redirected to /dev/pts/183 (label compat_monitor0)
KVM: entry failed, hardware error 0xffffffff
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=00000000 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 00000000 00000000
CS =0000 00000000 00000000 00000000
SS =0000 00000000 00000000 00000000
DS =0000 00000000 00000000 00000000
FS =0000 00000000 00000000 00000000
GS =0000 00000000 00000000 00000000
LDT=0000 00000000 00000000 00000000
TR =0000 00000000 00000000 00000000
GDT=     0000000000000000 00000000
IDT=     0000000000000000 00000000
CR0=80010033 CR2=0000000000000000 CR3=0000000000000000 CR4=00000668
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
EFER=0000000000001d00
Code=<??> ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??
      ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??

Currently, the SVSM stack size is 4 pages. The same issue happens if we
double the stack size.

This patch increases the BSP and AP stack size to 16 pages.

Signed-off-by: Claudio Carvalho <[email protected]>
Add a generic crypto API required to encrypt and decrypt SNP guest
messages.

This ensures that the nossl.rs stubs are compiled in when we compile the
SVSM with the test feature flag set (e.g. cargo test). This is important
because the test binary is meant to run standalone; so, if we try to
compile any code that calls the SVSM OpenSSL, that will likely cause
compilation conflicts between the libcrt headers and the system glibc.

This also adds a placeholder to when the code is compiled without
setting the test feature flag (e.g. cargo build). Later we can replace
that to point out to a real crypto implementation.

Signed-off-by: Claudio Carvalho <[email protected]>
When we compile the code without setting the test feature flag (e.g.
cargo build), only the OpenSSL-based implementation is compiled in.

Signed-off-by: Claudio Carvalho <[email protected]>
Each SNP guest request command has its own request and response
structure definition. However, they are sent and received from the PSP
wrapped in the SnpGuestRequestMsg structure.

SNP guest request commands are communicated through the hypervisor, so
they are expected to be encrypted with a key known only by the guest and
the PSP.

Signed-off-by: Claudio Carvalho <[email protected]>
This pre-allocates the required SNP_GUEST_REQUEST buffers at boot time
to prevent us from having to deal with out-of-memory issues later at
boot time or runtime.

To send a SNP Guest Request command to the PSP, we need to provide the
request and response physical addresses to the PSP; depending on the
command we also need to provide the physical address of a data buffer.
The size of these buffers are 1, 1 and 4 pages, and they need to be
shared with the hypervisor.

Access to the buffers are controled through a spinlock.

Signed-off-by: Claudio Carvalho <[email protected]>
The function vc_snp_guest_request sends SNP Guest Request messages
following the GHCB protocol defined in the Guest Hypervisor
Communication Block (GHCB) specification. It supports sending either a
extended or non-extended SNP_GUEST_REQUEST message; each one has its own
VMGEXIT exit code.

Signed-off-by: Claudio Carvalho <[email protected]>
As described in the SNP Firmware ABI specification, SNP_GUEST_REQUEST
commands are protected using AES_GCM 256 and a VMPCK key to
encrypt/decrypt the message. The firmware generates and provides the
VMPCK keys to the guest in a especial secrets page that only the guest
and firmware have access to, so the hypervisor cannot alter messages
without detection nor read the plaintext of the message.

We are limiting the send_request() implementation to encrypt/decrypt
messages using the VMPCK0 key only. From guest userspace we can send
SNP_GUEST_REQUEST commands using other VMPCK keys.

The send_request() also supports sending extended SNP_GUEST_REQUEST
commands, where the extended part of it is provided by the hypervisor.
For example, in an extended attestation report the PSP firmware provides
the attestation report and the hypervisor provides the certificate chain
needed to verify the attestation report.

If a SNP_GUEST_REQUEST fails, we disable the VMPCK0 to prevent it from
being used again to send SNP_GUEST_REQUEST commands to the PSP firmware.
The only two exceptions are when the hypervisor returns the error codes
below:

- BUSY: in this case we re-send the message and if it resturns any error
code, we disable the VMPCK0.

- INVALID_DATA_BUFFER_LEN: the data buffer provided in the extended
SNP_GUEST_REQUEST command is too small. So, we re-send the command, but
as non-extended SNP_GUEST_REQUEST in order to protect the IV (sequence
number) from replay attacks. If it returns any error code, we disable
the VMPCK0.

The two cases above could be improved later when, for example, timer
support is added to the SVSM.

Signed-off-by: Claudio Carvalho <[email protected]>
The guest uses the SnpReportRequest structure to assemble an attestation
report request.

The PSP uses the SnpReportResponse structure to assemble an attestation
report response, which contains the signed attestation report requested.

Signed-off-by: Claudio Carvalho <[email protected]>
The get_report() can be used to request an attestation report to the PSP
firmware. If the last parameter CertBuf is provided, the certificate
chain required to verify the attestation report is saved in the
CertBuf.addr provided.

If get_report() fails an Err(error_code) is returned. The wrapped error_code is
compliant with the Core Protocol error codes defined in the SVSM spec 0.62
(draft). The psp_rc reference provided can be used to further understand
the error.

Example:

let buf: x86_64::addr::VirtAddr = mem::mem_allocate(0x4000).unwrap();
let mut certs: CertsBuf = CertsBuf::new(buf, 0x4000usize);
let mut psp_rc: u64 = 0;
let mut data: [u8; USER_DATA_SIZE] = [0u8; USER_DATA_SIZE];
data[0] = 0x31;
data[1] = 0x32;
data[2] = 0x33;
data[4] = 0x34;

// Test extended attestation report request
let result: Result<psp::msg_report::SnpReportResponse, u64> =
    psp::request::get_report(&data, &mut psp_rc, Some(&mut certs));

if let Ok(resp) = result {
    prints!("INFO: Report, {} bytes, vmpl {}\n",
            { resp.get_report_size() },
            { resp.get_report().get_vmpl() }
    );
    prints!("INFO: report_id: {:x?}\n", {
            resp.get_report().get_report_id()
    });
    prints!("INFO: report_data: {:x?}\n", {
            resp.get_report().get_report_data()
    });

    let sample: *const [u8; 500] = buf.as_ptr() as *const [u8; 500];
    prints!("INFO: certs sample {:x?}\n", { unsafe { *sample } });
}

Signed-off-by: Claudio Carvalho <[email protected]>
Add the RUST_INSTALLER_ARGS variable to allow passing parameters to the
Rust installer in the 'make prereq'. For example:

$ make prereq RUST_INSTALLER_ARGS='-y'

The cmdline above tells the rust installer that we want to go with
the default options without any prompt. It could be useful in the github
CI, where tty is not available.

If RUST_INSTALLER_ARGS is not set outside the Makefile, the Rust
installer is executed without any parameter.

All assignments to RUST_INSTALLER_ARGS within the Makefile is ignored,
unless the override directive is used.

Signed-off-by: Claudio Carvalho <[email protected]>
The test.yml calls the same 'cargo test' command line as defined in the
Makefile test target.

This updates the test.yml to call 'make test' so that we don't need to
maintain the same test in multiple places.

Signed-off-by: Claudio Carvalho <[email protected]>
@cclaudio cclaudio force-pushed the svsm-report-ossl-preview branch from b9d8985 to 71aab71 Compare July 4, 2023 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants