]>
Commit | Line | Data |
---|---|---|
8dc67017 SB |
1 | QEMU TPM Device |
2 | =============== | |
3 | ||
4 | = Guest-side Hardware Interface = | |
5 | ||
6 | The QEMU TPM emulation implements a TPM TIS hardware interface following the | |
7 | Trusted Computing Group's specification "TCG PC Client Specific TPM Interface | |
8 | Specification (TIS)", Specification Version 1.3, 21 March 2013. This | |
9 | specification, or a later version of it, can be accessed from the following | |
10 | URL: | |
11 | ||
12 | https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ | |
13 | ||
14 | The TIS interface makes a memory mapped IO region in the area 0xfed40000 - | |
15 | 0xfed44fff available to the guest operating system. | |
16 | ||
17 | ||
18 | QEMU files related to TPM TIS interface: | |
19 | - hw/tpm/tpm_tis.c | |
20 | - hw/tpm/tpm_tis.h | |
21 | ||
22 | ||
23 | = ACPI Interface = | |
24 | ||
25 | The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes | |
26 | it into the guest through the fw_cfg device. The device description contains | |
27 | the base address of the TIS interface 0xfed40000 and the size of the MMIO area | |
28 | (0x5000). In case a TPM2 is used by QEMU, a TPM2 ACPI table is also provided. | |
29 | The device is described to be used in polling mode rather than interrupt mode | |
30 | primarily because no unused IRQ could be found. | |
31 | ||
32 | To support measurement logs to be written by the firmware, e.g. SeaBIOS, a TCPA | |
33 | table is implemented. This table provides a 64kb buffer where the firmware can | |
34 | write its log into. For TPM 2 only a more recent version of the TPM2 table | |
35 | provides support for measurements logs and a TCPA table does not need to be | |
36 | created. | |
37 | ||
38 | The TCPA and TPM2 ACPI tables follow the Trusted Computing Group specification | |
39 | "TCG ACPI Specification" Family "1.2" and "2.0", Level 00 Revision 00.37. This | |
40 | specification, or a later version of it, can be accessed from the following | |
41 | URL: | |
42 | ||
43 | https://trustedcomputinggroup.org/tcg-acpi-specification/ | |
44 | ||
45 | ||
46 | QEMU files related to TPM ACPI tables: | |
47 | - hw/i386/acpi-build.c | |
48 | - include/hw/acpi/tpm.h | |
49 | ||
50 | ||
51 | = TPM backend devices = | |
52 | ||
53 | The TPM implementation is split into two parts, frontend and backend. The | |
54 | frontend part is the hardware interface, such as the TPM TIS interface | |
55 | described earlier, and the other part is the TPM backend interface. The backend | |
56 | interfaces implement the interaction with a TPM device, which may be a physical | |
57 | or an emulated device. The split between the front- and backend devices allows | |
58 | a frontend to be connected with any available backend. This enables the TIS | |
59 | interface to be used with the passthrough backend or the (future) swtpm backend. | |
60 | ||
61 | ||
62 | QEMU files related to TPM backends: | |
63 | - backends/tpm.c | |
64 | - include/sysemu/tpm_backend.h | |
65 | - include/sysemu/tpm_backend_int.h | |
66 | ||
67 | ||
68 | == The QEMU TPM passthrough device == | |
69 | ||
70 | In case QEMU is run on Linux as the host operating system it is possible to | |
71 | make the hardware TPM device available to a single QEMU guest. In this case the | |
72 | user must make sure that no other program is using the device, e.g., /dev/tpm0, | |
73 | before trying to start QEMU with it. | |
74 | ||
75 | The passthrough driver uses the host's TPM device for sending TPM commands | |
76 | and receiving responses from. Besides that it accesses the TPM device's sysfs | |
77 | entry for support of command cancellation. Since none of the state of a | |
78 | hardware TPM can be migrated between hosts, virtual machine migration is | |
79 | disabled when the TPM passthrough driver is used. | |
80 | ||
81 | Since the host's TPM device will already be initialized by the host's firmware, | |
82 | certain commands, e.g. TPM_Startup(), sent by the virtual firmware for device | |
83 | initialization, will fail. In this case the firmware should not use the TPM. | |
84 | ||
85 | Sharing the device with the host is generally not a recommended usage scenario | |
86 | for a TPM device. The primary reason for this is that two operating systems can | |
87 | then access the device's single set of resources, such as platform configuration | |
88 | registers (PCRs). Applications or kernel security subsystems, such as the | |
89 | Linux Integrity Measurement Architecture (IMA), are not expecting to share PCRs. | |
90 | ||
91 | ||
92 | QEMU files related to the TPM passthrough device: | |
93 | - hw/tpm/tpm_passthrough.c | |
94 | - hw/tpm/tpm_util.c | |
95 | - hw/tpm/tpm_util.h | |
96 | ||
97 | ||
98 | Command line to start QEMU with the TPM passthrough device using the host's | |
99 | hardware TPM /dev/tpm0: | |
100 | ||
a1d30f28 | 101 | qemu-system-x86_64 -display sdl -accel kvm \ |
8dc67017 SB |
102 | -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ |
103 | -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ | |
104 | -device tpm-tis,tpmdev=tpm0 test.img | |
105 | ||
106 | The following commands should result in similar output inside the VM with a | |
107 | Linux kernel that either has the TPM TIS driver built-in or available as a | |
108 | module: | |
109 | ||
110 | #> dmesg | grep -i tpm | |
111 | [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) | |
112 | ||
113 | #> dmesg | grep TCPA | |
114 | [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ | |
115 | BXPCTCPA 0000001 BXPC 00000001) | |
116 | ||
117 | #> ls -l /dev/tpm* | |
118 | crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 | |
119 | ||
120 | #> find /sys/devices/ | grep pcrs$ | xargs cat | |
121 | PCR-00: 35 4E 3B CE 23 9F 38 59 ... | |
122 | ... | |
123 | PCR-23: 00 00 00 00 00 00 00 00 ... | |
83e83c34 SB |
124 | |
125 | ||
126 | == The QEMU TPM emulator device == | |
127 | ||
128 | The TPM emulator device uses an external TPM emulator called 'swtpm' for | |
129 | sending TPM commands to and receiving responses from. The swtpm program | |
130 | must have been started before trying to access it through the TPM emulator | |
131 | with QEMU. | |
132 | ||
133 | The TPM emulator implements a command channel for transferring TPM commands | |
134 | and responses as well as a control channel over which control commands can | |
135 | be sent. The specification for the control channel can be found here: | |
136 | ||
137 | https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod | |
138 | ||
139 | ||
140 | The control channel serves the purpose of resetting, initializing, and | |
141 | migrating the TPM state, among other things. | |
142 | ||
143 | The swtpm program behaves like a hardware TPM and therefore needs to be | |
144 | initialized by the firmware running inside the QEMU virtual machine. | |
145 | One necessary step for initializing the device is to send the TPM_Startup | |
146 | command to it. SeaBIOS, for example, has been instrumented to initialize | |
147 | a TPM 1.2 or TPM 2 device using this command. | |
148 | ||
149 | ||
150 | QEMU files related to the TPM emulator device: | |
151 | - hw/tpm/tpm_emulator.c | |
152 | - hw/tpm/tpm_util.c | |
153 | - hw/tpm/tpm_util.h | |
154 | ||
155 | ||
156 | The following commands start the swtpm with a UnixIO control channel over | |
157 | a socket interface. They do not need to be run as root. | |
158 | ||
159 | mkdir /tmp/mytpm1 | |
160 | swtpm socket --tpmstate dir=/tmp/mytpm1 \ | |
161 | --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ | |
162 | --log level=20 | |
163 | ||
164 | Command line to start QEMU with the TPM emulator device communicating with | |
165 | the swtpm: | |
166 | ||
a1d30f28 | 167 | qemu-system-x86_64 -display sdl -accel kvm \ |
83e83c34 SB |
168 | -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ |
169 | -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ | |
170 | -tpmdev emulator,id=tpm0,chardev=chrtpm \ | |
171 | -device tpm-tis,tpmdev=tpm0 test.img | |
172 | ||
173 | ||
174 | In case SeaBIOS is used as firmware, it should show the TPM menu item | |
175 | after entering the menu with 'ESC'. | |
176 | ||
177 | Select boot device: | |
178 | 1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] | |
179 | [...] | |
180 | 5. Legacy option rom | |
181 | ||
182 | t. TPM Configuration | |
183 | ||
184 | ||
185 | The following commands should result in similar output inside the VM with a | |
186 | Linux kernel that either has the TPM TIS driver built-in or available as a | |
187 | module: | |
188 | ||
189 | #> dmesg | grep -i tpm | |
190 | [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) | |
191 | ||
192 | #> dmesg | grep TCPA | |
193 | [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ | |
194 | BXPCTCPA 0000001 BXPC 00000001) | |
195 | ||
196 | #> ls -l /dev/tpm* | |
197 | crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 | |
198 | ||
199 | #> find /sys/devices/ | grep pcrs$ | xargs cat | |
200 | PCR-00: 35 4E 3B CE 23 9F 38 59 ... | |
201 | ... | |
202 | PCR-23: 00 00 00 00 00 00 00 00 ... | |
9d1f0985 SB |
203 | |
204 | ||
205 | === Migration with the TPM emulator === | |
206 | ||
207 | The TPM emulator supports the following types of virtual machine migration: | |
208 | ||
209 | - VM save / restore (migration into a file) | |
210 | - Network migration | |
211 | - Snapshotting (migration into storage like QoW2 or QED) | |
212 | ||
213 | The following command sequences can be used to test VM save / restore. | |
214 | ||
215 | ||
216 | In a 1st terminal start an instance of a swtpm using the following command: | |
217 | ||
218 | mkdir /tmp/mytpm1 | |
219 | swtpm socket --tpmstate dir=/tmp/mytpm1 \ | |
220 | --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ | |
221 | --log level=20 --tpm2 | |
222 | ||
223 | In a 2nd terminal start the VM: | |
224 | ||
a1d30f28 | 225 | qemu-system-x86_64 -display sdl -accel kvm \ |
9d1f0985 SB |
226 | -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ |
227 | -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ | |
228 | -tpmdev emulator,id=tpm0,chardev=chrtpm \ | |
229 | -device tpm-tis,tpmdev=tpm0 \ | |
230 | -monitor stdio \ | |
231 | test.img | |
232 | ||
233 | Verify that the attached TPM is working as expected using applications inside | |
234 | the VM. | |
235 | ||
236 | To store the state of the VM use the following command in the QEMU monitor in | |
237 | the 2nd terminal: | |
238 | ||
239 | (qemu) migrate "exec:cat > testvm.bin" | |
240 | (qemu) quit | |
241 | ||
242 | At this point a file called 'testvm.bin' should exists and the swtpm and QEMU | |
243 | processes should have ended. | |
244 | ||
245 | To test 'VM restore' you have to start the swtpm with the same parameters | |
246 | as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 must now be | |
247 | passed again on the command line. | |
248 | ||
249 | In the 1st terminal restart the swtpm with the same command line as before: | |
250 | ||
251 | swtpm socket --tpmstate dir=/tmp/mytpm1 \ | |
252 | --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ | |
253 | --log level=20 --tpm2 | |
254 | ||
9277d81f | 255 | In the 2nd terminal restore the state of the VM using the additional |
9d1f0985 SB |
256 | '-incoming' option. |
257 | ||
a1d30f28 | 258 | qemu-system-x86_64 -display sdl -accel kvm \ |
9d1f0985 SB |
259 | -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ |
260 | -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ | |
261 | -tpmdev emulator,id=tpm0,chardev=chrtpm \ | |
262 | -device tpm-tis,tpmdev=tpm0 \ | |
263 | -incoming "exec:cat < testvm.bin" \ | |
264 | test.img | |
265 | ||
266 | ||
267 | Troubleshooting migration: | |
268 | ||
269 | There are several reasons why migration may fail. In case of problems, | |
270 | please ensure that the command lines adhere to the following rules and, | |
271 | if possible, that identical versions of QEMU and swtpm are used at all | |
272 | times. | |
273 | ||
274 | VM save and restore: | |
275 | - QEMU command line parameters should be identical apart from the | |
276 | '-incoming' option on VM restore | |
277 | - swtpm command line parameters should be identical | |
278 | ||
279 | VM migration to 'localhost': | |
280 | - QEMU command line parameters should be identical apart from the | |
281 | '-incoming' option on the destination side | |
282 | - swtpm command line parameters should point to two different | |
283 | directories on the source and destination swtpm (--tpmstate dir=...) | |
284 | (especially if different versions of libtpms were to be used on the | |
285 | same machine). | |
286 | ||
287 | VM migration across the network: | |
288 | - QEMU command line parameters should be identical apart from the | |
289 | '-incoming' option on the destination side | |
290 | - swtpm command line parameters should be identical | |
291 | ||
292 | VM Snapshotting: | |
293 | - QEMU command line parameters should be identical | |
294 | - swtpm command line parameters should be identical | |
295 | ||
296 | ||
297 | Besides that, migration failure reasons on the swtpm level may include | |
298 | the following: | |
299 | ||
300 | - the versions of the swtpm on the source and destination sides are | |
301 | incompatible | |
302 | - downgrading of TPM state may not be supported | |
303 | - the source and destination libtpms were compiled with different | |
304 | compile-time options and the destination side refuses to accept the | |
305 | state | |
306 | - different migration keys are used on the source and destination side | |
307 | and the destination side cannot decrypt the migrated state | |
308 | (swtpm ... --migration-key ... ) |