Thanks to visit codestin.com
Credit goes to github.com

Skip to content

TPM code fixes - #8305

Merged
liuw merged 4 commits into
cloud-hypervisor:mainfrom
liuw:mshv-tpm-fix
Jun 1, 2026
Merged

liuw merged 4 commits into
cloud-hypervisor:mainfrom
liuw:mshv-tpm-fix

Conversation

@liuw

@liuw liuw commented May 30, 2026

Copy link
Copy Markdown
Member

TPM test didn't work on MSHV. This series attempts to fix it.

@liuw
liuw requested a review from a team as a code owner May 30, 2026 03:57
liuw added 2 commits May 29, 2026 21:00
The swtpm control socket is a Unix SOCK_STREAM, so a single read() is
not guaranteed to return the full response in one shot. swtpm may
split a response into multiple writes, in which case the existing
single read() returns only the first chunk and subsequent parsing
fails with "Response for ... cmd is of incorrect length". This has
been observed on Azure Linux during emulator initialization.

In addition, when swtpm encounters an error processing a control
command (e.g. PTM_BAD_ORDINAL = 0x0A returned for commands issued
before CMD_INIT), the swtpm protocol returns only the 4-byte result
code instead of the full response. Blindly looping until msg_len_out
bytes arrive would deadlock in that case.

Add SocketDev::read_exact() that loops until the requested number of
bytes has been received (retrying on EINTR), and rework
run_control_cmd() to:

  * read_exact the 4-byte result code first;
  * on error, set the result code on the PTM message and return a
    clean error without waiting for a payload that will never arrive;
  * on success, read_exact the remaining (msg_len_out - 4) payload
    bytes.

Assisted-by: Copilot:GPT-5.5
Signed-off-by: Wei Liu <[email protected]>
Emulator::new() refused to start the VMM unless the TPM Establishment
bit (TPM_LOC_STATE.tpmEstablished, bit 0) was already set, aborting
with "TPM not in established state" otherwise.

That gate is not justified by the TCG PC Client Platform TPM Profile
(PTP) specification:

  * tpmEstablished == 0 is the defined default state after a cold
    reset of the TPM.
  * The bit transitions to 1 only after a TPM2_Startup is issued from
    Locality 3 or 4 -- something the guest firmware/OS may or may not
    ever do, and which has not happened by the time the VMM is wiring
    up the device.

So the check was rejecting the spec-defined normal case. It also had
inverted internal naming (the boolean called "established_flag" was
true when the bit was 0), which is what made the conditional read as
if it were testing the opposite of what it actually tested.

In practice the check happened to pass on KVM and fail on MSHV (issue
socket, but the bug is independent of the backend: the VMM has no
business gating startup on tpmEstablished at all.

Drop the check. The bit is still surfaced to the guest from
Tpm::read() when CRB_LOC_STATE is read, which is the only place the
PTP spec requires it to be visible.

Assisted-by: Copilot:GPT-5.5
Signed-off-by: Wei Liu <[email protected]>
liuw added 2 commits May 29, 2026 21:14
The helper used to communicate the TPM Establishment bit between the
swtpm backend and the CRB device had inverted semantics:

    self.established_flag = est.resp.bit == 0;

so `established_flag == true` actually meant "*not* established". The
device-side call site then double-negated:

    if !self.emulator.get_established_flag() {
        val |= 0x1;  // tpmEstablished in TPM_LOC_STATE
    }

The end-to-end behaviour was correct but the boundary between the
swtpm-specific backend and the (TCG-spec defined) CRB device was hard
to follow and easy to misuse -- the now-removed pre-init check in
Emulator::new() was an example of that confusion (it errored out with
"TPM not in established state" precisely when the TPM *was*
established).

Per the TCG PC Client Platform TPM Profile (PTP) specification, bit 0
of TPM_LOC_STATE_x is `tpmEstablished`:

  * 0 = default state after a cold reset
  * 1 = a TPM2_Startup from Locality 3 or 4 has occurred

Rename the backend accessor to `get_established_bit()` and return the
bit value directly (true == 1, false == 0). The CRB device then simply
forwards the bit, with no inversion, which makes the spec mapping
obvious and removes swtpm-flavoured naming from the device layer.

No functional change.

Asissted-by: Copilot:GPT-5.5
Signed-off-by: Wei Liu <[email protected]>
@liuw

liuw commented May 30, 2026

Copy link
Copy Markdown
Member Author

The MSHV TPM test is passing now.

PASS [  34.873s] ( 70/146) ***-hypervisor::integration common_parallel::test_tpm

@liuw
liuw marked this pull request as draft May 31, 2026 04:49
@liuw
liuw marked this pull request as ready for review June 1, 2026 16:30
@liuw

liuw commented Jun 1, 2026

Copy link
Copy Markdown
Member Author

I checked our internal bug report. The test doesn't fail 100% of the time. Hopefully this fix can help with that.

@liuw
liuw added this pull request to the merge queue Jun 1, 2026
Merged via the queue into cloud-hypervisor:main with commit dfcc02f Jun 1, 2026
41 checks passed
@liuw
liuw deleted the mshv-tpm-fix branch June 1, 2026 18:42
@phip1611 phip1611 linked an issue Jun 2, 2026 that may be closed by this pull request
@rbradford rbradford added the bug-fix Bug fix to include in release notes label Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix Bug fix to include in release notes

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

test_tpm failing for MSHV in CI

2 participants