Skip to content

vTPM on KVM does not persist data (ACS 4.20.1.0, Ubuntu 24.04) #11842

Open

Description

@jgotteswinter

problem

after a shutdown, the /var/lib/libvirt/swtpm/ which holds the tpm data is gone. When starting the vm again, the folder is re-created with empty tpm files.

I am using a similar tpm definition in manually configured kvm guests, if those vm are powered off the folder remains.

versions

4.20.1.0
Ubuntu 24.04

The steps to reproduce the bug

root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# echo "Hello, TPM!" > datafile
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# tpm2_nvwrite -C o -i datafile 0x1500016
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# tpm2_nvread -C o 0x1500016
WARN: Reading full size of the NV index
Hello, TPM!

Instance power cycle, and tryi to read our value again from the tpm

root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# tpm2_nvread -C o 0x1500016
WARN: Reading full size of the NV index
WARNING:esys:src/tss2-esys/api/Esys_NV_ReadPublic.c:309:Esys_NV_ReadPublic_Finish() Received TPM Error
ERROR:esys:src/tss2-esys/esys_tr.c:243:Esys_TR_FromTPMPublic_Finish() Error NV_ReadPublic ErrorCode (0x0000018b)
ERROR:esys:src/tss2-esys/esys_tr.c:398:Esys_TR_FromTPMPublic() Error TR FromTPMPublic ErrorCode (0x0000018b)
ERROR: Esys_TR_FromTPMPublic(0x18B) - tpm:handle(1):the handle is not correct for the use
ERROR: Unable to run tpm2_nvread
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:

What to do about it?

No response

Activity

  1. added this to the 4.20.3 milestone on Oct 15, 2025
  2. weizhouapache commented on Oct 15, 2025

    @weizhouapache
    Member

    @jgotteswinter
    added to 4.20.3.0 milestone

  3. weizhouapache commented on Oct 15, 2025

    @weizhouapache
    Member

    if vm runs on local storage, this might work

    @@ -123,7 +123,7 @@
           <alias name='input2'/>
         </input>
         <tpm model='tpm-tis'>
    -      <backend type='emulator' version='2.0'/>
    +      <backend type='emulator' version='2.0' persistent_state='yes'/>
           <alias name='tpm0'/>
         </tpm>
    

    however, if vm runs on shared storage, when vm is migrated, or started on another host, it will not work, as the tpm file is saved on the original host, for example /var/lib/libvirt/swtpm/<vm uuid>/tpm2/tpm2-00.permall

    we could save the tpm file on the same primary pool as ROOT disk, for example <path of ROOT disk>.tpm2, add then create a vm with tpm device (it is supported since libivrt v10.10.0, so it does not work on RHEL 8/9 and ubuntu 22/24, it only works with RHEL 10)

           <alias name='input2'/>
         </input>
         <tpm model='tpm-tis'>
    -      <backend type='emulator' version='2.0'/>
    +      <backend type='emulator' version='2.0' persistent_state='yes'>
    +          <source type='file' path='<path of ROOT disk>.tpm2'/>
    +      </backend>
           <alias name='tpm0'/>
         </tpm>
    

    then we need to handle the migration of the tpm2 file when migrate ROOT disk to another storage pool.

  4. jgotteswinter commented on Oct 15, 2025

    @jgotteswinter
    Author

    i am using the swtpm together with manually deployed vms, using this tpm definition

        <tpm model='tpm-tis'>
          <backend type='emulator' version='2.0'/>
          <alias name='tpm0'/>
        </tpm>
    

    the files remain, even after the vm has been powered off

  5. weizhouapache commented on Oct 15, 2025

    @weizhouapache
    Member

    i am using the swtpm together with manually deployed vms, using this tpm definition

        <tpm model='tpm-tis'>
          <backend type='emulator' version='2.0'/>
          <alias name='tpm0'/>
        </tpm>
    

    the files remain, even after the vm has been powered off

    it may be because the vms you created are defined and persistent on the kvm host.
    when you stop them, you can still find them by virsh list --all

    but the vms created by ACS, are not persistent on the kvm host.

  6. jgotteswinter commented on Oct 15, 2025

    @jgotteswinter
    Author

    yes, you are absolutely right

  7. jgotteswinter commented on Oct 15, 2025

    @jgotteswinter
    Author

    i did not yet test moving the tpm files to a different host, but it might be also needed to handle /var/lib/swtpm-localca to get migration working

  8. jgotteswinter commented on Nov 12, 2025

    @jgotteswinter
    Author

    Is there currently any warning or hint in the docs somewhere that the current implementation is non-persisting? I think this should mentioned.

  9. weizhouapache commented on Nov 12, 2025

    @weizhouapache
    Member

    Is there currently any warning or hint in the docs somewhere that the current implementation is non-persisting? I think this should mentioned.

    created a doc PR: apache/cloudstack-documentation#598

  10. abh1sar commented on Jan 5, 2026

    @abh1sar
    Contributor

    @weizhouapache this just needs a documentation update, right?

  11. added theissue type on Jan 5, 2026
  12. moved this from Todo to Dev In Progress in Apache CloudStack BugFest - Issueson Jan 5, 2026
  13. weizhouapache commented on Jan 6, 2026

    @weizhouapache
    Member

    @weizhouapache this just needs a documentation update, right?

    yes.
    we can consider it as a known limitation as of now, and improve it in the future release, for example 4.23

  14. abh1sar commented on Jan 7, 2026

    @abh1sar
    Contributor
  15. modified the milestones: 4.20.3, 4.23.0 on Jan 7, 2026
  16. daviftorres commented on Feb 25, 2026

    @daviftorres
    Contributor

    Dear @abh1sar , is this fix also going to be available on 4.22.1? Regards,

  17. sureshanaparti commented on Feb 26, 2026

    @sureshanaparti
    Contributor

    @daviftorres the doc update with known limitation will be available in 4.22.1 as well.

  18. jgotteswinter commented on Feb 26, 2026

    @jgotteswinter
    Author

    Wouldnt it be possible to add an option which persists a vm on a specific host? From my understanding it would be sufficient to make the libvirt xml persistent.

    I gave the Cloudstack source to the AI together with the Bugreport and the initial implementation ticket to see what kind of solutions could be implemented. It seems like there is a flag in Libvirt 7.0+ "persistent_state XML attributes". Adding this to the swtpm part should keep the tpm files, and i think this would help if the instance is fixed to a specific compute node.

  19. modified the milestones: 4.23.0, 4.24.0 on May 11, 2026
  20. weizhouapache commented on Jul 6, 2026

    @weizhouapache
    Member

    related issue: #12427

  21. modified the milestones: 24.0, 25.0 on Oct 29, 2026
  22. MitchDrage commented on Nov 12, 2026

    @MitchDrage
    Contributor

    I'd like to take this on. I'm planning to do it in two parts.

    Part 1: keep the TPM on the same host.
    Right now libvirt deletes the TPM data every time the VM stops. Setting persistent_state='yes' on the TPM stops that. Live migration already moves the TPM to the new host, so with this change the TPM survives a stop and start and a live migration. It still resets if the host fails and HA starts the VM somewhere else. This is a small change and I think it could go into 4.22 (if there's more maintenance releases to go), or into 23/24.

    One side effect is that a host keeps the TPM data after the VM moves away. For example, a VM that runs on host A, is stopped and then started on host B will get a new TPM on B. Host A still has the old one, so if the VM later starts on A again it would pick that up. To keep this predictable, I'm proposing that the agent only reuse the saved TPM when the VM starts on the host it last ran on, and clear it otherwise. Happy to change this if people would rather keep the old copy.

    Part 2: save the TPM on primary storage.
    I'd add a small hidden volume for each VM that holds a copy of the TPM. The agent copies the TPM out of it before the VM starts and saves it back while the VM runs and when it stops. The TPM then follows the VM to any host, including after HA. This works on Ceph RBD as well as file-based storage. The copy would be encrypted, and there would be room for UEFI NVRAM too (see #12427). This would be a new feature for main.

    I also looked at letting swtpm use the volume directly while the VM runs, which is closer to how Proxmox does it. On Ceph that means mapping the volume on the host as a block device, which the KVM agent doesn't do today. libvirt also resets the TPM file on the destination host during a live migration, so each migration would need extra handling. Copying in and out avoids both of these. The downside is that if a host crashes, the last few seconds of TPM changes could be lost. In practice this should be rare, because the TPM data only changes when something like BitLocker is set up or its keys change, so the saved copy will almost always be current.

    I've tested the libvirt side on libvirt 11.10 and swtpm 0.8, and with persistent_state='yes' the TPM kept its identity after the VM was stopped and started again. Restoring a saved copy of the TPM also kept its identity. Let me know if you have any thoughts before I start on the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions