Skip to content

Commit

Permalink
fixup! o/{install,devicestate}: use a struct instead of map for snapd…
Browse files Browse the repository at this point in the history
… versions

Signed-off-by: Zeyad Gouda <[email protected]>
  • Loading branch information
ZeyadYasser committed Jan 24, 2025
1 parent 8414512 commit 9b84668
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 37 deletions.
26 changes: 14 additions & 12 deletions overlord/devicestate/devicemgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -2201,12 +2201,12 @@ func (m *DeviceManager) systems() ([]*System, error) {
return systems, nil
}

func snapdVersionByTypeFromSeed20(s seed.Seed, types []snap.Type) (snapdVersionByType map[snap.Type]string, err error) {
func snapdVersionByTypeFromSeed20(s seed.Seed, types []snap.Type) (systemSnapdVersions *install.SystemSnapdVersions, err error) {
perf := &timings.Timings{}
if err := s.LoadEssentialMeta(types, perf); err != nil {
return nil, fmt.Errorf("cannot load essential snaps metadata: %v", err)
}

Check warning on line 2208 in overlord/devicestate/devicemgr.go

View check run for this annotation

Codecov / codecov/patch

overlord/devicestate/devicemgr.go#L2207-L2208

Added lines #L2207 - L2208 were not covered by tests
snapdVersionByType = make(map[snap.Type]string)
systemSnapdVersions = &install.SystemSnapdVersions{}
for _, snapSeed := range s.EssentialSnaps() {
snapf, err := snapfile.Open(snapSeed.Path)
if err != nil {
Expand All @@ -2216,12 +2216,14 @@ func snapdVersionByTypeFromSeed20(s seed.Seed, types []snap.Type) (snapdVersionB
if err != nil {
return nil, err
}

Check warning on line 2218 in overlord/devicestate/devicemgr.go

View check run for this annotation

Codecov / codecov/patch

overlord/devicestate/devicemgr.go#L2217-L2218

Added lines #L2217 - L2218 were not covered by tests
snapdVersionByType[snapSeed.EssentialType] = snapdVersion
}
if len(snapdVersionByType) != len(types) {
return nil, fmt.Errorf("internal error: retrieved snaps (%d) does not match number of types (%d)", len(snapdVersionByType), len(types))
switch snapSeed.EssentialType {
case snap.TypeSnapd:
systemSnapdVersions.SnapdVersion = snapdVersion
case snap.TypeKernel:
systemSnapdVersions.SnapdInitramfsVersion = snapdVersion
}
}
return snapdVersionByType, nil
return systemSnapdVersions, nil
}

// SystemAndGadgetAndEncryptionInfo return the system details
Expand All @@ -2247,20 +2249,20 @@ func (m *DeviceManager) SystemAndGadgetAndEncryptionInfo(wantedSystemLabel strin
return nil, nil, nil, fmt.Errorf("reading gadget information: %v", err)
}

var snapdVersionByType map[snap.Type]string
var systemSnapdVersions *install.SystemSnapdVersions
// Find snapd versions for snapd and kernel snaps in the seed for
// the passphrase/PINs auth checks.
// FDE is only supported in UC20+ (i.e. Model grade is set).
if systemAndSnaps.Model.Grade() != asserts.ModelGradeUnset {
// Snapd snap should exist in UC20+.
snapdVersionByType, err = snapdVersionByTypeFromSeed20(systemAndSnaps.Seed, []snap.Type{snap.TypeSnapd, snap.TypeKernel})
systemSnapdVersions, err = snapdVersionByTypeFromSeed20(systemAndSnaps.Seed, []snap.Type{snap.TypeSnapd, snap.TypeKernel})
if err != nil {
return nil, nil, nil, err
}

Check warning on line 2261 in overlord/devicestate/devicemgr.go

View check run for this annotation

Codecov / codecov/patch

overlord/devicestate/devicemgr.go#L2260-L2261

Added lines #L2260 - L2261 were not covered by tests
}

// Encryption details
encInfo, err := m.encryptionSupportInfo(systemAndSnaps.Model, secboot.TPMProvisionFull, systemAndSnaps.InfosByType[snap.TypeKernel], gadgetInfo, snapdVersionByType)
encInfo, err := m.encryptionSupportInfo(systemAndSnaps.Model, secboot.TPMProvisionFull, systemAndSnaps.InfosByType[snap.TypeKernel], gadgetInfo, systemSnapdVersions)
if err != nil {
return nil, nil, nil, err
}
Expand Down Expand Up @@ -2903,6 +2905,6 @@ func (m *DeviceManager) checkEncryption(st *state.State, deviceCtx snapstate.Dev
return install.CheckEncryptionSupport(model, tpmMode, kernelInfo, gadgetInfo, m.runFDESetupHook)
}

func (m *DeviceManager) encryptionSupportInfo(model *asserts.Model, tpmMode secboot.TPMProvisionMode, kernelInfo *snap.Info, gadgetInfo *gadget.Info, snapdVersionByType map[snap.Type]string) (install.EncryptionSupportInfo, error) {
return install.GetEncryptionSupportInfo(model, tpmMode, kernelInfo, gadgetInfo, snapdVersionByType, m.runFDESetupHook)
func (m *DeviceManager) encryptionSupportInfo(model *asserts.Model, tpmMode secboot.TPMProvisionMode, kernelInfo *snap.Info, gadgetInfo *gadget.Info, systemSnapdVersions *install.SystemSnapdVersions) (install.EncryptionSupportInfo, error) {
return install.GetEncryptionSupportInfo(model, tpmMode, kernelInfo, gadgetInfo, systemSnapdVersions, m.runFDESetupHook)
}
6 changes: 6 additions & 0 deletions overlord/devicestate/devicestate_install_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,12 @@ func (s *deviceMgrInstallAPISuite) testInstallSetupStorageEncryption(c *C, hasTP
snap.TypeSnapd: "2.68",
snap.TypeKernel: "2.68",
}
} else {
// mock other versions to cover more cases
snapdVersionByType = map[snap.Type]string{
snap.TypeSnapd: "2.67",
snap.TypeKernel: "2.66",
}
}
seedOpts := mockSystemSeedWithLabelOpts{
isClassic: isClassic,
Expand Down
8 changes: 4 additions & 4 deletions overlord/devicestate/handlers_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -1295,19 +1295,19 @@ func (m *DeviceManager) doInstallSetupStorageEncryption(t *state.Task, _ *tomb.T
return fmt.Errorf("reading gadget information: %v", err)
}

var snapdVersionByType map[snap.Type]string
var systemSnapdVersions *installLogic.SystemSnapdVersions
// Find snapd versions for snapd and kernel snaps in the seed for
// the passphrase/PINs auth checks.
// FDE is only supported in UC20+ (i.e. Model grade is set).
if volumesAuthRequired && systemAndSeeds.Model.Grade() != asserts.ModelGradeUnset {
if systemAndSeeds.Model.Grade() != asserts.ModelGradeUnset {
// Snapd and kernel snaps are expected to exist in UC20+.
snapdVersionByType, err = snapdVersionByTypeFromSeed20(systemAndSeeds.Seed, []snap.Type{snap.TypeSnapd, snap.TypeKernel})
systemSnapdVersions, err = snapdVersionByTypeFromSeed20(systemAndSeeds.Seed, []snap.Type{snap.TypeSnapd, snap.TypeKernel})
if err != nil {
return err
}

Check warning on line 1307 in overlord/devicestate/handlers_install.go

View check run for this annotation

Codecov / codecov/patch

overlord/devicestate/handlers_install.go#L1306-L1307

Added lines #L1306 - L1307 were not covered by tests
}

encryptInfo, err := m.encryptionSupportInfo(systemAndSeeds.Model, secboot.TPMProvisionFull, systemAndSeeds.InfosByType[snap.TypeKernel], gadgetInfo, snapdVersionByType)
encryptInfo, err := m.encryptionSupportInfo(systemAndSeeds.Model, secboot.TPMProvisionFull, systemAndSeeds.InfosByType[snap.TypeKernel], gadgetInfo, systemSnapdVersions)
if err != nil {
return err
}
Expand Down
52 changes: 35 additions & 17 deletions overlord/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ type EncryptionSupportInfo struct {
PassphraseAuthAvailable bool
}

// SystemSnapdVersions describes the snapd versions in a given systems.
type SystemSnapdVersions struct {
// SnapdVersion is the version of snapd in a given system
SnapdVersion string
// SnapdInitramfsVersion is the version of snapd related component, which participates
// in the boot process and performs unlocking. Typically snap-bootstrap in the kernel snap.
SnapdInitramfsVersion string
}

var (
timeNow = time.Now

Expand All @@ -103,31 +112,40 @@ func MockSecbootCheckTPMKeySealingSupported(f func(tpmMode secboot.TPMProvisionM
}
}

func checkPassphraseSupportedByTargetSystem(snapdVersionByType map[snap.Type]string) (bool, error) {
func checkPassphraseSupportedByTargetSystem(sysVer *SystemSnapdVersions) (bool, error) {
const minSnapdVersion = "2.68"
// snapd and snap-bootstrap inside the kernel must support passphrases.
for _, typ := range []snap.Type{snap.TypeSnapd, snap.TypeKernel} {
ver := snapdVersionByType[typ]
if ver == "" {
// absent snapd version info is expected for older kernels
return false, nil
}
cmp, err := strutil.VersionCompare(ver, minSnapdVersion)
if err != nil {
return false, fmt.Errorf("invalid snapd version in info file from %s snap: %v", typ, err)
}
if cmp < 0 {
return false, nil
}
if sysVer == nil {
return false, nil
}
if sysVer.SnapdVersion == "" || sysVer.SnapdInitramfsVersion == "" {
return false, nil
}

// snapd snap must support passphrases.
cmp, err := strutil.VersionCompare(sysVer.SnapdVersion, minSnapdVersion)
if err != nil {
return false, fmt.Errorf("invalid snapd version in info file from snapd snap: %v", err)
}

Check warning on line 128 in overlord/install/install.go

View check run for this annotation

Codecov / codecov/patch

overlord/install/install.go#L127-L128

Added lines #L127 - L128 were not covered by tests
if cmp < 0 {
return false, nil
}
// snap-bootstrap inside the kernel must support passphrases.
cmp, err = strutil.VersionCompare(sysVer.SnapdInitramfsVersion, minSnapdVersion)
if err != nil {
return false, fmt.Errorf("invalid snapd version in info file from kernel snap: %v", err)
}

Check warning on line 136 in overlord/install/install.go

View check run for this annotation

Codecov / codecov/patch

overlord/install/install.go#L135-L136

Added lines #L135 - L136 were not covered by tests
if cmp < 0 {
return false, nil
}

return true, nil
}

// GetEncryptionSupportInfo returns the encryption support information
// for the given model, TPM provision mode, kernel and gadget information and
// system hardware. It uses runSetupHook to invoke the kernel fde-setup hook if
// any is available, leaving the caller to decide how, based on the environment.
func GetEncryptionSupportInfo(model *asserts.Model, tpmMode secboot.TPMProvisionMode, kernelInfo *snap.Info, gadgetInfo *gadget.Info, snapdVersionByType map[snap.Type]string, runSetupHook fde.RunSetupHookFunc) (EncryptionSupportInfo, error) {
func GetEncryptionSupportInfo(model *asserts.Model, tpmMode secboot.TPMProvisionMode, kernelInfo *snap.Info, gadgetInfo *gadget.Info, systemSnapdVersions *SystemSnapdVersions, runSetupHook fde.RunSetupHookFunc) (EncryptionSupportInfo, error) {
secured := model.Grade() == asserts.ModelSecured
dangerous := model.Grade() == asserts.ModelDangerous
encrypted := model.StorageSafety() == asserts.StorageSafetyEncrypted
Expand Down Expand Up @@ -186,7 +204,7 @@ func GetEncryptionSupportInfo(model *asserts.Model, tpmMode secboot.TPMProvision
// it is usually in the context of embedded systems where passphrase
// authentication is not practical.
if checkSecbootEncryption {
passphraseAuthAvailable, err := checkPassphraseSupportedByTargetSystem(snapdVersionByType)
passphraseAuthAvailable, err := checkPassphraseSupportedByTargetSystem(systemSnapdVersions)
if err != nil {
return res, fmt.Errorf("cannot check passphrase support: %v", err)
}

Check warning on line 210 in overlord/install/install.go

View check run for this annotation

Codecov / codecov/patch

overlord/install/install.go#L209-L210

Added lines #L209 - L210 were not covered by tests
Expand Down
8 changes: 4 additions & 4 deletions overlord/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,12 @@ func (s *installSuite) TestEncryptionSupportInfoWithTPM(c *C) {
"grade": tc.grade,
"storage-safety": tc.storageSafety,
})
mockSnapdVersionByType := map[snap.Type]string{
snap.TypeSnapd: tc.snapdVersion,
snap.TypeKernel: tc.kernelSnapdVersion,
mockSystemSnapdVersions := &install.SystemSnapdVersions{
SnapdVersion: tc.snapdVersion,
SnapdInitramfsVersion: tc.kernelSnapdVersion,
}

res, err := install.GetEncryptionSupportInfo(mockModel, secboot.TPMProvisionFull, kernelInfo, gadgetInfo, mockSnapdVersionByType, nil)
res, err := install.GetEncryptionSupportInfo(mockModel, secboot.TPMProvisionFull, kernelInfo, gadgetInfo, mockSystemSnapdVersions, nil)
c.Assert(err, IsNil)
c.Check(res, DeepEquals, tc.expected, Commentf("%v", tc))
}
Expand Down

0 comments on commit 9b84668

Please sign in to comment.