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: update secboot and use new key format #14304

Conversation

valentindavid
Copy link
Contributor

@valentindavid valentindavid commented Aug 5, 2024

This is the second part of moving to new secboot. This one is where we start using the new format.

This PR is draft as it is on top of #14282 (being split into smaller PRs) and #14253 (the first part of updating secboot).

@valentindavid valentindavid added Run nested The PR also runs tests inluded in nested suite FDE Manager Pull requests that target FDE manager branch labels Aug 5, 2024
@github-actions github-actions bot added the Run Nested -auto- Label automatically added in case nested tests need to be executed label Aug 5, 2024
@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch 9 times, most recently from 7183b85 to 63e5383 Compare August 8, 2024 14:50
@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch 3 times, most recently from 948f2b3 to 3060fd6 Compare August 16, 2024 11:07
@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch from 3060fd6 to 71aa49c Compare August 26, 2024 08:48
@valentindavid valentindavid marked this pull request as ready for review August 26, 2024 08:49
@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch 2 times, most recently from 0940e30 to b9e785f Compare August 26, 2024 11:32
@valentindavid
Copy link
Contributor Author

valentindavid commented Aug 26, 2024

This updates to secboot canonical/secboot@8dd835e19590 because later version use a broken go dependency.

@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch from b9e785f to d742f96 Compare August 26, 2024 11:54
golang.org/x/term v0.8.0 // indirect
maze.io/x/crypto v0.0.0-20190131090603-9b94c9afe066 // indirect
)

// github.com/intel-go was taken over
replace github.com/intel-go/cpuid => github.com/aregm/cpuid v0.0.0-20220614022739-219e067757cb
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need a fix in secboot for this. @chrisccoulson ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I'm going to push this to the @canonical org.

@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch 6 times, most recently from 6a8f879 to dcb925e Compare August 27, 2024 17:01
Comment on lines +776 to +780
// TODO: when save partition does not have slots, then
// we need to create new partition the old fashion
// way. Or, we should upgrade the save partition
// (which should be safe since the seed should not be
// considered safe to downgrade).
Copy link
Contributor Author

@valentindavid valentindavid Aug 27, 2024

Choose a reason for hiding this comment

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

I think I need to create a spread test for that case first.

  1. Install with an old snapd.
  2. Remodel with a newer snapd.
  3. Factory reset with the new snapd.

It is possible that it is already working, but we are left with some non-slot keys that we should remove.

@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch 4 times, most recently from d274f23 to eb18dca Compare August 28, 2024 10:57
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 an initial pass

