1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::os::raw::{c_int, c_uint};
6 use std::ptr;
7 use std::slice;
8 use std::sync::atomic::{AtomicBool, Ordering};
9
10 static SIMULATOR_EXISTS: AtomicBool = AtomicBool::new(false);
11
12 /// A libtpm2-based TPM simulator.
13 ///
14 /// At most one simulator may exist per process because libtpm2 uses a static
15 /// global response buffer.
16 ///
17 /// # Examples
18 ///
19 /// ```no_run
20 /// let mut simulator = tpm2::Simulator::singleton_in_current_directory();
21 ///
22 /// let command = &[ /* ... */ ];
23 /// let response = simulator.execute_command(command);
24 /// println!("{:?}", response);
25 /// ```
26 pub struct Simulator {
27 _priv: (),
28 }
29
30 impl Simulator {
31 /// Initializes a TPM simulator in the current working directory.
32 ///
33 /// # Panics
34 ///
35 /// Panics if a TPM simulator has already been initialized by this process.
singleton_in_current_directory() -> Self36 pub fn singleton_in_current_directory() -> Self {
37 let already_existed = SIMULATOR_EXISTS.swap(true, Ordering::SeqCst);
38 if already_existed {
39 panic!("libtpm2 simulator singleton already exists");
40 }
41
42 // Based on trunks:
43 // https://chromium.googlesource.com/chromiumos/platform2/+/e4cf13c05773f3446bd76a13c4e37f0b80728711/trunks/tpm_simulator_handle.cc
44 tpm_manufacture(true);
45 plat_set_nv_avail();
46 plat_signal_power_on();
47 tpm_init();
48
49 let mut simulator = Simulator { _priv: () };
50
51 // Send TPM2_Startup(TPM_SU_CLEAR), ignore the result. This is normally
52 // done by firmware.
53 let startup_command = &[
54 0x80, 0x01, // TPM_ST_NO_SESSIONS
55 0x00, 0x00, 0x00, 0x0c, // commandSize = 12
56 0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup
57 0x00, 0x00, // TPM_SU_CLEAR
58 ];
59 let _ = simulator.execute_command(startup_command);
60
61 simulator
62 }
63
64 /// Sends a TPM command to the TPM simulator, waits for the work to be
65 /// performed, and receives back the TPM response.
66 ///
67 /// Executing a command requires exclusive access to the TPM simulator
68 /// because it mutates libtpm2 static state.
69 ///
70 /// The returned response buffer remains valid until the next TPM command is
71 /// executed.
72 #[must_use]
execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8]73 pub fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
74 let request_size = command.len() as c_uint;
75 let request = command.as_ptr() as *mut u8;
76 let mut response_size: c_uint = 0;
77 let mut response: *mut u8 = ptr::null_mut();
78
79 // We need to provide the following guarantees in order for this block
80 // of code to be safe:
81 //
82 // - The TPM must have been initialized.
83 //
84 // - There must not be a concurrently executing call to
85 // ExecuteCommand.
86 //
87 // - The `request` pointer must be a valid pointer to `request_size`
88 // bytes of data that remain valid and constant for the full
89 // duration of the call to ExecuteCommand. The implementation may
90 // read up to `request_size` bytes of data from this address.
91 //
92 // - The `response_size` pointer must be a valid pointer to a mutable
93 // unsigned int. The implementation will write the response buffer
94 // size to this address.
95 //
96 // - The `response` pointer must be a valid pointer to a mutable
97 // unsigned char pointer. The implementation will write a pointer to
98 // the start of the response buffer to this address.
99 //
100 // - No more than `response_size` bytes may be read from the response
101 // buffer after the call returns.
102 //
103 // - Data may be read from the response buffer only until the next
104 // call to ExecuteCommand.
105 //
106 // The first guarantee is enforced by the public API of the Simulator
107 // struct, and in particular the singleton_in_current_directory
108 // constructor, which only makes a value of type Simulator available
109 // outside of this module after TPM initialization has been performed.
110 // Thus any Simulator on which the caller may be calling execute_command
111 // from outside of this module is witness that initialization has taken
112 // place.
113 //
114 // The second guarantee is made jointly by the &mut self reference in
115 // execute_command and the singleton_in_current_directory constructor
116 // which uses the SIMULATOR_EXISTS atomic flag to ensure that at most
117 // one value of type Simulator is ever made available to code outside of
118 // this module. Since at most one Simulator exists, and the caller is
119 // holding an exclusive reference to a Simulator, we know that no other
120 // code can be calling execute_command at the same time because they too
121 // would need their own exclusive reference to the same Simulator. We
122 // assume here that all use of libtpm2 within crosvm happens through the
123 // safe bindings provided by this tpm2 crate, so that the codebase
124 // contains no other unsafe calls to ExecuteCommand.
125 //
126 // The remaining guarantees are upheld by the signature and
127 // implementation of execute_command. In particular, note the lifetime
128 // 'a which ties the lifetime of the response slice we return to the
129 // caller to the lifetime of their exclusively held reference to
130 // Simulator. This signature looks the same to Rust as if the response
131 // buffer were a field inside the Simulator struct, rather than a
132 // statically allocated buffer inside libtpm2. As soon as the caller
133 // "mutates" the Simulator by performing another call to
134 // execute_command, the response buffer returned by the previous call is
135 // assumed to be invalidated and is made inaccessible by the borrow
136 // checker.
137 //
138 // Altogether we have guaranteed that execute_command is a safe
139 // abstraction around unsafe code and is entirely safe to call from
140 // outside of this module.
141 //
142 // Note additionally that the call to ExecuteCommand is over FFI so we
143 // need to know that the signature declared by tpm2-sys is
144 // ABI-compatible with the symbol provided by libtpm2.
145 unsafe {
146 tpm2_sys::ExecuteCommand(request_size, request, &mut response_size, &mut response);
147 slice::from_raw_parts(response, response_size as usize)
148 }
149 }
150 }
151
tpm_manufacture(first_time: bool)152 fn tpm_manufacture(first_time: bool) {
153 // From libtpm2 documentation:
154 //
155 // This function initializes the TPM values in preparation for the TPM's
156 // first use. This function will fail if previously called. The TPM can
157 // be re-manufactured by calling TPM_Teardown() first and then calling
158 // this function again.
159 //
160 // Arguments
161 //
162 // firstTime: indicates if this is the first call from main()
163 //
164 // Return value
165 //
166 // 0 = success
167 // 1 = manufacturing process previously performed
168 //
169 // Unsafe only because this is over FFI and we need to know that the
170 // signature declared by tpm2-sys is ABI-compatible with the symbol provided
171 // by libtpm2. There are no other invariants to uphold.
172 let ret: c_int = unsafe { tpm2_sys::TPM_Manufacture(first_time as c_int) };
173
174 // We expect that the TPM must not already have been manufactured. The
175 // SIMULATOR_EXISTS atomic flag guards calls to this function such that only
176 // one call can ever be performed by a process.
177 assert!(ret == 0);
178 }
179
plat_set_nv_avail()180 fn plat_set_nv_avail() {
181 // From libtpm2 documentation:
182 //
183 // Set the current NV state to available. This function is for testing
184 // purpose only. It is not part of the platform NV logic.
185 //
186 // The "for testing purpose only" is unsettling but trunks performs the same
187 // call during initialization so we trust that it is okay.
188 //
189 // Unsafe only because this is over FFI and we need to know that the
190 // signature declared by tpm2-sys is ABI-compatible with the symbol provided
191 // by libtpm2. There are no other invariants to uphold.
192 unsafe {
193 tpm2_sys::_plat__SetNvAvail();
194 }
195 }
196
plat_signal_power_on()197 fn plat_signal_power_on() {
198 // From libtpm2 documentation:
199 //
200 // Signal platform power on.
201 //
202 // The libtpm2 implementation always returns 0 but does not document what
203 // the return value means, so we aren't checking it.
204 //
205 // Unsafe only because this is over FFI and we need to know that the
206 // signature declared by tpm2-sys is ABI-compatible with the symbol provided
207 // by libtpm2. There are no other invariants to uphold.
208 unsafe {
209 let _: c_int = tpm2_sys::_plat__Signal_PowerOn();
210 }
211 }
212
tpm_init()213 fn tpm_init() {
214 // This function is not documented in libtpm2. Trunks performs the same call
215 // during initialization so we trust that it is okay.
216 //
217 // Unsafe only because this is over FFI and we need to know that the
218 // signature declared by tpm2-sys is ABI-compatible with the symbol provided
219 // by libtpm2. There are no other invariants to uphold.
220 unsafe {
221 tpm2_sys::_TPM_Init();
222 }
223 }
224