1+ use std:: io:: Seek ;
12use std:: io:: Write ;
2- use std:: path:: Path ;
3- use std:: process:: Command ;
3+ use std:: path:: { Path , PathBuf } ;
4+ use std:: process:: { Command , Stdio } ;
45
56use tempfile:: NamedTempFile ;
67
7- use super :: BootableToplevel ;
8+ use super :: { BootableToplevel , PcrPhase } ;
89use crate :: Result ;
910
1011pub struct EfiProgram {
@@ -16,9 +17,17 @@ impl EfiProgram {
1617 Self { source }
1718 }
1819
19- pub fn write_unified_efi ( & self , objcopy : & Path , outpath : & Path , stub : & Path ) -> Result < ( ) > {
20+ pub fn write_unified_efi (
21+ & self ,
22+ objcopy : & Path ,
23+ systemd_measure : & Option < PathBuf > ,
24+ pcr_phases : & Option < Vec < PcrPhase > > ,
25+ outpath : & Path ,
26+ stub : & Path ,
27+ ) -> Result < ( ) > {
2028 let generation_path = & self . source . toplevel . 0 ;
2129 let mut kernel_params = NamedTempFile :: new ( ) ?;
30+ let mut pcr_sig = NamedTempFile :: new ( ) ?;
2231
2332 write ! (
2433 kernel_params,
@@ -27,30 +36,75 @@ impl EfiProgram {
2736 self . source. kernel_params. join( " " )
2837 ) ?;
2938
39+ write ! ( pcr_sig, "{{}}" ) ?;
40+
41+ if let Some ( pcr_phases) = pcr_phases {
42+ for phase in pcr_phases {
43+ let mut cmd = Command :: new ( systemd_measure. as_ref ( ) . unwrap ( ) ) ;
44+ for bank in & phase. banks {
45+ cmd. args ( [ "--bank" , bank] ) ;
46+ }
47+ cmd. args ( [
48+ "--osrel" ,
49+ & format ! ( "{}/etc/os-release" , generation_path. display( ) ) ,
50+ "--cmdline" ,
51+ & format ! ( "{}" , kernel_params. path( ) . display( ) ) ,
52+ "--linux" ,
53+ & format ! ( "{}/kernel" , generation_path. display( ) ) ,
54+ "--initrd" ,
55+ & format ! ( "{}/initrd" , generation_path. display( ) ) ,
56+ "--phase" ,
57+ & phase. phase_path . to_string ( ) ,
58+ "--private-key" ,
59+ & format ! ( "{}" , phase. private_key_file. display( ) ) ,
60+ "--public-key" ,
61+ & format ! ( "{}" , phase. public_key_file. display( ) ) ,
62+ "--append" ,
63+ & format ! ( "{}" , pcr_sig. path( ) . display( ) ) ,
64+ "sign" ,
65+ ] ) ;
66+ let output = cmd. stderr ( Stdio :: inherit ( ) ) . output ( ) ?;
67+
68+ if !output. status . success ( ) {
69+ return Err ( "failed to sign measurement" . into ( ) ) ;
70+ }
71+ pcr_sig. rewind ( ) ?;
72+ pcr_sig. as_file ( ) . set_len ( 0 ) ?;
73+ pcr_sig. write_all ( & output. stdout ) ?;
74+ }
75+ }
76+
3077 // Offsets taken from one of systemd's EFI tests:
3178 // https://github.com/systemd/systemd/blob/01d0123f044d6c090b6ac2f6d304de2bdb19ae3b/test/test-efi-create-disk.sh#L32-L38
32- let status = Command :: new ( objcopy)
33- . args ( & [
34- "--add-section" ,
35- & format ! ( ".osrel={}/etc/os-release" , generation_path. display( ) ) ,
36- "--change-section-vma" ,
37- ".osrel=0x20000" ,
79+ let mut cmd = Command :: new ( objcopy) ;
80+ cmd. args ( [
81+ "--add-section" ,
82+ & format ! ( ".osrel={}/etc/os-release" , generation_path. display( ) ) ,
83+ "--change-section-vma" ,
84+ ".osrel=0x20000" ,
85+ "--add-section" ,
86+ & format ! ( ".cmdline={}" , kernel_params. path( ) . display( ) ) ,
87+ "--change-section-vma" ,
88+ ".cmdline=0x30000" ,
89+ "--add-section" ,
90+ & format ! ( ".linux={}/kernel" , generation_path. display( ) ) ,
91+ "--change-section-vma" ,
92+ ".linux=0x2000000" ,
93+ "--add-section" ,
94+ & format ! ( ".initrd={}/initrd" , generation_path. display( ) ) ,
95+ "--change-section-vma" ,
96+ ".initrd=0x3000000" ,
97+ ] ) ;
98+ if pcr_phases. is_some ( ) {
99+ cmd. args ( [
38100 "--add-section" ,
39- & format ! ( ".cmdline ={}" , kernel_params . path( ) . display( ) ) ,
101+ & format ! ( ".pcrsig ={}" , pcr_sig . path( ) . display( ) ) ,
40102 "--change-section-vma" ,
41- ".cmdline=0x30000" ,
42- "--add-section" ,
43- & format ! ( ".linux={}/kernel" , generation_path. display( ) ) ,
44- "--change-section-vma" ,
45- ".linux=0x2000000" ,
46- "--add-section" ,
47- & format ! ( ".initrd={}/initrd" , generation_path. display( ) ) ,
48- "--change-section-vma" ,
49- ".initrd=0x3000000" ,
50- & stub. display ( ) . to_string ( ) ,
51- & outpath. display ( ) . to_string ( ) ,
52- ] )
53- . status ( ) ?;
103+ ".pcrsig=0x40000" ,
104+ ] ) ;
105+ }
106+ cmd. args ( [ & stub. display ( ) . to_string ( ) , & outpath. display ( ) . to_string ( ) ] ) ;
107+ let status = cmd. status ( ) ?;
54108
55109 if !status. success ( ) {
56110 return Err ( "failed to write unified efi" . into ( ) ) ;
0 commit comments