github.com/freetocompute/snapd@v0.0.0-20210618182524-2fb355d72fd9/cmd/snap-bootstrap/initramfs_mounts_state.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package main 21 22 import ( 23 "errors" 24 "fmt" 25 "os" 26 "path/filepath" 27 28 "github.com/snapcore/snapd/asserts" 29 "github.com/snapcore/snapd/boot" 30 "github.com/snapcore/snapd/logger" 31 "github.com/snapcore/snapd/osutil" 32 "github.com/snapcore/snapd/seed" 33 "github.com/snapcore/snapd/snap" 34 "github.com/snapcore/snapd/timings" 35 ) 36 37 var ( 38 osutilSetTime = osutil.SetTime 39 ) 40 41 // initramfsMountsState helps tracking the state and progress 42 // of the mounting driving process. 43 type initramfsMountsState struct { 44 mode string 45 recoverySystem string 46 } 47 48 var errRunModeNoImpliedRecoverySystem = errors.New("internal error: no implied recovery system in run mode") 49 50 // ReadEssential returns the model and verified essential 51 // snaps from the recoverySystem. If recoverySystem is "" the 52 // implied one will be used (only for modes other than run). 53 func (mst *initramfsMountsState) ReadEssential(recoverySystem string, essentialTypes []snap.Type) (*asserts.Model, []*seed.Snap, error) { 54 if recoverySystem == "" { 55 if mst.mode == "run" { 56 return nil, nil, errRunModeNoImpliedRecoverySystem 57 } 58 recoverySystem = mst.recoverySystem 59 } 60 61 perf := timings.New(nil) 62 63 // get the current time to pass to ReadSystemEssentialAndBetterEarliestTime 64 // note that we trust the time we have from the system, because that time 65 // comes from either: 66 // * a RTC on the system that the kernel/systemd consulted and used to move 67 // time forward 68 // * systemd using a built-in timestamp from the initrd which was stamped 69 // when the initrd was built, giving a lower bound on the current time if 70 // the RTC does not have a battery or is otherwise unreliable, etc. 71 now := timeNow() 72 73 model, snaps, newTrustedEarliestTime, err := seed.ReadSystemEssentialAndBetterEarliestTime(boot.InitramfsUbuntuSeedDir, recoverySystem, essentialTypes, now, perf) 74 if err != nil { 75 return nil, nil, err 76 } 77 78 // set the time on the system to move forward if it is in the future - never 79 // move the time backwards 80 if newTrustedEarliestTime.After(now) { 81 if err := osutilSetTime(newTrustedEarliestTime); err != nil { 82 // log the error but don't fail on it, we should be able to continue 83 // even if the time can't be moved forward 84 logger.Noticef("failed to move time forward from %s to %s: %v", now, newTrustedEarliestTime, err) 85 } 86 } 87 88 return model, snaps, nil 89 } 90 91 // UnverifiedBootModel returns the unverified model from the 92 // boot partition for run mode. The current and only use case 93 // is measuring the model for run mode. Otherwise no decisions 94 // should be based on an unverified model. Note that the model 95 // is verified at the time the key auth policy is computed. 96 func (mst *initramfsMountsState) UnverifiedBootModel() (*asserts.Model, error) { 97 if mst.mode != "run" { 98 return nil, fmt.Errorf("internal error: unverified boot model access is for limited run mode use") 99 } 100 101 mf, err := os.Open(filepath.Join(boot.InitramfsUbuntuBootDir, "device/model")) 102 if err != nil { 103 return nil, fmt.Errorf("cannot read model assertion: %v", err) 104 } 105 defer mf.Close() 106 ma, err := asserts.NewDecoder(mf).Decode() 107 if err != nil { 108 return nil, fmt.Errorf("cannot decode assertion: %v", err) 109 } 110 if ma.Type() != asserts.ModelType { 111 return nil, fmt.Errorf("unexpected assertion: %q", ma.Type().Name) 112 } 113 return ma.(*asserts.Model), nil 114 } 115 116 // EphemeralModeenvForModel generates a modeenv given the model and the snaps for the 117 // current mode and recovery system of the initramfsMountsState. 118 func (mst *initramfsMountsState) EphemeralModeenvForModel(model *asserts.Model, snaps map[snap.Type]snap.PlaceInfo) (*boot.Modeenv, error) { 119 if mst.mode == "run" { 120 return nil, fmt.Errorf("internal error: initramfs should not write modeenv in run mode") 121 } 122 return &boot.Modeenv{ 123 Mode: mst.mode, 124 RecoverySystem: mst.recoverySystem, 125 Base: snaps[snap.TypeBase].Filename(), 126 Model: model.Model(), 127 BrandID: model.BrandID(), 128 Grade: string(model.Grade()), 129 // TODO:UC20: what about current kernel snaps, trusted boot assets and 130 // kernel command lines? 131 }, nil 132 }