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  }