Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boot/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func MockResealKeyForBootChains(f func(unlocker Unlocker, method device.SealingM
}
}

func MockSealKeyForBootChains(f func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *SealKeyForBootChainsParams) error) (restore func()) {
func MockSealKeyForBootChains(f func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *SealKeyForBootChainsParams, fdeState InitialFDEState) error) (restore func()) {
old := SealKeyForBootChains
SealKeyForBootChains = f
return func() {
Expand Down
9 changes: 5 additions & 4 deletions boot/makebootable.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ func isSealModeenvLocked() bool {
return atomic.LoadInt32(&sealModeenvLocked) == 1
}

func makeRunnableSystemSeal(modeenv *Modeenv, model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *EncryptionSetup, makeOpts makeRunnableOptions) error {
func makeRunnableSystemSeal(modeenv *Modeenv, model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *EncryptionSetup, makeOpts makeRunnableOptions, fdeState InitialFDEState) error {
tokens := UseTokens(model)
if tokens {
logger.Debugf("key data will be stored in tokens")
Expand Down Expand Up @@ -507,6 +507,7 @@ func makeRunnableSystemSeal(modeenv *Modeenv, model *asserts.Model, protector se
model,
modeenv,
flags,
fdeState,
); err != nil {
return err
}
Expand Down Expand Up @@ -708,7 +709,7 @@ func makeRunnableSystem(model *asserts.Model, bootWith *BootableSet, bootAssets
return fmt.Errorf("cannot check for fde-setup hook key protector: %v", err)
}

if err := makeRunnableSystemSeal(modeenv, model, protector, encryption, makeOpts); err != nil {
if err := makeRunnableSystemSeal(modeenv, model, protector, encryption, makeOpts, nil); err != nil {
return err
}
}
Expand Down Expand Up @@ -823,7 +824,7 @@ func MakeRunnableSystemAfterDataReset(model *asserts.Model, bootWith *BootableSe
// MakeRunnableSystemReprovision make the systems currently running bootable again.
// This is intended to repair the boot of a system that was booted for example
// with a recovery key.
func MakeRunnableSystemReprovision(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *EncryptionSetup) error {
func MakeRunnableSystemReprovision(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *EncryptionSetup, fdeState InitialFDEState) error {
sealModeenvLock()
defer sealModeenvUnlock()

Expand All @@ -835,5 +836,5 @@ func MakeRunnableSystemReprovision(model *asserts.Model, protector secboot.KeyPr
return makeRunnableSystemSeal(modeenv, model, protector, encryption, makeRunnableOptions{
Reprovision: true,
SeedDir: dirs.SnapSeedDir,
})
}, fdeState)
}
11 changes: 6 additions & 5 deletions boot/makebootable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ func (s *makeBootable20Suite) TestMakeSystemRunnableSealWithHookKeyProtector(c *
model *asserts.Model,
modeenv *boot.Modeenv,
flags boot.MockSealKeyToModeenvFlags,
fdeState boot.InitialFDEState,
) error {
gotFlags = flags
return nil
Expand Down Expand Up @@ -773,7 +774,7 @@ version: 5.0
defer restore()

sealKeyForBootChainsCalled := 0
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++
c.Check(method, Equals, device.SealingMethodTPM)
c.Check(key, Equals, myKey)
Expand Down Expand Up @@ -1297,7 +1298,7 @@ version: 5.0
defer restore()

sealKeyForBootChainsCalled := 0
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++
c.Check(method, Equals, device.SealingMethodTPM)
c.Check(key, Equals, myKey)
Expand Down Expand Up @@ -1501,7 +1502,7 @@ version: 5.0
defer restore()

sealKeyForBootChainsCalled := 0
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++
c.Check(method, Equals, device.SealingMethodTPM)
c.Check(key, DeepEquals, myKey)
Expand Down Expand Up @@ -2667,7 +2668,7 @@ func (s *makeBootable20Suite) TestMakeSystemRunnableReprovision(c *C) {
c.Assert(err, IsNil)

sealKeyForBootChainsCalled := 0
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++
c.Check(method, Equals, device.SealingMethodTPM)
c.Check(key, Equals, myKey)
Expand Down Expand Up @@ -2769,7 +2770,7 @@ func (s *makeBootable20Suite) TestMakeSystemRunnableReprovision(c *C) {

var protector secboot.KeyProtectorFactory

err = boot.MakeRunnableSystemReprovision(model, protector, encryptionSetup)
err = boot.MakeRunnableSystemReprovision(model, protector, encryptionSetup, nil)
c.Assert(err, IsNil)

c.Check(sealKeyForBootChainsCalled, Equals, 1)
Expand Down
13 changes: 10 additions & 3 deletions boot/seal.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func MockResealKeyToModeenv(f func(rootdir string, modeenv *Modeenv, opts Reseal
type MockSealKeyToModeenvFlags = sealKeyToModeenvFlags

// MockSealKeyToModeenv is used for testing from other packages.
func MockSealKeyToModeenv(f func(key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, model *asserts.Model, modeenv *Modeenv, flags MockSealKeyToModeenvFlags) error) (restore func()) {
func MockSealKeyToModeenv(f func(key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, model *asserts.Model, modeenv *Modeenv, flags MockSealKeyToModeenvFlags, fdeState InitialFDEState) error) (restore func()) {
old := sealKeyToModeenv
sealKeyToModeenv = f
return func() {
Expand Down Expand Up @@ -119,6 +119,7 @@ func sealKeyToModeenvImpl(
model *asserts.Model,
modeenv *Modeenv,
flags sealKeyToModeenvFlags,
fdeState InitialFDEState,
) error {
if !isSealModeenvLocked() {
return fmt.Errorf("internal error: cannot seal without the seal modeenv lock")
Expand Down Expand Up @@ -147,7 +148,7 @@ func sealKeyToModeenvImpl(
defer relock()
}

return sealKeyToModeenvForMethod(method, key, saveKey, primaryKey, volumesAuth, checkResult, model, modeenv, flags)
return sealKeyToModeenvForMethod(method, key, saveKey, primaryKey, volumesAuth, checkResult, model, modeenv, flags, fdeState)
}

type BootChains struct {
Expand Down Expand Up @@ -183,13 +184,18 @@ type SealKeyForBootChainsParams struct {
KeyProtectorFactory secboot.KeyProtectorFactory
}

type InitialFDEState interface {
UpdateParameters(role string, containerRole string, bootModes []string, models []secboot.ModelForSealing, tpmPCRProfile []byte, pcrHandle uint32) error
}

func sealKeyForBootChainsImpl(
method device.SealingMethod,
key, saveKey secboot.BootstrappedContainer,
primaryKey []byte,
volumesAuth *device.VolumesAuthOptions,
checkResult *secboot.PreinstallCheckResult,
params *SealKeyForBootChainsParams,
fdeState InitialFDEState,
) error {
return fmt.Errorf("FDE manager backend was not built in")
}
Expand All @@ -205,6 +211,7 @@ func sealKeyToModeenvForMethod(
model *asserts.Model,
modeenv *Modeenv,
flags sealKeyToModeenvFlags,
fdeState InitialFDEState,
) error {
params := &SealKeyForBootChainsParams{
LegacyFactoryResetKeyPath: flags.LegacyFactoryResetKeyPath,
Expand Down Expand Up @@ -287,7 +294,7 @@ func sealKeyToModeenvForMethod(
params.RoleToBlName[bootloader.RoleRunMode] = bl.Name()
}

return SealKeyForBootChains(method, key, saveKey, primaryKey, volumesAuth, checkResult, params)
return SealKeyForBootChains(method, key, saveKey, primaryKey, volumesAuth, checkResult, params, fdeState)
}

var resealKeyToModeenv = resealKeyToModeenvImpl
Expand Down
12 changes: 6 additions & 6 deletions boot/seal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (s *sealSuite) TestSealKeyToModeenv(c *C) {
defer restore()

sealKeyForBootChainsCalled := 0
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++

for _, d := range []string{boot.InitramfsSeedEncryptionKeyDir, filepath.Join(dirs.GlobalRootDir, "/run/mnt/ubuntu-data/system-data/var/lib/snapd/device/fde")} {
Expand Down Expand Up @@ -280,7 +280,7 @@ func (s *sealSuite) TestSealKeyToModeenv(c *C) {
Reprovision: tc.reprovision,
StateUnlocker: u.unlocker,
UseTokens: !tc.disableTokens,
})
}, nil)
c.Check(u.unlocked, Equals, 1)
c.Check(sealKeyForBootChainsCalled, Equals, tc.expSealCalls)
if tc.expErr == "" {
Expand Down Expand Up @@ -1651,7 +1651,7 @@ func (s *sealSuite) TestSealToModeenvWithSecbootProtectorHappy(c *C) {
myKey2 := secboot.CreateMockBootstrappedContainer()

sealKeyForBootChainsCalled := 0
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore = boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++
c.Check(method, Equals, device.SealingMethodFDESetupHook)
c.Check(key, DeepEquals, myKey)
Expand Down Expand Up @@ -1681,7 +1681,7 @@ func (s *sealSuite) TestSealToModeenvWithSecbootProtectorHappy(c *C) {

defer boot.MockSealModeenvLocked()()

err := boot.SealKeyToModeenv(myKey, myKey2, nil, nil, nil, model, modeenv, boot.MockSealKeyToModeenvFlags{HookKeyProtectorFactory: &fakeProtectorFactory{}, UseTokens: true})
err := boot.SealKeyToModeenv(myKey, myKey2, nil, nil, nil, model, modeenv, boot.MockSealKeyToModeenvFlags{HookKeyProtectorFactory: &fakeProtectorFactory{}, UseTokens: true}, nil)
c.Assert(err, IsNil)
c.Check(sealKeyForBootChainsCalled, Equals, 1)
}
Expand All @@ -1694,7 +1694,7 @@ func (s *sealSuite) TestSealToModeenvWithSecbootProtectorSad(c *C) {
model := boottest.MakeMockUC20Model()

sealKeyForBootChainsCalled := 0
restore := boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams) error {
restore := boot.MockSealKeyForBootChains(func(method device.SealingMethod, key, saveKey secboot.BootstrappedContainer, primaryKey []byte, volumesAuth *device.VolumesAuthOptions, checkResult *secboot.PreinstallCheckResult, params *boot.SealKeyForBootChainsParams, fdeState boot.InitialFDEState) error {
sealKeyForBootChainsCalled++

return fmt.Errorf("seal key failed")
Expand All @@ -1714,7 +1714,7 @@ func (s *sealSuite) TestSealToModeenvWithSecbootProtectorSad(c *C) {

defer boot.MockSealModeenvLocked()()

err := boot.SealKeyToModeenv(key, saveKey, nil, nil, nil, model, modeenv, boot.MockSealKeyToModeenvFlags{HookKeyProtectorFactory: &fakeProtectorFactory{}})
err := boot.SealKeyToModeenv(key, saveKey, nil, nil, nil, model, modeenv, boot.MockSealKeyToModeenvFlags{HookKeyProtectorFactory: &fakeProtectorFactory{}}, nil)
c.Assert(err, ErrorMatches, `seal key failed`)
c.Check(sealKeyForBootChainsCalled, Equals, 1)
}
Expand Down
1 change: 1 addition & 0 deletions overlord/devicestate/devicestate_install_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ func (s *deviceMgrInstallAPISuite) testInstallFinishStep(c *C, opts finishStepOp
model *asserts.Model,
modeenv *boot.Modeenv,
flags boot.MockSealKeyToModeenvFlags,
fdeState boot.InitialFDEState,
) error {
c.Check(model.Classic(), Equals, opts.installClassic)
// Note that we cannot compare the full structure and we check
Expand Down
2 changes: 1 addition & 1 deletion overlord/devicestate/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ func MockSecbootDeleteContainerKey(f func(disk string, name string) error) (rest
return testutil.Mock(&secbootDeleteContainerKey, f)
}

func MockBootMakeRunnableReprovision(f func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup) error) (restore func()) {
func MockBootMakeRunnableReprovision(f func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup, fdeState boot.InitialFDEState) error) (restore func()) {
return testutil.Mock(&bootMakeRunnableReprovision, f)
}

Expand Down
9 changes: 8 additions & 1 deletion overlord/devicestate/handlers_reprovision.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,23 +413,29 @@ func (m *DeviceManager) doReprovision(t *state.Task, _ *tomb.Tomb) error {
volumesAuth,
checkResult)

fdeState, err := fdestate.InitialState(primaryKey)

err = bootMakeRunnableReprovision(
deviceCtx.Model(),
keyProtector,
encryptionParams,
&fdeState,
)

if err != nil {
return fmt.Errorf("cannot make system runnable: %v", err)
}

// Step 7. Swap the state
// TODO: Actually swap the state. And move it after step 6.
var oldState any
errGetState := st.Get("fde", &oldState)
if errGetState != nil && !errors.Is(errGetState, state.ErrNoState) {
return fmt.Errorf("internal error: cannot get the fde state %v", err)
}
// In case the write of protector key fails but we lose power
// before we can revert, having a nil fde state will make the
// system rebuild it on reboot instead of having a state that
// does not match.
st.Set("fde", nil)

// Step 6. write the protector key
Expand All @@ -439,6 +445,7 @@ func (m *DeviceManager) doReprovision(t *state.Task, _ *tomb.Tomb) error {
}
return fmt.Errorf("cannot save the system-save key: %v", err)
}
st.Set("fde", fdeState)
// swapping the protector key is the sign we have finished
revertReprovisionAttemptOnError = false

Expand Down
6 changes: 3 additions & 3 deletions overlord/devicestate/running_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ version: 1.0
})()

bootMakeRunnableReprovisionCalls := 0
defer devicestate.MockBootMakeRunnableReprovision(func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup) error {
defer devicestate.MockBootMakeRunnableReprovision(func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup, fdeState boot.InitialFDEState) error {
bootMakeRunnableReprovisionCalls++

c.Check(encryption.PrimaryKey(), DeepEquals, []byte("new-primary-key"))
Expand Down Expand Up @@ -1315,7 +1315,7 @@ version: 1.0
})()

bootMakeRunnableReprovisionCalls := 0
defer devicestate.MockBootMakeRunnableReprovision(func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup) error {
defer devicestate.MockBootMakeRunnableReprovision(func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup, fdeState boot.InitialFDEState) error {
bootMakeRunnableReprovisionCalls++

c.Check(encryption.PrimaryKey(), DeepEquals, []byte("new-primary-key"))
Expand Down Expand Up @@ -1878,7 +1878,7 @@ version: 1.0
return &secboot.PreinstallCheckResult{}, nil
})()

defer devicestate.MockBootMakeRunnableReprovision(func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup) error {
defer devicestate.MockBootMakeRunnableReprovision(func(model *asserts.Model, protector secboot.KeyProtectorFactory, encryption *boot.EncryptionSetup, fdeState boot.InitialFDEState) error {
return fmt.Errorf("make runnable failed")
})()

Expand Down
6 changes: 6 additions & 0 deletions overlord/fdestate/activate_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ type FDESystemState struct {
// AutoRepairResult is the status of the auto-repair attempt
AutoRepairResult AutoRepairResult `json:"auto-repair-result"`

Recommendations []RecommendedRemedialAction `json:"recommendations,omitempty"`

// Preinstall provides information captured during install-time checks.
Preinstall FDEPreinstallInfo `json:"preinstall"`
}
Expand Down Expand Up @@ -144,6 +146,7 @@ func SystemState(st *state.State, model *asserts.Model) (*FDESystemState, error)
ret.AutoRepairResult = AutoRepairNotInitialized
} else {
ret.AutoRepairResult = repairResult.Result
ret.Recommendations = repairResult.Recommendations
}

s, err := getActivateState(st)
Expand Down Expand Up @@ -187,6 +190,9 @@ func SystemState(st *state.State, model *asserts.Model) (*FDESystemState, error)
if s.NumActivatedContainersWithRecoveryKey() != 0 {
ret.Status = FDEStatusRecovery
} else if secboot.ActivateStateHasDegradedErrors(s) {
// TODO: we should get degraded from the autorepair
// state since there are system wide errors to look
// at.
ret.Status = FDEStatusDegraded
} else {
ret.Status = FDEStatusActive
Expand Down
Loading
Loading