Skip to content

Commit

Permalink
AA/attester: support to read CCEL for kernel older than v6.4
Browse files Browse the repository at this point in the history
linux kernels older than v6.4 does not support to read CCEL from acpi
sysfs. This patch supports to read CCEL from dev/mem

This is accomplished by reading CCEL's physical address from ACPI table
description. Then read the CCEL from /dev/mem.

ACPI table to include CCEL patch of linux kernel

torvalds/linux@4f855dc

Signed-off-by: Xynnn007 <[email protected]>
  • Loading branch information
Xynnn007 committed Dec 30, 2024
1 parent 3cfbbfa commit 896acad
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 3 deletions.
2 changes: 1 addition & 1 deletion attestation-agent/attester/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ all-attesters = [
# quotes. It's an unconditional dependency for tdx-attester since that is the only way to
# generate TDX quotes with upstream kernels.
tsm-report = ["tempfile"]
tdx-attester = ["scroll", "tsm-report", "tdx-attest-rs"]
tdx-attester = ["scroll", "tsm-report", "tdx-attest-rs", "tokio/io-util"]
sgx-attester = ["occlum_dcap"]
az-snp-vtpm-attester = ["az-snp-vtpm"]
az-tdx-vtpm-attester = ["az-snp-vtpm-attester", "az-tdx-vtpm"]
Expand Down
104 changes: 104 additions & 0 deletions attestation-agent/attester/src/tdx/ccel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) 2024 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//

use anyhow::{bail, Context};
use scroll::Pread;
use tokio::io::{AsyncReadExt, AsyncSeekExt};

use crate::tdx::TdxAttester;

use std::path::Path;

const CCEL_PATH: &str = "/sys/firmware/acpi/tables/data/CCEL";

/// Path to the ACPI table CCEL description
const CCEL_ACPI_DESCRIPTION: &str = "/sys/firmware/acpi/tables/CCEL";

/// Guest memory which is used to read the CCEL
const GUEST_MEMORY: &str = "/dev/mem";

/// Signature of CCEL's ACPI Description Header
const CCEL_SIGNATURE: &[u8] = b"CCEL";

#[repr(C)]
#[derive(Pread)]
struct EfiAcpiDescriptionHeader {
signature: u32,
length: u32,
revision: u8,
checksum: u8,
oem_id: [u8; 6],
oem_table_id: u64,
oem_revision: u32,
craetor_id: u32,
creator_revision: u32,
}

#[repr(C)]
#[derive(Pread)]
struct TdxEventLogACPITable {
efi_acpi_description_header: EfiAcpiDescriptionHeader,
rsv: u32,
laml: u64,
lasa: u64,
}

impl TdxAttester {
pub async fn read_ccel() -> anyhow::Result<Vec<u8>> {
if Path::new(CCEL_PATH).exists() {
let ccel = tokio::fs::read(CCEL_PATH).await?;
return Ok(ccel);
}

let efi_acpi_description = tokio::fs::read(CCEL_ACPI_DESCRIPTION)
.await
.context("read ccel description")?;
let ccel_acpi_table = efi_acpi_description
.pread::<TdxEventLogACPITable>(0)
.context("parse CCEL ACPI description failed")?;

let ccel_signature = u32::from_le_bytes(CCEL_SIGNATURE.try_into()?);
if ccel_acpi_table.efi_acpi_description_header.signature != ccel_signature {
bail!("invalid CCEL ACPI table: wrong CCEL signature");
}

if ccel_acpi_table.rsv != 0 {
bail!("invalid CCEL ACPI table: RSV must be 0");
}

if ccel_acpi_table.efi_acpi_description_header.length != efi_acpi_description.len() as u32 {
bail!("invalid CCEL ACPI table: header length not match");
}

let mut guest_memory = tokio::fs::OpenOptions::new()
.read(true)
.open(GUEST_MEMORY)
.await?;
guest_memory
.seek(std::io::SeekFrom::Start(ccel_acpi_table.lasa))
.await?;
let mut ccel = vec![0; ccel_acpi_table.laml as usize];
let read_size = guest_memory.read(&mut ccel).await?;
if read_size == 0 {
bail!("read CCEL failed");
}

Ok(ccel)
}
}

#[cfg(test)]
mod tests {
use crate::tdx::TdxAttester;

#[ignore]
#[tokio::test]
async fn test_read_ccel() {
let ccel = TdxAttester::read_ccel().await.unwrap();
tokio::fs::write("/root/test/guest-components/2.bin", ccel)
.await
.unwrap();
}
}
4 changes: 2 additions & 2 deletions attestation-agent/attester/src/tdx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use std::fs;
use std::path::Path;
use tdx_attest_rs::tdx_report_t;

mod ccel;
mod report;
mod rtmr;

const TDX_REPORT_DATA_SIZE: usize = 64;
const CCEL_PATH: &str = "/sys/firmware/acpi/tables/data/CCEL";

pub fn detect_platform() -> bool {
TsmReportPath::new(TsmReportProvider::Tdx).is_ok() || Path::new("/dev/tdx_guest").exists()
Expand Down Expand Up @@ -129,7 +129,7 @@ impl Attester for TdxAttester {
let engine = base64::engine::general_purpose::STANDARD;
let quote = engine.encode(quote_bytes);

let cc_eventlog = match std::fs::read(CCEL_PATH) {
let cc_eventlog = match Self::read_ccel().await {
Result::Ok(el) => Some(engine.encode(el)),
Result::Err(e) => {
log::warn!("Read CC Eventlog failed: {:?}", e);
Expand Down

0 comments on commit 896acad

Please sign in to comment.