Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tpm2: Avoid attempting to open duplicate TPM connections #360

Merged

Conversation

chrisccoulson
Copy link
Collaborator

@chrisccoulson chrisccoulson commented Jan 16, 2025

When using NewTPMPassphraseProtectedKey, it is passed an already open
connection. But the core secboot package calls back into the platform
handler to set the user auth value, which opens a second connection.
When using the direct device (/dev/tpm0), this doesn't work.

This updates the test suite to make sure that this scenario is caught
and results in an error. It also fixes the problem by providing a way to
pass the open TPM connection to the singleton tpm2 platform handler
via a new field on the secboot.KeyWithPassphraseParams struct which
can be set to any value and is passed to the ChangeAuthKey implementation
when setting the initial auth value. The tpm2 platform handler
implementation uses this connection if passed rather than trying to open a
new connection. If the ChangeAuthKey implementation is called via
KeyData.ChangePassphrase, then the new argument will be nil and the
tpm2 implementation will open a new TPM connection as required.

This also identified a bug that the core secboot package was not passing
the role value to the platform handler, which only seemed to be caught
by adding tests that created passphrase protected TPM keys with a role.

This addresses issue #353

@chrisccoulson chrisccoulson force-pushed the tpm2-avoid-duplicate-connections branch from 610b686 to 2249d34 Compare January 16, 2025 16:36
@chrisccoulson chrisccoulson marked this pull request as ready for review January 16, 2025 16:37
When using NewTPMPassphraseProtectedKey, it is passed an already open
connection. But the core secboot package calls back into the platform
handler to set the user auth value, which opens a second connection.
When using the direct device (/dev/tpm0), this doesn't work.

This updates the test suite to make sure that this scenario is caught
and results in an error. It also fixes the problem by providing the open
TPM connection to the singleton tpm2 platform handler so that it uses
this rather than trying to open a new connection.

This also identified a bug that the core secboot package was not passing
the role value to the platform handler, which only seemed to be caught
by adding tests that created passphrase protected TPM keys with a role.
@chrisccoulson chrisccoulson force-pushed the tpm2-avoid-duplicate-connections branch from 2249d34 to 963b7b7 Compare January 16, 2025 16:56
@chrisccoulson chrisccoulson changed the title tpm2: Avoid attempting to avoid opening duplicate TPM connections tpm2: Avoid attempting to open duplicate TPM connections Jan 16, 2025
Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question

tpm2/seal.go Outdated
Comment on lines 84 to 87
// Avoid trying to reopen another connection when setting the user auth value
orig := mainPlatformKeyDataHandler.tpm
mainPlatformKeyDataHandler.tpm = tpm
defer func() { mainPlatformKeyDataHandler.tpm = orig }()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

depending how things are used this could create a data race, do we need a global mutex around some of the handler usage?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that might be a good idea - I'll add that. We might want to actually hold the lock throughout the whole code section that runs with the connection set, so that any other code that wants to set the connection will have to wait, else things might get a bit confusing if there are multiple connections around.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whilst trying to figure out the best way to do this, and given that I'd like to reduce existing data races, I ended up taking a different approach by permitting the open connection to be passed to NewKeyDataWithPassphrase and subsequently back to the tpm2 platform handler via a new context argument to ChangeAuthKey. It seemed like the safest way to do it in the end.

Rather than setting a Connection on the platform handler on the tpm2
side and then the calling PlatformKeyDataHandler.ChangeAuthKey for the
first time, try permitting the Connection to be passed directly to
ChangeAuthKey instead.

This adds a new parameter that can be of any type to
KeyWithPassphraseParams. This is passed directly to
PlatformKeyDataHandler.ChangeAuthKey when it is called for the first
time. Plarforms are free to use this new parameter however they like,
but the tpm2 package uses it to pass an open TPM connection. When called
via KeyData.ChangePassphrase, nothing is passed via the new argument and
the tpm2 package will open a new connection.

This avoids race conditions with the previous approach and introducing
new thread safety issues at a time when I'd like to be reducing these
overall.
Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, this looks alright, shouldn't now NewTPMProtectedKey doc comment say something abut when the TPM connection passed in can be closed?

Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry my question didn't make sense, I hastily misread the changes to keydata.go. +1

@chrisccoulson chrisccoulson merged commit 12230bb into canonical:master Jan 28, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants