gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/overlord/assertstate/assertmgr.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2017 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 assertstate 21 22 import ( 23 "fmt" 24 25 "gopkg.in/tomb.v2" 26 27 "github.com/snapcore/snapd/asserts" 28 "github.com/snapcore/snapd/asserts/snapasserts" 29 "github.com/snapcore/snapd/asserts/sysdb" 30 "github.com/snapcore/snapd/overlord/snapstate" 31 "github.com/snapcore/snapd/overlord/state" 32 ) 33 34 // AssertManager is responsible for the enforcement of assertions in 35 // system states. It manipulates the observed system state to ensure 36 // nothing in it violates existing assertions, or misses required 37 // ones. 38 type AssertManager struct{} 39 40 // Manager returns a new assertion manager. 41 func Manager(s *state.State, runner *state.TaskRunner) (*AssertManager, error) { 42 delayedCrossMgrInit() 43 44 runner.AddHandler("validate-snap", doValidateSnap, nil) 45 46 db, err := sysdb.Open() 47 if err != nil { 48 return nil, err 49 } 50 51 s.Lock() 52 ReplaceDB(s, db) 53 s.Unlock() 54 55 return &AssertManager{}, nil 56 } 57 58 // Ensure implements StateManager.Ensure. 59 func (m *AssertManager) Ensure() error { 60 return nil 61 } 62 63 type cachedDBKey struct{} 64 65 // ReplaceDB replaces the assertion database used by the manager. 66 func ReplaceDB(state *state.State, db *asserts.Database) { 67 state.Cache(cachedDBKey{}, db) 68 } 69 70 func cachedDB(s *state.State) *asserts.Database { 71 db := s.Cached(cachedDBKey{}) 72 if db == nil { 73 panic("internal error: needing an assertion database before the assertion manager is initialized") 74 } 75 return db.(*asserts.Database) 76 } 77 78 // DB returns a read-only view of system assertion database. 79 func DB(s *state.State) asserts.RODatabase { 80 return cachedDB(s) 81 } 82 83 // doValidateSnap fetches the relevant assertions for the snap being installed and cross checks them with the snap. 84 func doValidateSnap(t *state.Task, _ *tomb.Tomb) error { 85 st := t.State() 86 st.Lock() 87 defer st.Unlock() 88 89 snapsup, err := snapstate.TaskSnapSetup(t) 90 if err != nil { 91 return fmt.Errorf("internal error: cannot obtain snap setup: %s", err) 92 } 93 94 sha3_384, snapSize, err := asserts.SnapFileSHA3_384(snapsup.SnapPath) 95 if err != nil { 96 return err 97 } 98 99 deviceCtx, err := snapstate.DeviceCtx(st, t, nil) 100 if err != nil { 101 return err 102 } 103 104 modelAs := deviceCtx.Model() 105 106 err = doFetch(st, snapsup.UserID, deviceCtx, func(f asserts.Fetcher) error { 107 if err := snapasserts.FetchSnapAssertions(f, sha3_384); err != nil { 108 return err 109 } 110 111 // fetch store assertion if available 112 if modelAs.Store() != "" { 113 err := snapasserts.FetchStore(f, modelAs.Store()) 114 if notFound, ok := err.(*asserts.NotFoundError); ok { 115 if notFound.Type != asserts.StoreType { 116 return err 117 } 118 } else if err != nil { 119 return err 120 } 121 } 122 123 return nil 124 }) 125 if notFound, ok := err.(*asserts.NotFoundError); ok { 126 if notFound.Type == asserts.SnapRevisionType { 127 return fmt.Errorf("cannot verify snap %q, no matching signatures found", snapsup.InstanceName()) 128 } else { 129 return fmt.Errorf("cannot find supported signatures to verify snap %q and its hash (%v)", snapsup.InstanceName(), notFound) 130 } 131 } 132 if err != nil { 133 return err 134 } 135 136 db := DB(st) 137 err = snapasserts.CrossCheck(snapsup.InstanceName(), sha3_384, snapSize, snapsup.SideInfo, db) 138 if err != nil { 139 // TODO: trigger a global sanity check 140 // that will generate the changes to deal with this 141 // for things like snap-decl revocation and renames? 142 return err 143 } 144 145 // TODO: set DeveloperID from assertions 146 return nil 147 }