CCF/include/ccf/pal/snp_ioctl5.h

143 строки
3.5 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once
#include "ccf/pal/attestation_sev_snp.h"
#include <fcntl.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
// Based on the SEV-SNP ABI Spec document at
// https://www.amd.com/system/files/TechDocs/56860.pdf
/* linux kernel 5.15.* versions of the ioctls that talk to the PSP */
namespace ccf::pal::snp::ioctl5
{
constexpr auto DEVICE = "/dev/sev";
struct GuestRequest
{
uint8_t req_msg_type;
uint8_t rsp_msg_type;
uint8_t msg_version;
uint16_t request_len;
uint64_t request_uaddr;
uint16_t response_len;
uint64_t response_uaddr;
uint32_t error; /* firmware error code on failure (see psp-sev.h) */
};
// Table 99
enum MsgType
{
MSG_TYPE_INVALID = 0,
MSG_CPUID_REQ,
MSG_CPUID_RSP,
MSG_KEY_REQ,
MSG_KEY_RSP,
MSG_REPORT_REQ,
MSG_REPORT_RSP,
MSG_EXPORT_REQ,
MSG_EXPORT_RSP,
MSG_IMPORT_REQ,
MSG_IMPORT_RSP,
MSG_ABSORB_REQ,
MSG_ABSORB_RSP,
MSG_VMRK_REQ,
MSG_VMRK_RSP,
MSG_TYPE_MAX
};
// Table 20
struct AttestationReq
{
uint8_t report_data[snp_attestation_report_data_size];
uint32_t vmpl = 0;
uint8_t reserved[28];
};
// Table 23
#pragma pack(push, 1)
struct AttestationResp
{
uint32_t status;
uint32_t report_size;
uint8_t reserved[0x20 - 0x8];
struct Attestation report;
uint8_t padding[64];
// padding to the size of SEV_SNP_REPORT_RSP_BUF_SZ (i.e., 1280 bytes)
};
#pragma pack(pop)
constexpr char SEV_GUEST_IOC_TYPE = 'S';
constexpr int SEV_SNP_GUEST_MSG_REPORT =
_IOWR(SEV_GUEST_IOC_TYPE, 0x1, struct snp::ioctl5::GuestRequest);
static inline bool is_sev_snp()
{
return access(DEVICE, W_OK) == 0;
}
class Attestation : public AttestationInterface
{
AttestationReq req = {};
AttestationResp resp = {};
public:
Attestation(const PlatformAttestationReportData& report_data)
{
if (report_data.data.size() <= snp_attestation_report_data_size)
{
std::copy(
report_data.data.begin(), report_data.data.end(), req.report_data);
}
else
{
throw std::logic_error(
"User-defined report data is larger than available space");
}
int fd = open(DEVICE, O_RDWR | O_CLOEXEC);
if (fd < 0)
{
throw std::logic_error(fmt::format("Failed to open \"{}\"", DEVICE));
}
// Documented at
// https://www.kernel.org/doc/html/latest/virt/coco/sev-guest.html
GuestRequest payload = {
.req_msg_type = MSG_REPORT_REQ,
.rsp_msg_type = MSG_REPORT_RSP,
.msg_version = 1,
.request_len = sizeof(req),
.request_uaddr = reinterpret_cast<uint64_t>(&req),
.response_len = sizeof(resp),
.response_uaddr = reinterpret_cast<uint64_t>(&resp),
.error = 0};
int rc = ioctl(fd, SEV_SNP_GUEST_MSG_REPORT, &payload);
if (rc < 0)
{
CCF_APP_FAIL("IOCTL call failed: {}", strerror(errno));
CCF_APP_FAIL("Payload error: {}", payload.error);
throw std::logic_error(
"Failed to issue ioctl SEV_SNP_GUEST_MSG_REPORT");
}
}
const snp::Attestation& get() const override
{
return resp.report;
}
std::vector<uint8_t> get_raw() override
{
auto quote_bytes = reinterpret_cast<uint8_t*>(&resp.report);
return {quote_bytes, quote_bytes + resp.report_size};
}
};
}