secboot/encrypt_sb.go Outdated Show resolved Hide resolved
secboot/secboot_hooks.go Show resolved Hide resolved
secboot/secboot_hooks.go Show resolved Hide resolved
secboot/bootstrap_container.go Outdated Show resolved Hide resolved
secboot/secboot_sb.go Show resolved Hide resolved
Comment on lines 43 to 50
renames := map[string]string{
"default": "factory-reset-old",
"default-fallback": "factory-reset-old-fallback",
"save": "factory-reset-old-save",
}
if err := secboot.RenameOrDeleteKeys(saveNode, renames); err != nil {
return nil, err
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

what this bit of code is doing probably needs a comment

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 added a comment.

I am wondering if we should remove all the other keys (that is not "default" or "default-fallback"). We do remove the recovery keys. But in the future we will might have other keys. And it is not obvious which ones will need to be removed. Maybe all?

Copy link
Collaborator

Choose a reason for hiding this comment

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

should probably leave a TODO somewhere about the fact that factory reset should indeed remove all extra keys when done?

overlord/devicestate/handlers_install_sb.go Outdated Show resolved Hide resolved
secboot/secboot_sb.go Show resolved Hide resolved
overlord/devicestate/handlers_install_sb.go Outdated Show resolved Hide resolved
overlord/install/install.go Outdated Show resolved Hide resolved
secboot/secboot_sb.go Outdated Show resolved Hide resolved
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, notice that I also replied to some discussions from the previous pass

Comment on lines 37 to 54
func (bc *bootstrappedContainer) AddKey(slotName string, newKey []byte, token bool) (KeyDataWriter, error) {
if slotName == "" {
slotName = "default"
}
if err := sb.AddLUKS2ContainerUnlockKey(bc.devicePath, slotName, sb.DiskUnlockKey(bc.key), sb.DiskUnlockKey(newKey)); err != nil {
return nil, err
}
if !token {
return nil, nil
}
return nil, fmt.Errorf("not implemented")
}

func (bc *bootstrappedContainer) RemoveBootstrapKey() error {
Copy link
Collaborator

@pedronis pedronis Sep 2, 2024

Choose a reason for hiding this comment

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

these don't seem exercised by tests

boot/seal.go Outdated
} {
if container != nil {
if err := container.RemoveBootstrapKey(); err != nil {
// This could be a warning
Copy link
Contributor

Choose a reason for hiding this comment

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

shall we log it then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we change it from an error to a warning, yes we should log it. But I do not think we should log here yet since we do return an error.


// AddBootstrapKeyOnExistingDisk will add a new bootstrap key to on
// an existing encrypted disk. The disk is expected to be unlocked and
// they key is available on . The bootstrap key is temporary and is
Copy link
Contributor

Choose a reason for hiding this comment

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

available on ?

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 t was the keyring. I have pushed a fix.

@@ -27,6 +27,8 @@ NotifyAccess=all
SuccessExitStatus=42
RestartPreventExitStatus=42
KillMode=process
#TODO: test with "shared"
KeyringMode=inherit
Copy link
Contributor

Choose a reason for hiding this comment

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

wouldn't every process we spawn how have access to the same keyring we inherited from systemd? I suppose with this we could simply call snapd-fde-keymgr without systemd-run too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • Yes, we will call everything else with access to the keyring. But we should really not call anything we cannot trust anyway as we run as root and anything we call could just dispatch anything to systemd. Let's say there is a vulnerability in sfdisk, we are already vulnerable then. Unless we start dropping privileges on whatever we execute.

  • I can follow up with removing systemd-run from calling snapd-fde-keymgr. But it is a lot of changes in tests for very little.

Copy link
Contributor

Choose a reason for hiding this comment

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

No, it's fine, I don't think there's an urgent need to do anything about snapd-fde-keymgr right now. I think we should look into ensuring that the external things we run are isolated from us in a reasonable manner, and preferably invoked through systemd-run where possible.

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.

LGTM

if err != nil {
return fmt.Errorf("cannot list slots in partition save partition: %v", err)
}
for _, slot := range slots {
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a possible ordering issue when the target name repeats again as the name to rename from?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that if renames contains for example A -> B, B -> C. Then maybe A is renamed to B, or to C depending on the order?

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 added checks for 2 cases:

  • As a precondition, give an internal error if we have something like a -> b, b -> c. We cannot use the same name as a target or source.
  • Before we do the renaming, we verify that no target name exists in the luks2 container already. This is not an internal error.

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 added also 2 FIXME notes in the caller part of the code. I do not think we need to save the "default" key. And I think we need to delete "default-fallback" if "factory-reset-old-fallback" exists, and not do the rename.

Comment on lines 114 to 118
slots, err := sbListLUKS2ContainerUnlockKeyNames(dev)
if err != nil {
return keys.RecoveryKey{}, fmt.Errorf("cannot find list keys for: %v", err)
}
if len(slots) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

wonder if this maybe could be refactored into a more explicit function testing for the legacy setup?

or could use a comment maybe

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about adding hasOnlyLegacyKeys := len(slots) == 0. And use that? I do not see anywhere else in the code where we need that.

Copy link
Contributor

Choose a reason for hiding this comment

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

that's fine, with a comment that key slot names were not used previously and lack of them indicates a legacy setup

@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch from 89166a0 to 7178818 Compare September 13, 2024 11:19
Copy link
Contributor

@chrisccoulson chrisccoulson left a comment

Choose a reason for hiding this comment

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

I've left a small number of comments, but this seems to be ok

@@ -100,7 +100,7 @@ var (
secbootMeasureSnapSystemEpochWhenPossible func() error
secbootMeasureSnapModelWhenPossible func(findModel func() (*asserts.Model, error)) error
secbootUnlockVolumeUsingSealedKeyIfEncrypted func(disk disks.Disk, name string, encryptionKeyFile string, opts *secboot.UnlockVolumeUsingSealedKeyOptions) (secboot.UnlockResult, error)
secbootUnlockEncryptedVolumeUsingKey func(disk disks.Disk, name string, key []byte) (secboot.UnlockResult, error)
secbootUnlockEncryptedVolumeUsingPlatformKey func(disk disks.Disk, name string, key []byte) (secboot.UnlockResult, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

At some point, then intention is that snap-bootstrap calls plainkey.SetProtectorKeys, and then there will just be a single API for unlocking data and save.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right. Though that will still be here for the key data in files. That is for backward compliance.

I do not think we need that rename in this PR. That was an intermediate state of the spike, but later. I will check if I can revert this.

@@ -27,6 +27,8 @@ NotifyAccess=all
SuccessExitStatus=42
RestartPreventExitStatus=42
KillMode=process
#TODO: test with "shared"
KeyringMode=inherit
Copy link
Contributor

@chrisccoulson chrisccoulson Sep 16, 2024

Choose a reason for hiding this comment

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

shared should work as well. The main difference is that in inherit mode, systemd leaves the session keyring pointer untouched (in this case, NULL, because PID1 does nothing to initialise a session keyring), so the kernel initialises it to the kernel created user session keyring associated with the root user on first access. In shared mode, systemd creates a session keyring with a link to the user keyring in it, so that the user keyring becomes "possessed" and possessor permissions apply when accessing it. In private mode, the link to the user keyring is missing so the service can access the user keyring with user permissions but not posseessor permissions. The security benefits of this are limited though - the user keyring can be linked in to a private mode session keyring because the permissions of the user keyring permit user linking. So, even the default private works here, but snapd would need to add a link to the user keyring from its session keyring, which is just extra work.

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 set it to shared.

@@ -377,13 +362,20 @@ fi
if opts.encryption {
runOpts.EncryptionType = secboot.EncryptionTypeLUKS
}

defer install.MockCryptsetupOpen(func(key secboot.DiskUnlockKey, node, name string) error {
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these mocks test that any of the arguments are the expected values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

golang.org/x/term v0.8.0 // indirect
maze.io/x/crypto v0.0.0-20190131090603-9b94c9afe066 // indirect
)

// github.com/intel-go was taken over
replace github.com/intel-go/cpuid => github.com/aregm/cpuid v0.0.0-20220614022739-219e067757cb
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I'm going to push this to the @canonical org.

@valentindavid valentindavid force-pushed the valentindavid/update-secboot-part2-new-keyformat branch from 1b74e68 to 85f269e Compare September 19, 2024 14:22
@ernestl ernestl merged commit 5afd0bc into canonical:fde-manager-features Sep 20, 2024
41 of 51 checks passed
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 -auto- Label automatically added in case nested tests need to be executed Run nested The PR also runs tests inluded in nested suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants