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

many: rework the way we allocate counter handles #14910

Open
wants to merge 9 commits into
base: fde-manager-features
Choose a base branch
from

Conversation

valentindavid
Copy link
Contributor

We used 4 handles from 0x01880001-0x01880004 for PCR policies. We always used a pair and would switch to the other pair after factory reset.

No instead we look for free handle in range 0x01880005-0x0188000F. We also use only one handle per primary key.

When we factory reset, we should remove the handles correctly since the old primary key for the save partition should have been the same as the data partition that was removed, thus the handles should be the same.

We also now correctly populate the FDE state with the correct handles.

Thanks for helping us make a better snapd!
Have you signed the license agreement and read the contribution guide?

@valentindavid valentindavid added Run nested The PR also runs tests inluded in nested suite FDE Manager Pull requests that target FDE manager branch labels Jan 9, 2025
@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch 8 times, most recently from 3766f88 to 796c572 Compare January 9, 2025 14:50
@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch from 796c572 to bb2978a Compare January 10, 2025 11:11
@valentindavid valentindavid marked this pull request as ready for review January 10, 2025 11:11
Copy link

codecov bot commented Jan 10, 2025

Codecov Report

Attention: Patch coverage is 55.37849% with 112 lines in your changes missing coverage. Please review.

Please upload report for BASE (fde-manager-features@7005c64). Learn more about missing BASE report.

Files with missing lines Patch % Lines
secboot/secboot_tpm.go 50.00% 70 Missing and 15 partials ⚠️
overlord/fdestate/fdestate.go 62.50% 8 Missing and 4 partials ⚠️
overlord/devicestate/handlers_install.go 83.78% 4 Missing and 2 partials ⚠️
secboot/secboot_dummy.go 0.00% 6 Missing ⚠️
overlord/fdestate/backend/seal.go 60.00% 1 Missing and 1 partial ⚠️
overlord/devicestate/devicemgr.go 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@                   Coverage Diff                   @@
##             fde-manager-features   #14910   +/-   ##
=======================================================
  Coverage                        ?   78.09%           
=======================================================
  Files                           ?     1170           
  Lines                           ?   155133           
  Branches                        ?        0           
=======================================================
  Hits                            ?   121147           
  Misses                          ?    26449           
  Partials                        ?     7537           
Flag Coverage Δ
unittests 78.09% <55.37%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@pedronis pedronis force-pushed the fde-manager-features branch from 5802840 to 5ec2e43 Compare January 13, 2025 09:50
@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch from bb2978a to 20133bc Compare January 13, 2025 09:55
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.

did a first quick pass, some questions

overlord/devicestate/handlers_install.go Outdated Show resolved Hide resolved
// keys.

// FIXME: maybe there is better if we had a function returning the devname instead.
func deleteOldKeys(saveMntPnt string) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this needs a doc comment about what is doing

boot/seal.go Show resolved Hide resolved
secboot/secboot_tpm.go Show resolved Hide resolved
secboot/secboot_tpm.go Outdated Show resolved Hide resolved
secboot/secboot_tpm.go Show resolved Hide resolved
if err != nil {
if os.IsNotExist(err) {
if readKeyDataErr != nil {
// FIXME: we need to check for
Copy link
Contributor Author

Choose a reason for hiding this comment

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

That fixme is not complete...

@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch 2 times, most recently from a96331b to 0dc4a83 Compare January 15, 2025 14:15
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 for the changes, some small comments, please ping people to get more reviews


var oldKeys []string
renameKey := false
if osutil.FileExists(saveFallbackKeyFactory) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this little bit of logic probably needs a small comment

@@ -1360,7 +1360,18 @@ func createSaveBootstrappedContainer(saveNode string) (secboot.BootstrappedConta
return secbootCreateBootstrappedContainer(secboot.DiskUnlockKey(saveEncryptionKey), saveNode), nil
}


// deleteOldKeys remove old keys that were used in previous installation after successful factory reset.
// * Key files ubuntu-save.recovery.sealed-key has to be replaced by key file ubuntu-save.recovery.sealed-key.factory-reset
Copy link
Collaborator

Choose a reason for hiding this comment

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

given this bit, shouldn't the name say something like swap save key as well?

@@ -936,6 +936,9 @@ func mockableReadKeyFileImpl(keyFile string, keyLoader *mockableKeyLoader, hintE

var mockableReadKeyFile = mockableReadKeyFileImpl

// GetPCRHandle returns the handle used by a key. The key will be
// search on as token on node in the keySlot. If keySlot has no
Copy link
Collaborator

Choose a reason for hiding this comment

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

s/search on/searched/ ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe "searched on the token of the keySlot from the node". I will change that.

@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch from 0dc4a83 to 374fffa Compare January 20, 2025 12:29
@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch from 374fffa to 4883247 Compare January 20, 2025 13:09
Copy link
Contributor

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

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

Just some trivial comments. TBH I'm not fond of all the mocking we do right now. On the one hand, it'd be nice to think about it a little, on the other there are things to deliver.

Comment on lines 1365 to 1367
// * Key files ubuntu-save.recovery.sealed-key has to be replaced by key file ubuntu-save.recovery.sealed-key.factory-reset
// * Keyslots factory-reset-* have to be removed
// * TPM handles used by the removed keys have to be released
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// * Key files ubuntu-save.recovery.sealed-key has to be replaced by key file ubuntu-save.recovery.sealed-key.factory-reset
// * Keyslots factory-reset-* have to be removed
// * TPM handles used by the removed keys have to be released
// - rotate ubuntu-save key file, replace ubuntu-save.recovery.sealed-key with
// ubuntu-save.recovery.sealed-key.factory-reset, which was successfully recovered
// - remove factory-reset-* keyslots
// - reelase TPM handles used by the removed keys

Comment on lines +1391 to +1396
// If the fallback save key exists, then it is the new
// key. That means the default save key is the old save key
// that needs to be removed.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// If the fallback save key exists, then it is the new
// key. That means the default save key is the old save key
// that needs to be removed.
// ubuntu-save key rotation, delete old key and use
// fallback save key if it exists

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is more confusing. If the fallback key does not exist, the default one is not the old key, because the rotation might have happened already.

Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't we capture in the comment a bit what are the cases when is missing as well then?

// If the fallback save key exists, then it is the new
// key. That means the default save key is the old save key
// that needs to be removed.
if osutil.FileExists(saveFallbackKeyFactory) {
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe I'm missing something, but is it possible this key doesn't exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it is possible if we already swapped it before but we did not finish clean up.

// possibleKeyFiles is a list to paths. hintExpectFDEHook helps
// reading old key object files. If not TPM2 key is found, nothing
// happens.
func RemoveOldCounterHandles(node string, possibleOldKeys map[string]bool, possibleKeyFiles []string, hintExpectFDEHook bool) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

unless other code is using node already

Suggested change
func RemoveOldCounterHandles(node string, possibleOldKeys map[string]bool, possibleKeyFiles []string, hintExpectFDEHook bool) error {
func RemoveOldCounterHandles(device string, possibleOldKeys map[string]bool, possibleKeyFiles []string, hintExpectFDEHook bool) error {

Comment on lines 1008 to 1012
// RemoveOldCounterHandles tracks and release TPM2 handles used by
// given keys node and possibleOldKeys point to keyslot tokens. And
// possibleKeyFiles is a list to paths. hintExpectFDEHook helps
// reading old key object files. If not TPM2 key is found, nothing
// happens.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// RemoveOldCounterHandles tracks and release TPM2 handles used by
// given keys node and possibleOldKeys point to keyslot tokens. And
// possibleKeyFiles is a list to paths. hintExpectFDEHook helps
// reading old key object files. If not TPM2 key is found, nothing
// happens.
// RemoveOldCounterHandles releases TPM2 handles of keys used on a given
// device, which are either stored in key slots matching possibleOldKeys or in key
// files listed in possibleKeyFiles. If not TPM2 key is found, nothing happens.

readKeyDataErr = err
break
}
keyData, err := mockableReadKeyData(reader)
Copy link
Contributor

Choose a reason for hiding this comment

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

this is slightly annoying

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.

thank you, couple small comments

renameKey = true
}

// FIXME: we are missing a bit of context here. We should do this only if we are using TPM2.
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we still need this comment, now that we pass hasHook?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed.

saveFallbackKeyFactory := device.FactoryResetFallbackSaveSealedKeyUnder(boot.InitramfsSeedEncryptionKeyDir)

var oldKeys []string
renameKey := false
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe this should be called rotateKey to match the doc comment of the function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have changed it.


takenHandles := make(map[uint32]bool)
for _, handle := range handles {
takenHandles[uint32(handle)] = true
Copy link
Contributor

Choose a reason for hiding this comment

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

I would log which handles are in use here

for _, tentative := range randutil.Perm(int(PCRPolicyCounterHandleRange)) {
handle := PCRPolicyCounterHandleStart + uint32(tentative)
if !takenHandles[PCRPolicyCounterHandleStart+uint32(tentative)] {
return handle, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

and here, log the free handle

func rotateSaveKeyAndDeleteOldKeys(saveMntPnt string) error {
hasHook, err := boot.HasFDESetupHook(nil)
if err != nil {
logger.Noticef("WARNING: cannot figure out if FDE hooks are in use: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
logger.Noticef("WARNING: cannot figure out if FDE hooks are in use: %v", err)
logger.Noticef("WARNING: cannot determine whether FDE hooks are in use: %v", err)

@@ -7482,6 +7482,11 @@ func (s *mgrsSuiteCore) testRemodelUC20WithRecoverySystem(c *C, encrypted bool)
})
defer restore()

restore = fdestate.MockSecbootGetPCRHandle(func(devicePath, keySlot, keyFile string) (uint32, error) {
return 42, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, I would return an int which looks like the actual handles we expect, such that when looking at the logs you'd see familiar values, so eg. 0x1880002

We used 4 handles from 0x01880001-0x01880004 for PCR policies. We
always used a pair and would switch to the other pair after factory
reset.

No instead we look for free handle in range 0x01880005-0x0188000F. We
also use only one handle per primary key.

When we factory reset, we should remove the handles correctly since
the old primary key for the save partition should have been the same
as the data partition that was removed, thus the handles should be the
same.

We also now correctly populate the FDE state with the correct handles.
@valentindavid valentindavid force-pushed the valentindavid/fde-rework-counter-handles branch from 24ce51f to 2d88bcf Compare January 24, 2025 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FDE Manager Pull requests that target FDE manager branch Run nested The PR also runs tests inluded in nested suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants