Repository navigation
Conversation
This branch has not been deployed
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.
Problem
TDX module 1.5.34 and 2.0.18 add
TDG.MR.KEY.GET(TDCALL leaf 29). It derives a key from a platform hardware secret and the TD measurements chosen by a key policy (MRTD, MROWNER, RTMR0-3, masked ATTRIBUTES/XFAM, salt). That is native TD sealing: the same measured TD on the same platform gets the same key, with no external key provider. Today the only local option is thelocal-sgxprovider, which runs a Gramine enclave next to the VMM.The dstack guest kernel (6.18.40) has no wrapper for this TDCALL and no way to reach it from user space. Upstream Linux has none either.
The TDX module enables the leaf for a TD only when one of these is set:
TD_PARAMS.CONFIG_FLAGS.SEALING, set by the VMM atTDH.MNG.INIT. That would need changes to QEMU and KVM on the host.TDCS.TD_CTLS.ENABLE_HW_KEYS(bit 4). In the 1.5.34 and 2.0.18 metadata tables,TD_CTLShasprod_wr_mask = 0andguest_wr_mask = 0x800000000000001F, so only the guest can write this bit.So the feature can be enabled from the guest alone, with no host changes.
Fix
Add guest kernel patch
0011:tdx_mcall_get_key()inarch/x86/coco/tdx/tdx.cwrapsTDG.MR.KEY.GET. It first checksTDX_FEATURES0.HW_SEALING(bit 12) withTDG.SYS.RD. If the bit is clear it returns-EOPNOTSUPP, because the module answersTDX_OPERAND_INVALIDto every request on a CPU withoutSEAMOPS(SEAMGETKEY). If the TDCALL returnsTDX_MR_KEY_GET_NOT_SUPPORTED, it setsTD_CTLS.ENABLE_HW_KEYSwithTDG.VM.WRand retries once. A VMM-providedCONFIG_FLAGS.SEALINGtherefore keeps working, andTD_CTLSis not touched when it is set.TDX_CMD_GET_KEYioctl on/dev/tdx_guest(_IOWR('T', 0x10, struct tdx_key_req)) passes a raw 128-byteTDKEYREQUESTthrough and returns the key and its size in bits. The kernel does not interpret the request; the TDX module validates it. The key buffer is freed withkfree_sensitive().-EINVAL, requested SVN newer than the current TCB →-EPERM, busy →-EBUSY.The ioctl number is
0x10so it can't collide with Intel's downstream'T'numbers (dstack'stdx-attestalready uses'T', 3for the legacy RTMR extend).Bit 12 of
TDX_FEATURES0is reserved in the 1.5.28 and 2.0.16 modules, so checking it is safe on older modules. On TDX 1.0, whereTDG.SYS.RDis unavailable, the result is also-EOPNOTSUPP.This PR only adds the guest OS capability. Nothing in dstack calls the ioctl yet, so key derivation and measurements of existing deployments do not change.
Verification
I built the mkosi kernel with patches 0001-0011 (
checkpatch.pl: 0 errors, 0 warnings). I booted it as a throwaway TD with a static test/init: 1 vCPU, 1 GiB, launched by plain QEMU and not managed by dstack-vmm.TDX_FEATURES0.HW_SEALINGTDX_CMD_GET_KEY0x10003c22d2de102…3afa, TEE_TCB_SVN0903)-EOPNOTSUPP0x210002e0346bc77a…31a1)-EOPNOTSUPPOn both hosts
TDX_CMD_GET_REPORT0and the sysfs RTMR extend still work. Before I added the capability check, the b200 TD loggedTDG.MR.KEY.GET→0xC000010000000000(TDX_OPERAND_INVALID), withTDX_FEATURES0 = 0x5ad9336f3f0fff,CONFIG_FLAGS = 0x5(SEALING clear) andTD_CTLS = 0xf. That matches the module source:if (!global_data->sealing_supported) return TDX_OPERAND_INVALID;.Not yet verified end to end. None of the machines available to me report
HW_SEALING = 1, so the success path is untested on hardware: theENABLE_HW_KEYSopt-in, key derivation, determinism, and policy/SVN behavior. b200's microcode is several revisions behind Intel's latest GNR release (0x1000434, microcode-20260811). Whether a newer microcode turns onSEAMGETKEYis unconfirmed. Upgrading it needs a host reboot, which I did not do on a production host. Keeping this as a draft until it runs on a platform that reportsHW_SEALING = 1.Follow-ups (separate PRs)
tdx-attestbinding plus adstack-utilprobe.tdx-sealkey provider as an alternative tolocal-sgx. This needs design decisions first:local-sgxwould be MRTD + RTMR0-3 at the same boot point.MRCONFIGIDpolicy bit but does not mix MRCONFIGID into the derivation.