Return INV_CRB_CTRL_DATA for empty CRB control data on Start#4
Closed
dymk wants to merge 1 commit into
Closed
Conversation
d717a3e to
5fd3231
Compare
dymk
added a commit
to dymk/odp-platform-qemu-sbsa
that referenced
this pull request
Jun 12, 2026
Five test edits in e2e-tests/tests/tpm/src/main.rs, paired with the
SP-side fix (companion commit in mod/secure-services/odp-secure-services)
that returns INV_CRB_CTRL_DATA for empty CRB control data:
- Add TPM2_FFA_INV_CRB_CTRL_DATA constant (0x8e00_0006).
- tpm_start_closed_locality / tpm_start_locality_qualifier_closed:
change locality argument from 0 to 2. Localities 0 and 1 default to
Open after SP init (per odp-secure-services PR OpenDevicePartnership#76), but the test
name still wants to exercise the 'closed locality' branch — so use
locality 2 (or 3 or 4), which remain Closed by default. The DENIED
expectation is unchanged because locality 2 is genuinely
administratively disabled at boot.
- tpm_start_locality_no_crb_bits: change expected from DENIED to
INV_CRB_CTRL_DATA. The scenario is 'Start(LOCALITY) with neither
Request/Relinquish bit set' — per DEN0138 this is malformed CRB
control data, not a DENIED-class fault.
- tpm_start_command_locality_mismatch + tpm_start_command_idle_no_bits:
change expected from INV_ARG to INV_CRB_CTRL_DATA. Both exercise
the same code path now ('Start(COMMAND) with no command queued in
CRB'). The test name 'locality_mismatch' is historical from when
these tests were written assuming standalone-SP behavior; in the
live SP+EC scenario the EC's earlier Start(LOCALITY,0) traffic
sets active_locality=0, so the locality matches and execution
falls into handle_command, where the empty CRB now returns
INV_CRB_CTRL_DATA per DEN0138.
Also bumps the odp-secure-services submodule to 5fd3231 (the
companion SP fix at dymk/odp-secure-services#4) and temporarily
redirects .gitmodules to the dymk fork so CI can fetch the
submodule commit (per AGENTS.md cascade pattern — the URL is
restored to the OpenDevicePartnership org once the upstream SP PR
merges).
Verified locally inside the devcontainer: make e2e-test
QEMU_TIMEOUT=900 now reports RESULT: ALL TESTS PASSED (27/27),
including the four previously-failing or coincidentally-passing
tests above.
Stacked on top of PRs for issues #3 (TPM device) + #5 (CI gate)
+ #4 (uart-logger virt). The clean PR for this fix will target a
main that already has those landed.
Assisted-by: GitHub Copilot:claude-opus-4.7-1m-internal
Per ARM DEN0138 'TPM Service CRB Interface Over FF-A':
CRB_FFA_DENIED: the TPM has previously DISABLED locality
requests and command processing at the
given locality
CRB_FFA_INV_CRB_CTRL_DATA: CRB control data or locality control
data at the given TPM locality is not valid
The SP currently returns DENIED for two scenarios that don't match
the DENIED semantics:
1. handle_command() falls through to a default 'Denied' status
whenever no state-transition bit is set in the CRB control_request
/ control_start registers (e.g., the host issues Start(COMMAND)
before writing cmdReady).
2. handle_locality_request() returns 'Denied' when neither the
RELINQUISH nor REQUEST_ACCESS bit is set in locality_control.
Both are 'host gave us a Start with empty CRB control data', which
per DEN0138 is INV_CRB_CTRL_DATA, not DENIED. The TianoCore EDK2
client maps INV_CRB_CTRL_DATA to EFI_COMPROMISED_DATA and DENIED to
EFI_ACCESS_DENIED — confirming the spec's semantic distinction
between 'malformed CRB' and 'access disabled'.
Fix is two minimal edits to ec-service-lib/src/services/tpm.rs:
- handle_command(): early-return InvCrbCtrlData when both
crb_control_request and crb_control_start are zero.
- handle_locality_request(): change the 'no bits set' branch
return from Denied to InvCrbCtrlData.
Other paths (locality mismatch, closed locality, invalid arguments)
are left as-is — their existing return codes are spec-conformant.
Surfaced from systematic debugging of qemu-sbsa Phase 2 e2e tests
(tpm_start_command_locality_mismatch, tpm_start_command_idle_no_bits,
tpm_start_locality_no_crb_bits). The qemu-sbsa test expectations
are updated in a companion commit.
References:
- Linux kernel driver: drivers/char/tpm/tpm_crb_ffa.c (CRB_FFA_START documented function status codes)
- TianoCore EDK2: SecurityPkg/Library/Tpm2DeviceLibFfa/Tpm2ServiceFfaRaw.c::TranslateTpmReturnStatus
Assisted-by: GitHub Copilot:claude-opus-4.7-1m-internal
5fd3231 to
6d164c9
Compare
dymk
added a commit
to dymk/odp-platform-qemu-sbsa
that referenced
this pull request
Jun 12, 2026
Five test edits in e2e-tests/tests/tpm/src/main.rs, paired with the
SP-side fix (companion commit in mod/secure-services/odp-secure-services)
that returns INV_CRB_CTRL_DATA for empty CRB control data:
- Add TPM2_FFA_INV_CRB_CTRL_DATA constant (0x8e00_0006).
- tpm_start_closed_locality / tpm_start_locality_qualifier_closed:
change locality argument from 0 to 2. Localities 0 and 1 default to
Open after SP init (per odp-secure-services PR OpenDevicePartnership#76), but the test
name still wants to exercise the 'closed locality' branch — so use
locality 2 (or 3 or 4), which remain Closed by default. The DENIED
expectation is unchanged because locality 2 is genuinely
administratively disabled at boot.
- tpm_start_locality_no_crb_bits: change expected from DENIED to
INV_CRB_CTRL_DATA. The scenario is 'Start(LOCALITY) with neither
Request/Relinquish bit set' — per DEN0138 this is malformed CRB
control data, not a DENIED-class fault.
- tpm_start_command_locality_mismatch + tpm_start_command_idle_no_bits:
change expected from INV_ARG to INV_CRB_CTRL_DATA. Both exercise
the same code path now ('Start(COMMAND) with no command queued in
CRB'). The test name 'locality_mismatch' is historical from when
these tests were written assuming standalone-SP behavior; in the
live SP+EC scenario the EC's earlier Start(LOCALITY,0) traffic
sets active_locality=0, so the locality matches and execution
falls into handle_command, where the empty CRB now returns
INV_CRB_CTRL_DATA per DEN0138.
Also bumps the odp-secure-services submodule to 5fd3231 (the
companion SP fix at dymk/odp-secure-services#4) and temporarily
redirects .gitmodules to the dymk fork so CI can fetch the
submodule commit (per AGENTS.md cascade pattern — the URL is
restored to the OpenDevicePartnership org once the upstream SP PR
merges).
Verified locally inside the devcontainer: make e2e-test
QEMU_TIMEOUT=900 now reports RESULT: ALL TESTS PASSED (27/27),
including the four previously-failing or coincidentally-passing
tests above.
Stacked on top of PRs for issues #3 (TPM device) + #5 (CI gate)
+ #4 (uart-logger virt). The clean PR for this fix will target a
main that already has those landed.
Assisted-by: GitHub Copilot:claude-opus-4.7-1m-internal
Owner
Author
|
Superseded — promoted to upstream as OpenDevicePartnership#79, which merged at commit 29af461. The qemu-sbsa consumer side has now also landed via OpenDevicePartnership/odp-platform-qemu-sbsa#93 (merged at b3d09316). Closing the fork-review trail. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Per ARM DEN0138 TPM Service CRB Interface Over FF-A, the
Startfunction's response codes have these semantics:The SP currently returns
DENIEDfor two scenarios that don't fit the spec's DENIED semantics:handle_command()falls through to a defaultDeniedwhenever no state-transition bit is set in the CRBcontrol_request/control_startregisters (e.g., the host issuesStart(COMMAND)before writingcmdReady).handle_locality_request()returnsDeniedwhen neither theRELINQUISHnorREQUEST_ACCESSbit is set inlocality_control.Both cases are "host issued Start with empty CRB control data" — which per DEN0138 is
INV_CRB_CTRL_DATA, notDENIED. The semantic distinction is corroborated by two independent authoritative consumers of DEN0138:drivers/char/tpm/tpm_crb_ffa.c): theCRB_FFA_STARTdocstring lists the same four status codes with the same semantics.SecurityPkg/Library/Tpm2DeviceLibFfa/Tpm2ServiceFfaRaw.c::TranslateTpmReturnStatus): mapsINV_CRB_CTRL_DATA→EFI_COMPROMISED_DATAandDENIED→EFI_ACCESS_DENIED, confirming the distinction between "malformed CRB" and "access disabled."Diff
Two minimal edits to
ec-service-lib/src/services/tpm.rs:Other paths (locality mismatch, closed locality, invalid arguments, source-id check) are left as-is — their existing return codes are spec-conformant.
Surfaced from / verified by
Systematic debugging of
odp-platform-qemu-sbsa's Phase 2 e2e tests (tpm_start_command_locality_mismatch,tpm_start_command_idle_no_bits,tpm_start_locality_no_crb_bits). Companion test-side change is opened againstdymk/odp-platform-qemu-sbsa— it updates the test expectations toINV_CRB_CTRL_DATAfor the affected cases and restructures the "closed locality" tests to target a locality that's actually closed by default (locality 2 instead of 0, since OpenDevicePartnership#76 made 0+1 default-open).Verified locally inside the qemu-sbsa devcontainer: with this SP fix + the companion test fix + the downstream
odp-platform-qemu-sbsaPRs that unblock the harness (TPM device wiring + uart-logger virt retarget),make e2e-test QEMU_TIMEOUT=900reportsRESULT: ALL TESTS PASSED(27/27).