Skip to content

Commit 34d252a

Browse files
committed
Add support for caculating kernel eventlog digist when using OVMF+QEMU
Signed-off-by: OuyangHang33 <[email protected]>
1 parent 9b4e454 commit 34d252a

File tree

2 files changed

+113
-4
lines changed

2 files changed

+113
-4
lines changed

td-shim-tools/src/bin/td-payload-reference-calculator/README.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ wget https://github.com/Xynnn007/td-payload-reference-provider/raw/main/tests/bz
1313

1414
Test with the example bzImage
1515
```
16-
cargo run -- kernel -k bzImage -s 0x10000000
16+
cargo run -p td-shim-tools --bin td-payload-reference-calculator -- kernel -k bzImage -s 0x10000000
1717
```
1818

1919
The `kernel-size` parameter here means `KERNEL_SIZE` defined in guest firmware, s.t. [TD-SHIM](https://github.com/confidential-containers/td-shim)
@@ -25,11 +25,23 @@ Will get the result
2525

2626
which is from https://github.com/confidential-containers/attestation-service/pull/33/files#diff-1a4e5ad4c3b043c019c00bc3b3072fd6e1e5b03a5ce8c498e1c0acaf697d9d3fR265
2727

28+
When using TDVF + QEMU Kernel Direct Boot, the kernel eventlog digest will be pre-processed by QEMU Kernel Direct Boot logic. Which is from https://github.com/confidential-containers/td-shim/issues/633
29+
30+
Test with the example bzImage
31+
```
32+
cargo run -p td-shim-tools --bin td-payload-reference-calculator -- kernel -k bzImage -q
33+
```
34+
35+
Will get the result
36+
```
37+
a5e921ae5bde7ab989216da059057741688eae9114b854ce60733824f93ade8a848f19c719f3fdd5c4f0d7178164a5e2
38+
```
39+
2840
### Kernel Parameter
2941

3042
Test
3143
```
32-
cargo run -- param -p "root=/dev/vda1 console=hvc0 rw" -s 0x1000
44+
cargo run -p td-shim-tools --bin td-payload-reference-calculator -- param -p "root=/dev/vda1 console=hvc0 rw" -s 0x1000
3345
```
3446

3547
Will get the result

td-shim-tools/src/bin/td-payload-reference-calculator/main.rs

+99-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ use std::{convert::TryFrom, path::Path};
1414
pub const KERNEL_SIZE: &str = "0x2000000";
1515
pub const KERNEL_PARAM_SIZE: &str = "0x1000";
1616

17+
// Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format,
18+
// file offset specified at offset 0x3c,
19+
// size of PE signature is 4: "PE\0\0"
20+
const IMAGE_PE_ADDR: usize = 0x003c;
21+
const PE_SIGNATURE_SIZE: u16 = 4;
22+
const IMGAE_BEGIN_CHECKSUM_ADDR: usize = 0x0000;
23+
const IMGAE_BEGIN_CHECKSUM_SIZE: usize = 0x00da;
24+
const IMGAE_CERT_TABLE_ADDR: usize = 0x00de;
25+
const IMGAE_CERT_TABLE_SIZE: usize = 0x004c;
26+
const IMGAE_HEADERS_ADDR: usize = 0x0132;
27+
const IMGAE_HEADERS_SIZE: usize = 0x00ce;
28+
1729
fn kernel(path: &str, size: &str) -> Result<String> {
1830
let path = Path::new(path).to_path_buf();
1931
let siz = parse::<u64>(size)?;
@@ -31,6 +43,85 @@ fn param(param: &str, size: &str) -> Result<String> {
3143
padding_digest(param, siz)
3244
}
3345

46+
fn qemu(path: &str, size: &str) -> Result<String> {
47+
let path = Path::new(path).to_path_buf();
48+
let siz = parse::<u64>(size)?;
49+
let file_size = std::fs::metadata(&path)?.len();
50+
if file_size > siz {
51+
bail!("File size should be less than `kernel-size`");
52+
}
53+
let buf = std::fs::read(path)?;
54+
qemu_patch(buf)
55+
}
56+
57+
fn qemu_patch(mut buf: Vec<u8>) -> Result<String> {
58+
// patching type_of_loader @0x210
59+
buf[0x210] = 0xb0;
60+
61+
// patching loadflags @0x211
62+
buf[0x211] = 0x81;
63+
64+
//patching heap_end_ptr @0x224 cmdline_addr - real_addr - 0x200 = 0xfe00
65+
buf[0x224] = 0x00;
66+
buf[0x225] = 0xfe;
67+
68+
//patching cmd_line_ptr @0x228 cmdline_addr = 0x20000
69+
buf[0x228] = 0x00;
70+
buf[0x229] = 0x00;
71+
buf[0x22A] = 0x02;
72+
73+
let mut hasher = sha2::Sha384::new();
74+
let image = buf.clone();
75+
let (number_of_region_entry, regions_base, regions_size) = get_image_regions(image);
76+
77+
for index in 0..number_of_region_entry {
78+
hasher.update(&buf[regions_base[index]..regions_base[index] + regions_size[index]]);
79+
}
80+
81+
let res = hasher.finalize();
82+
Ok(hex::encode(res))
83+
}
84+
85+
fn get_image_regions(buf: Vec<u8>) -> (usize, Vec<usize>, Vec<usize>) {
86+
let mut number_of_region_entry = 3;
87+
// These 3 regions are known.
88+
let mut regions_base = vec![
89+
IMGAE_BEGIN_CHECKSUM_ADDR,
90+
IMGAE_CERT_TABLE_ADDR,
91+
IMGAE_HEADERS_ADDR,
92+
];
93+
let mut regions_size = vec![
94+
IMGAE_BEGIN_CHECKSUM_SIZE,
95+
IMGAE_CERT_TABLE_SIZE,
96+
IMGAE_HEADERS_SIZE,
97+
];
98+
99+
// Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format, the NumberOfSections' offset is 2
100+
let pe_addr =
101+
((buf[IMAGE_PE_ADDR + 1] as u16) << 8) | (buf[IMAGE_PE_ADDR] as u16 + PE_SIGNATURE_SIZE);
102+
let number_of_pecoff_entry = buf[pe_addr as usize + 2];
103+
number_of_region_entry += number_of_pecoff_entry as usize;
104+
105+
// Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
106+
let mut p = IMGAE_HEADERS_ADDR + 8;
107+
for _i in 0..number_of_pecoff_entry {
108+
p += 16;
109+
let size = ((buf[p + 3] as u32) << 24)
110+
| ((buf[p + 2] as u32) << 16)
111+
| ((buf[p + 1] as u32) << 8)
112+
| buf[p] as u32;
113+
p += 4;
114+
let base = ((buf[p + 3] as u32) << 24)
115+
| ((buf[p + 2] as u32) << 16)
116+
| ((buf[p + 1] as u32) << 8)
117+
| buf[p] as u32;
118+
regions_base.push(base as usize);
119+
regions_size.push(size as usize);
120+
p += 20;
121+
}
122+
(number_of_region_entry, regions_base, regions_size)
123+
}
124+
34125
fn padding_digest(mut buf: Vec<u8>, len: usize) -> Result<String> {
35126
let diff = len - buf.len();
36127

@@ -56,7 +147,8 @@ fn main() {
56147
.required(false)
57148
.default_value(KERNEL_SIZE)
58149
.action(ArgAction::Set),
59-
),
150+
)
151+
.arg(arg!(-q --"qemu" "QEMU Kernel Direct Boot patch string").required(false)),
60152
)
61153
.subcommand(
62154
command!("param")
@@ -78,7 +170,12 @@ fn main() {
78170
Some(("kernel", args)) => {
79171
let path = args.get_one::<String>("kernel").unwrap();
80172
let siz = args.get_one::<String>("size").unwrap();
81-
kernel(path, siz)
173+
// let qflag = args.get_one::<String>("qemu").unwrap();
174+
if args.get_flag("qemu") {
175+
qemu(path, siz)
176+
} else {
177+
kernel(path, siz)
178+
}
82179
}
83180
Some(("param", args)) => {
84181
let parameter = args.get_one::<String>("parameter").unwrap();

0 commit comments

Comments
 (0)