Skip to content

Commit 695d665

Browse files
authored
QemuRunner TPM Updates for Q35 and SBSA (#1429)
## Description Updated QemuRunner.py to no longer point to the /tmp/mytpm1 directory from TPM_DEV, instead it now points to our build output folder. This prevents an issue where creation of the directory is a manual step and running could fail if a user does not do the mkdir step. Renamed TPM_DEV to SWTPM_ENABLE. SWTPM_ENABLE is TRUE by default. This enable allows for another user, if they so wish, to use a different TPM in place of the SWTPM by setting SWTPM_ENABLE to FALSE. - [x] Impacts functionality? - [ ] Impacts security? - [ ] Breaking change? - [ ] Includes tests? - [ ] Includes documentation? ## How This Was Tested Built and ran both Q35 and SBSA with TPM enabled. Verified functionality and swtpm created at the build output directory. ## Integration Instructions N/A
1 parent 7193e87 commit 695d665

8 files changed

Lines changed: 82 additions & 99 deletions

File tree

.github/workflows/platform-ci.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,19 @@ jobs:
151151
- name: Install dependencies
152152
run: pip install -r pip-requirements.txt
153153

154-
# Install swtpm and prepare its state dir for TPM-enabled runs. Exposes
155-
# TPM_ARGS for the build/run steps below.
154+
# Install swtpm on all Linux runners. QemuRunner.py launches swtpm by
155+
# default (SWTPM_ENABLE=TRUE) on Linux.
156156
- name: Setup swtpm
157-
if: matrix.variant == 'TPM'
157+
if: runner.os == 'Linux'
158158
run: |
159159
apt-get update
160160
apt-get install -y swtpm swtpm-tools
161-
mkdir -p /tmp/mytpm1
162-
echo "TPM_ARGS=BLD_*_TPM_ENABLE=TRUE TPM_DEV=/tmp/mytpm1/swtpm-sock" >> $GITHUB_ENV
161+
162+
# Expose TPM_ARGS for the build/run steps below on TPM-enabled runs.
163+
- name: Set TPM build args
164+
if: matrix.variant == 'TPM'
165+
run: |
166+
echo "TPM_ARGS=BLD_*_TPM_ENABLE=TRUE" >> $GITHUB_ENV
163167
164168
# Run the build-platform action, which calls stuart_setup, stuart_update, and stuart_build
165169
- name: Prepare and Build ${{ matrix.platform }} ${{ matrix.target }} ${{ matrix.tool-chain}}

Platforms/Docs/Common/Features/feature_tpm.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,18 @@ Swtpm can be installed from the linux package managers.
1010
sudo apt-get install swtpm
1111
```
1212

13-
To start the TPM emulator, invoke swtpm with a state file location and character
14-
device.
13+
To run using this TPM, build and run with the following options. `SWTPM_ENABLE`
14+
enables the swtpm emulator that is started automatically by `QemuRunner.py`.
15+
`SWTPM_ENABLE` is `TRUE` by default.
1516

17+
for the Q35 platform:
1618
```bash
17-
mkdir /tmp/mytpm1
18-
swtpm socket --tpmstate dir=/tmp/mytpm1 \
19-
--ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
20-
--tpm2 \
21-
--log level=20
19+
stuart_build -c Platforms/QemuQ35Pkg/PlatformBuild.py --flashrom TOOL_CHAIN_TAG=GCC5 BLD_*_TPM_ENABLE=TRUE
2220
```
2321

24-
To run Q35 using this TPM, build and run with the following options. `TPM_DEV` should
25-
point to the path of the character device from the above swtpm command.
26-
27-
```bash
28-
stuart_build -c Platforms/QemuQ35Pkg/PlatformBuild.py --flashrom TOOL_CHAIN_TAG=GCC5 BLD_*_TPM_ENABLE=TRUE TPM_DEV=/tmp/mytpm1/swtpm-sock
29-
```
30-
31-
or for SBSA platform:
22+
for the SBSA platform:
3223
```bash
33-
stuart_build -c Platforms/QemuSbsaPkg/PlatformBuild.py --flashrom TOOL_CHAIN_TAG=GCC5 BLD_*_TPM2_ENABLE=TRUE TPM_DEV=/tmp/mytpm1/swtpm-sock
24+
stuart_build -c Platforms/QemuSbsaPkg/PlatformBuild.py --flashrom TOOL_CHAIN_TAG=GCC5 BLD_*_TPM2_ENABLE=TRUE
3425
```
3526

3627
In the window running swtpm, there should be output from the TPM communication.

Platforms/Docs/Q35/Features/feature_tpm_replay.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Or, as a `stuart_build` argument:
2222

2323
```bash
2424
> stuart_build -c Platforms/QemuQ35Pkg/PlatformBuild.py --flashrom TOOL_CHAIN_TAG=GCC5 BLD_*_TPM_ENABLE=TRUE \
25-
BLD_*_TPM_REPLAY_ENABLED=TRUE TPM_DEV=/tmp/mytpm1/swtpm-sock
25+
BLD_*_TPM_REPLAY_ENABLED=TRUE
2626
```
2727

2828
Note that the TPM driver stack is also disabled by default in QEMU firmware. It requires a TPM emulator and currently

Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,15 @@ def QueryQemuVersion(exec):
4848

4949

5050
@staticmethod
51-
def RunThread(env):
52-
"""Runs TPM in a separate thread"""
53-
tpm_path = env.GetValue("TPM_DEV")
54-
if tpm_path is None:
55-
logging.critical("TPM Path Invalid")
56-
return
57-
51+
def RunSwTpmThread(tpm_dir, tpm_sock):
52+
"""Runs SWTPM in a separate thread"""
5853
tpm_cmd = "swtpm"
59-
tpm_args = f"socket --tpmstate dir={'/'.join(tpm_path.rsplit('/', 1)[:-1])} --ctrl type=unixio,path={tpm_path} --tpm2 --log level=20"
54+
tpm_args = f"socket --tpmstate dir={tpm_dir} --ctrl type=unixio,path={tpm_sock} --tpm2 --log level=1"
6055

6156
# Start the TPM emulator in a separate thread
6257
ret = utility_functions.RunCmd(tpm_cmd, tpm_args)
6358
if ret != 0:
64-
logging.critical("Failed to start TPM emulator.")
59+
logging.critical("Failed to start SWTPM emulator.")
6560
return
6661

6762
@staticmethod
@@ -217,13 +212,21 @@ def Runner(env):
217212
args += f" -smbios type=1,manufacturer=Palindrome,product=\"QEMU Q35\",family=QEMU,version=\"{'.'.join(qemu_version)}\",serial=42-42-42-42,uuid=9de555c0-05d7-4aa1-84ab-bb511e3a8bef"
218213
args += f" -smbios type=3,manufacturer=Palindrome,serial=40-41-42-43{boot_selection}"
219214

220-
# TPM in Linux
221-
tpm_dev = env.GetValue("TPM_DEV")
222-
if tpm_dev is not None:
223-
args += f" -chardev socket,id=chrtpm,path={tpm_dev}"
215+
sw_tpm_thread = None
216+
sw_tpm_enable = env.GetValue("SWTPM_ENABLE", "TRUE")
217+
if os.name == 'nt':
218+
sw_tpm_enable = "FALSE"
219+
if str(sw_tpm_enable).upper() == "TRUE":
220+
tpm_dir = env.GetValue("BUILD_OUTPUT_BASE")
221+
tpm_sock = os.path.join(tpm_dir, "swtpm-sock")
222+
args += f" -chardev socket,id=chrtpm,path={tpm_sock}"
224223
args += " -tpmdev emulator,id=tpm0,chardev=chrtpm"
225224
args += " -device tpm-tis,tpmdev=tpm0"
226225

226+
logging.info("Starting TPM emulator in a different thread.")
227+
sw_tpm_thread = threading.Thread(target=QemuRunner.RunSwTpmThread, args=(tpm_dir, tpm_sock))
228+
sw_tpm_thread.start()
229+
227230
if (env.GetValue("QEMU_HEADLESS").upper() == "TRUE"):
228231
args += " -display none" # no graphics
229232
else:
@@ -254,12 +257,6 @@ def Runner(env):
254257
except Exception:
255258
std_handle = None
256259

257-
thread = None
258-
if tpm_dev:
259-
# also spawn the TPM emulator on a different thread
260-
logging.critical("Starting TPM emulator in a different thread.")
261-
thread = threading.Thread(target=QemuRunner.RunThread, args=(env,))
262-
thread.start()
263260

264261
# Run QEMU
265262
try:
@@ -285,7 +282,7 @@ def Runner(env):
285282
# Linux version of QEMU will mess with the print if its run failed, let's just restore it anyway
286283
utility_functions.RunCmd('stty', 'sane', capture=False)
287284

288-
if thread is not None:
289-
logging.critical("Terminate TPM emulator by using Crtl + C now!")
290-
thread.join()
285+
if sw_tpm_thread is not None:
286+
sw_tpm_thread.join()
287+
291288
return ret

Platforms/QemuSbsaPkg/Plugins/QemuRunner/QemuRunner.py

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,15 @@ def QueryQemuVersion(exec):
4545

4646

4747
@staticmethod
48-
def RunThread(env):
49-
''' Runs TPM in a separate thread '''
50-
tpm_path = env.GetValue("TPM_DEV")
51-
if tpm_path is None:
52-
logging.critical("TPM Path Invalid")
53-
return
54-
48+
def RunSwTpmThread(tpm_dir, tpm_sock):
49+
"""Runs SWTPM in a separate thread"""
5550
tpm_cmd = "swtpm"
56-
tpm_args = f"socket --tpmstate dir={"/".join(tpm_path.rsplit("/", 1)[:-1])} --ctrl type=unixio,path={tpm_path} --tpm2 --log level=1"
51+
tpm_args = f"socket --tpmstate dir={tpm_dir} --ctrl type=unixio,path={tpm_sock} --tpm2 --log level=1"
5752

5853
# Start the TPM emulator in a separate thread
5954
ret = utility_functions.RunCmd(tpm_cmd, tpm_args)
6055
if ret != 0:
61-
logging.critical("Failed to start TPM emulator.")
56+
logging.critical("Failed to start SWTPM emulator.")
6257
return
6358

6459

@@ -129,16 +124,19 @@ def Runner(env):
129124
args += " -drive if=pflash,format=raw,unit=1,file=" + \
130125
code_fd + ",readonly=on"
131126

132-
tpm_dev = env.GetValue("TPM_DEV")
133-
thread = None
134-
if tpm_dev is not None:
135-
args += f" -chardev socket,id=chrtpm,path={tpm_dev}"
127+
sw_tpm_thread = None
128+
sw_tpm_enable = env.GetValue("SWTPM_ENABLE", "TRUE")
129+
if os.name == 'nt':
130+
sw_tpm_enable = "FALSE"
131+
if str(sw_tpm_enable).upper() == "TRUE":
132+
tpm_dir = env.GetValue("BUILD_OUTPUT_BASE")
133+
tpm_sock = os.path.join(tpm_dir, "swtpm-sock")
134+
args += f" -chardev socket,id=chrtpm,path={tpm_sock}"
136135
args += " -tpmdev emulator,id=tpm0,chardev=chrtpm"
137136

138-
# also spawn the TPM emulator on a different thread
139-
logging.critical("Starting TPM emulator in a different thread.")
140-
thread = threading.Thread(target=QemuRunner.RunThread, args=(env,))
141-
thread.start()
137+
logging.info("Starting TPM emulator in a different thread.")
138+
sw_tpm_thread = threading.Thread(target=QemuRunner.RunSwTpmThread, args=(tpm_dir, tpm_sock))
139+
sw_tpm_thread.start()
142140

143141
# Add XHCI USB controller and mouse
144142
args += " -device qemu-xhci,id=usb"
@@ -206,8 +204,7 @@ def Runner(env):
206204
# Linux version of QEMU will mess with the print if its run failed, let's just restore it anyway
207205
utility_functions.RunCmd('stty', 'sane', capture=False)
208206

209-
if thread is not None:
210-
logging.critical("Terminate TPM emulator by using Crtl + C now!")
211-
thread.join()
207+
if sw_tpm_thread is not None:
208+
sw_tpm_thread.join()
212209

213210
return ret

docs/TPM/TpmQemuQ35.md

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@ See [swtpm Setup](#swtpm-setup) for the full setup commands.
2929

3030
## Build Configuration
3131

32-
The TPM is disabled by default. To enable it, pass the build define and provide the swtpm
33-
socket path or provide it in a BuildConfig.conf file placed at the root level of the repo:
32+
The TPM is disabled by default. To enable it, set `BLD_*_TPM_ENABLE=TRUE` on the command line or in a
33+
BuildConfig.conf file placed at the root level of the repo:
3434

3535
```bash
3636
stuart_build -c Platforms/QemuQ35Pkg/PlatformBuild.py --FlashRom \
3737
BLD_*_TPM_ENABLE=TRUE \
38-
TPM_DEV=/tmp/mytpm1/swtpm-sock
3938
```
4039

4140
The following defines control TPM behavior in `QemuQ35Pkg.dsc`:
@@ -324,31 +323,30 @@ swtpm socket \
324323

325324
### Automatic Setup (QemuRunner)
326325

327-
When the `TPM_DEV` environment variable is set, `QemuRunner.py` automatically starts
328-
swtpm in a background thread before launching QEMU:
326+
When `SWTPM_ENABLE=TRUE`, `QemuRunner.py` automatically starts swtpm in a background thread
327+
before launching QEMU. The swtpm state directory is set to `BUILD_OUTPUT_BASE` and the
328+
Unix socket is placed at `{BUILD_OUTPUT_BASE}/swtpm-sock`:
329329

330330
```python
331331
# Platforms/QemuQ35Pkg/Plugins/QemuRunner/QemuRunner.py
332332
@staticmethod
333-
def RunThread(env):
334-
tpm_path = env.GetValue("TPM_DEV")
333+
def RunSwTpmThread(tpm_dir, tpm_sock):
334+
"""Runs TPM in a separate thread"""
335335
tpm_cmd = "swtpm"
336-
tpm_args = (
337-
f"socket --tpmstate dir={'/'.join(tpm_path.rsplit('/', 1)[:-1])} "
338-
f"--ctrl type=unixio,path={tpm_path} --tpm2 --log level=20"
339-
)
340-
utility_functions.RunCmd(tpm_cmd, tpm_args)
336+
tpm_args = f"socket --tpmstate dir={tpm_dir} --ctrl type=unixio,path={tpm_sock} --tpm2 --log level=1"
341337
```
342338

343-
The thread is launched before QEMU starts and joined after QEMU exits. The user is
344-
prompted to press Ctrl+C to terminate swtpm at shutdown.
339+
The thread is launched before QEMU starts and joined after QEMU exits. Note that the SWTPM
340+
is enabled by default. You can disable it by setting `SWTPM_ENABLE=FALSE` from the command
341+
line or in the BuildConfig.conf file.
345342

346343
### QEMU Arguments
347344

348-
The `QemuCommandBuilder.with_tpm()` method adds three arguments for Q35:
345+
When `SWTPM_ENABLE=TRUE`, `QemuRunner.py` adds the following to the QEMU command line
346+
(with the socket path under `BUILD_OUTPUT_BASE`):
349347

350348
```text
351-
-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock
349+
-chardev socket,id=chrtpm,path={BUILD_OUTPUT_BASE}/swtpm-sock
352350
-tpmdev emulator,id=tpm0,chardev=chrtpm
353351
-device tpm-tis,tpmdev=tpm0
354352
```

docs/TPM/TpmQemuSbsa.md

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,12 @@ See [swtpm Setup](#swtpm-setup) for the full setup commands.
3636

3737
## Build Configuration
3838

39-
The TPM is disabled by default. To enable it, pass the build define and provide the swtpm
40-
socket path or provide it in a BuildConfig.conf file placed at the root level of the repo:
39+
The TPM is disabled by default. To enable it, set `BLD_*_TPM2_ENABLE=TRUE` on the command line or in a
40+
BuildConfig.conf file placed at the root level of the repo:
4141

4242
```bash
4343
stuart_build -c Platforms/QemuSbsaPkg/PlatformBuild.py --FlashRom \
4444
BLD_*_TPM2_ENABLE=TRUE \
45-
TPM_DEV=/tmp/mytpm1/swtpm-sock
4645
```
4746

4847
The following defines control TPM behavior in `QemuSbsaPkg.dsc`:
@@ -274,7 +273,7 @@ The external CRB connects to the `swtpm` process through QEMU's chardev/tpmdev
274273
infrastructure:
275274

276275
```text
277-
QEMU args: -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock
276+
QEMU args: -chardev socket,id=chrtpm,path={BUILD_OUTPUT_BASE}/swtpm-sock
278277
-tpmdev emulator,id=tpm0,chardev=chrtpm
279278
```
280279

@@ -518,31 +517,30 @@ swtpm socket \
518517

519518
### Automatic Setup (QemuRunner)
520519

521-
When the `TPM_DEV` environment variable is set, `QemuRunner.py` automatically starts
522-
swtpm in a background thread before launching QEMU:
520+
When `SWTPM_ENABLE=TRUE`, `QemuRunner.py` automatically starts swtpm in a background thread
521+
before launching QEMU. The swtpm state directory is set to `BUILD_OUTPUT_BASE` and the
522+
Unix socket is placed at `{BUILD_OUTPUT_BASE}/swtpm-sock`:
523523

524524
```python
525525
# Platforms/QemuSbsaPkg/Plugins/QemuRunner/QemuRunner.py
526526
@staticmethod
527-
def RunThread(env):
528-
tpm_path = env.GetValue("TPM_DEV")
527+
def RunSwTpmThread(tpm_dir, tpm_sock):
528+
"""Runs SWTPM in a separate thread"""
529529
tpm_cmd = "swtpm"
530-
tpm_args = (
531-
f"socket --tpmstate dir={'/'.join(tpm_path.rsplit('/', 1)[:-1])} "
532-
f"--ctrl type=unixio,path={tpm_path} --tpm2 --log level=20"
533-
)
534-
utility_functions.RunCmd(tpm_cmd, tpm_args)
530+
tpm_args = f"socket --tpmstate dir={tpm_dir} --ctrl type=unixio,path={tpm_sock} --tpm2 --log level=1"
535531
```
536532

537-
The thread is launched before QEMU starts and joined after QEMU exits. The user is
538-
prompted to press Ctrl+C to terminate swtpm at shutdown.
533+
The thread is launched before QEMU starts and joined after QEMU exits. Note that the SWTPM
534+
is enabled by default. You can disable it by setting `SWTPM_ENABLE=FALSE` from the command
535+
line or in the BuildConfig.conf file.
539536

540537
### QEMU Arguments
541538

542-
The `QemuCommandBuilder.with_tpm()` method adds:
539+
When `SWTPM_ENABLE=TRUE`, `QemuRunner.py` adds the following to the QEMU command line
540+
(with the socket path under `BUILD_OUTPUT_BASE`):
543541

544542
```text
545-
-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock
543+
-chardev socket,id=chrtpm,path={BUILD_OUTPUT_BASE}/swtpm-sock
546544
-tpmdev emulator,id=tpm0,chardev=chrtpm
547545
```
548546

docs/TPM/TpmShellAppQemu.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ On SBSA, the TpmShellApp is placed directly in the firmware volume, which is map
3636
```bash
3737
stuart_build -c Platforms/QemuSbsaPkg/PlatformBuild.py --FlashRom \
3838
BLD_*_TPM2_ENABLE=TRUE \
39-
TPM_DEV=/tmp/mytpm1/swtpm-sock
4039
```
4140

4241
At the UEFI shell, run:
@@ -65,7 +64,6 @@ binaries are copied to the virtual drive:
6564
```bash
6665
stuart_build -c Platforms/QemuQ35Pkg/PlatformBuild.py --FlashRom \
6766
BLD_*_TPM_ENABLE=TRUE \
68-
TPM_DEV=/tmp/mytpm1/swtpm-sock \
6967
FILE_REGEX=TpmShellApp.efi
7068
```
7169

0 commit comments

Comments
 (0)