1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright (c) 2022 Intel Corporation
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
extern crate alloc;

use crate::metadata::{
    self, TdxMetadataDescriptor, TdxMetadataGuid, TdxMetadataSection, TDX_METADATA_DESCRIPTOR_LEN,
    TDX_METADATA_GUID_LEN, TDX_METADATA_OFFSET, TDX_METADATA_SECTION_LEN,
};
use alloc::vec::Vec;
use core::convert::TryInto;
use log::error;
use scroll::Pread;

pub struct TdShimLoader;

impl TdShimLoader {
    /// generate TdxMetadata elements tupple from input file
    ///
    /// # Arguments
    ///
    /// * `filename` - The td-shim binary which contains TdxMetadata
    pub fn parse(binary_file: &[u8]) -> Option<(TdxMetadataDescriptor, Vec<TdxMetadataSection>)> {
        let file_size = binary_file.len();
        // Then read 4 bytes at the pos of [file_len - 0x20]
        // This is the offset of TdxMetadata
        let metadata_offset_addr = file_size - TDX_METADATA_OFFSET as usize;
        let buffer = &binary_file[metadata_offset_addr..metadata_offset_addr + 4];
        let mut metadata_offset = ((buffer[3] as u32) << 24)
            | ((buffer[2] as u32) << 16)
            | ((buffer[1] as u32) << 8)
            | (buffer[0] as u32);
        if metadata_offset > file_size as u32 - TDX_METADATA_OFFSET - TDX_METADATA_DESCRIPTOR_LEN {
            error!("The metadata offset is invalid. {}", metadata_offset);
            error!("{:X?}", buffer);
            return None;
        }

        // Then read the guid
        metadata_offset -= TDX_METADATA_GUID_LEN;
        let buffer = &binary_file
            [metadata_offset as usize..(metadata_offset + TDX_METADATA_GUID_LEN) as usize]
            .try_into()
            .unwrap();
        let metadata_guid = TdxMetadataGuid::from_bytes(buffer);
        if metadata_guid.is_none() {
            error!("Invalid TdxMetadataGuid");
            error!("{:X?}", &buffer);
            return None;
        }

        // Then the descriptor
        metadata_offset += TDX_METADATA_GUID_LEN;
        let buffer = &binary_file
            [metadata_offset as usize..(metadata_offset + TDX_METADATA_DESCRIPTOR_LEN) as usize];
        let metadata_descriptor: TdxMetadataDescriptor =
            buffer.pread::<TdxMetadataDescriptor>(0).unwrap();
        if !metadata_descriptor.is_valid() {
            error!("Invalid TdxMetadata Descriptor: {:?}", metadata_descriptor);
            return None;
        }

        // check if the metadata length exceeds the file size
        let metadata_len = metadata_descriptor.number_of_section_entry * TDX_METADATA_SECTION_LEN
            + TDX_METADATA_GUID_LEN
            + TDX_METADATA_DESCRIPTOR_LEN;
        if metadata_offset + metadata_len + TDX_METADATA_GUID_LEN + TDX_METADATA_DESCRIPTOR_LEN
            > file_size as u32
        {
            error!("Invalid TdxMetadata length {}", metadata_len);
            return None;
        }

        // after that extract the sections one by one
        let mut metadata_sections: Vec<TdxMetadataSection> = Vec::new();
        let mut i = 0;
        metadata_offset += TDX_METADATA_DESCRIPTOR_LEN;

        loop {
            let buffer = &binary_file
                [metadata_offset as usize..(metadata_offset + TDX_METADATA_SECTION_LEN) as usize];

            let section = buffer.pread::<TdxMetadataSection>(0).unwrap();
            metadata_sections.push(section);

            i += 1;
            if i == metadata_descriptor.number_of_section_entry {
                break;
            }
            metadata_offset += TDX_METADATA_SECTION_LEN;
        }

        if i != metadata_descriptor.number_of_section_entry {
            error!("Invalid number of sections.");
            return None;
        }

        // check the validness of the sections
        if metadata::validate_sections(&metadata_sections).is_err() {
            error!("Invalid metadata sections.");
            return None;
        }

        Some((metadata_descriptor, metadata_sections))
    }
}