github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/overlord/snapstate/check_snap_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 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 snapstate_test
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  	"os/user"
    26  
    27  	. "gopkg.in/check.v1"
    28  
    29  	"github.com/snapcore/snapd/arch"
    30  	"github.com/snapcore/snapd/dirs"
    31  	"github.com/snapcore/snapd/osutil"
    32  	"github.com/snapcore/snapd/overlord/state"
    33  	"github.com/snapcore/snapd/release"
    34  	seccomp_compiler "github.com/snapcore/snapd/sandbox/seccomp"
    35  	"github.com/snapcore/snapd/snap"
    36  	"github.com/snapcore/snapd/snap/snaptest"
    37  	"github.com/snapcore/snapd/snapdtool"
    38  	"github.com/snapcore/snapd/testutil"
    39  
    40  	"github.com/snapcore/snapd/overlord/snapstate"
    41  	"github.com/snapcore/snapd/overlord/snapstate/snapstatetest"
    42  )
    43  
    44  type checkSnapSuite struct {
    45  	testutil.BaseTest
    46  	st        *state.State
    47  	deviceCtx snapstate.DeviceContext
    48  }
    49  
    50  var _ = Suite(&checkSnapSuite{})
    51  
    52  func (s *checkSnapSuite) SetUpTest(c *C) {
    53  	s.BaseTest.SetUpTest(c)
    54  	dirs.SetRootDir(c.MkDir())
    55  	s.st = state.New(nil)
    56  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    57  	s.deviceCtx = &snapstatetest.TrivialDeviceContext{DeviceModel: MakeModel(map[string]interface{}{
    58  		"kernel": "kernel",
    59  		"gadget": "gadget",
    60  	})}
    61  }
    62  
    63  func (s *checkSnapSuite) TearDownTest(c *C) {
    64  	s.BaseTest.TearDownTest(c)
    65  	dirs.SetRootDir("")
    66  }
    67  
    68  func emptyContainer(c *C) snap.Container {
    69  	return snaptest.MockContainer(c, nil)
    70  }
    71  
    72  func (s *checkSnapSuite) TestCheckSnapErrorOnUnsupportedArchitecture(c *C) {
    73  	const yaml = `name: hello
    74  version: 1.10
    75  architectures:
    76      - yadayada
    77      - blahblah
    78  `
    79  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
    80  	c.Assert(err, IsNil)
    81  
    82  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
    83  		c.Check(path, Equals, "snap-path")
    84  		c.Check(si, IsNil)
    85  		return info, emptyContainer(c), nil
    86  	}
    87  	restore := snapstate.MockOpenSnapFile(openSnapFile)
    88  	defer restore()
    89  
    90  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil)
    91  
    92  	errorMsg := fmt.Sprintf(`snap "hello" supported architectures (yadayada, blahblah) are incompatible with this system (%s)`, arch.DpkgArchitecture())
    93  	c.Assert(err.Error(), Equals, errorMsg)
    94  }
    95  
    96  var assumesTests = []struct {
    97  	version string
    98  	assumes string
    99  	classic bool
   100  	error   string
   101  }{{
   102  	assumes: "[common-data-dir]",
   103  }, {
   104  	assumes: "[f1, f2]",
   105  	error:   `snap "foo" assumes unsupported features: f1, f2 \(try to refresh the core or snapd snaps\)`,
   106  }, {
   107  	assumes: "[f1, f2]",
   108  	classic: true,
   109  	error:   `snap "foo" assumes unsupported features: f1, f2 \(try to update snapd and refresh the core snap\)`,
   110  }, {
   111  	assumes: "[snapd2.15]",
   112  	version: "unknown",
   113  }, {
   114  	assumes: "[snapdnono]",
   115  	version: "unknown",
   116  	error:   `.* unsupported features: snapdnono .*`,
   117  }, {
   118  	assumes: "[snapd2.15nono]",
   119  	version: "unknown",
   120  	error:   `.* unsupported features: snapd2.15nono .*`,
   121  }, {
   122  	assumes: "[snapd2.15]",
   123  	version: "2.15",
   124  }, {
   125  	assumes: "[snapd2.15]",
   126  	version: "2.15.1",
   127  }, {
   128  	assumes: "[snapd2.15]",
   129  	version: "2.15+git",
   130  }, {
   131  	assumes: "[snapd2.15]",
   132  	version: "2.16",
   133  }, {
   134  	assumes: "[snapd2.15.1]",
   135  	version: "2.16",
   136  }, {
   137  	assumes: "[snapd2.15.2]",
   138  	version: "2.16.1",
   139  }, {
   140  	assumes: "[snapd3]",
   141  	version: "3.1",
   142  }, {
   143  	assumes: "[snapd2.16]",
   144  	version: "2.15",
   145  	error:   `.* unsupported features: snapd2\.16 .*`,
   146  }, {
   147  	assumes: "[snapd2.15.1]",
   148  	version: "2.15",
   149  	error:   `.* unsupported features: snapd2\.15\.1 .*`,
   150  }, {
   151  	assumes: "[snapd2.15.1]",
   152  	version: "2.15.0",
   153  	error:   `.* unsupported features: snapd2\.15\.1 .*`,
   154  }, {
   155  	// Note that this is different from how strconv.VersionCompare
   156  	// (dpkg version numbering) would behave - it would error here
   157  	assumes: "[snapd2.15]",
   158  	version: "2.15~pre1",
   159  }, {
   160  	assumes: "[command-chain]",
   161  }}
   162  
   163  func (s *checkSnapSuite) TestCheckSnapAssumes(c *C) {
   164  	restore := snapdtool.MockVersion("2.15")
   165  	defer restore()
   166  
   167  	restore = release.MockOnClassic(false)
   168  	defer restore()
   169  
   170  	for _, test := range assumesTests {
   171  		snapdtool.Version = test.version
   172  		if snapdtool.Version == "" {
   173  			snapdtool.Version = "2.15"
   174  		}
   175  		release.OnClassic = test.classic
   176  
   177  		yaml := fmt.Sprintf("name: foo\nversion: 1.0\nassumes: %s\n", test.assumes)
   178  
   179  		info, err := snap.InfoFromSnapYaml([]byte(yaml))
   180  		c.Assert(err, IsNil)
   181  
   182  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   183  			return info, emptyContainer(c), nil
   184  		}
   185  		restore := snapstate.MockOpenSnapFile(openSnapFile)
   186  		defer restore()
   187  		err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
   188  		if test.error != "" {
   189  			c.Check(err, ErrorMatches, test.error)
   190  		} else {
   191  			c.Assert(err, IsNil)
   192  		}
   193  	}
   194  }
   195  
   196  func (s *checkSnapSuite) TestCheckSnapCheckCallbackOK(c *C) {
   197  	const yaml = `name: foo
   198  version: 1.0`
   199  
   200  	si := &snap.SideInfo{
   201  		SnapID: "snap-id",
   202  	}
   203  
   204  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   205  		info := snaptest.MockInfo(c, yaml, si)
   206  		cont := snaptest.MockContainer(c, [][]string{{"canary", "canary"}})
   207  		return info, cont, nil
   208  	}
   209  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   210  	defer r1()
   211  
   212  	checkCbCalled := false
   213  	checkCb := func(st *state.State, s, cur *snap.Info, sf snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error {
   214  		c.Assert(sf, NotNil)
   215  		data, err := sf.ReadFile("canary")
   216  		c.Assert(err, IsNil)
   217  		c.Assert(data, DeepEquals, []byte("canary"))
   218  		c.Assert(s.InstanceName(), Equals, "foo")
   219  		c.Assert(s.SnapID, Equals, "snap-id")
   220  		checkCbCalled = true
   221  		return nil
   222  	}
   223  	r2 := snapstate.MockCheckSnapCallbacks([]snapstate.CheckSnapCallback{checkCb})
   224  	defer r2()
   225  
   226  	err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, nil, snapstate.Flags{}, nil)
   227  	c.Check(err, IsNil)
   228  
   229  	c.Check(checkCbCalled, Equals, true)
   230  }
   231  
   232  func (s *checkSnapSuite) TestCheckSnapCheckCallbackFail(c *C) {
   233  	const yaml = `name: foo
   234  version: 1.0`
   235  
   236  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   237  	c.Assert(err, IsNil)
   238  
   239  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   240  		return info, emptyContainer(c), nil
   241  	}
   242  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   243  	defer restore()
   244  
   245  	fail := errors.New("bad snap")
   246  	checkCb := func(st *state.State, s, cur *snap.Info, _ snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error {
   247  		return fail
   248  	}
   249  	r2 := snapstate.MockCheckSnapCallbacks(nil)
   250  	defer r2()
   251  	snapstate.AddCheckSnapCallback(checkCb)
   252  
   253  	err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
   254  	c.Check(err, Equals, fail)
   255  }
   256  
   257  func (s *checkSnapSuite) TestCheckSnapGadgetUpdate(c *C) {
   258  	reset := release.MockOnClassic(false)
   259  	defer reset()
   260  
   261  	st := state.New(nil)
   262  	st.Lock()
   263  	defer st.Unlock()
   264  
   265  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
   266  	snaptest.MockSnap(c, `
   267  name: gadget
   268  type: gadget
   269  version: 1
   270  `, si)
   271  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   272  		SnapType: "gadget",
   273  		Active:   true,
   274  		Sequence: []*snap.SideInfo{si},
   275  		Current:  si.Revision,
   276  	})
   277  
   278  	const yaml = `name: gadget
   279  type: gadget
   280  version: 2
   281  `
   282  
   283  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   284  	info.SnapID = "gadget-id"
   285  	c.Assert(err, IsNil)
   286  
   287  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   288  		return info, emptyContainer(c), nil
   289  	}
   290  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   291  	defer restore()
   292  
   293  	st.Unlock()
   294  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   295  	st.Lock()
   296  	c.Check(err, IsNil)
   297  }
   298  
   299  func (s *checkSnapSuite) TestCheckSnapGadgetUpdateLocal(c *C) {
   300  	reset := release.MockOnClassic(false)
   301  	defer reset()
   302  
   303  	st := state.New(nil)
   304  	st.Lock()
   305  	defer st.Unlock()
   306  
   307  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2)}
   308  	snaptest.MockSnap(c, `
   309  name: gadget
   310  type: gadget
   311  version: 1
   312  `, si)
   313  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   314  		SnapType: "gadget",
   315  		Active:   true,
   316  		Sequence: []*snap.SideInfo{si},
   317  		Current:  si.Revision,
   318  	})
   319  
   320  	const yaml = `name: gadget
   321  type: gadget
   322  version: 2
   323  `
   324  
   325  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   326  	// no SnapID => local!
   327  	c.Assert(err, IsNil)
   328  
   329  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   330  		return info, emptyContainer(c), nil
   331  	}
   332  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   333  	defer restore()
   334  
   335  	st.Unlock()
   336  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   337  	st.Lock()
   338  	c.Check(err, IsNil)
   339  }
   340  
   341  func (s *checkSnapSuite) TestCheckSnapGadgetUpdateToUnassertedProhibited(c *C) {
   342  	reset := release.MockOnClassic(false)
   343  	defer reset()
   344  
   345  	st := state.New(nil)
   346  	st.Lock()
   347  	defer st.Unlock()
   348  
   349  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
   350  	snaptest.MockSnap(c, `
   351  name: gadget
   352  type: gadget
   353  version: 1
   354  `, si)
   355  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   356  		SnapType: "gadget",
   357  		Active:   true,
   358  		Sequence: []*snap.SideInfo{si},
   359  		Current:  si.Revision,
   360  	})
   361  
   362  	const yaml = `name: gadget
   363  type: gadget
   364  version: 2
   365  `
   366  
   367  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   368  	c.Assert(err, IsNil)
   369  
   370  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   371  		return info, emptyContainer(c), nil
   372  	}
   373  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   374  	defer restore()
   375  
   376  	st.Unlock()
   377  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   378  	st.Lock()
   379  	c.Check(err, ErrorMatches, `cannot replace signed gadget snap with an unasserted one`)
   380  }
   381  
   382  func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibited(c *C) {
   383  	reset := release.MockOnClassic(false)
   384  	defer reset()
   385  
   386  	st := state.New(nil)
   387  	st.Lock()
   388  	defer st.Unlock()
   389  
   390  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2)}
   391  	snaptest.MockSnap(c, `
   392  name: gadget
   393  type: gadget
   394  version: 1
   395  `, si)
   396  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   397  		SnapType: "gadget",
   398  		Active:   true,
   399  		Sequence: []*snap.SideInfo{si},
   400  		Current:  si.Revision,
   401  	})
   402  
   403  	const yaml = `name: zgadget
   404  type: gadget
   405  version: 2
   406  `
   407  
   408  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   409  	c.Assert(err, IsNil)
   410  
   411  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   412  		return info, emptyContainer(c), nil
   413  	}
   414  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   415  	defer restore()
   416  
   417  	st.Unlock()
   418  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   419  	st.Lock()
   420  	c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one")
   421  }
   422  
   423  func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibitedBySnapID(c *C) {
   424  	reset := release.MockOnClassic(false)
   425  	defer reset()
   426  
   427  	st := state.New(nil)
   428  	st.Lock()
   429  	defer st.Unlock()
   430  
   431  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
   432  	snaptest.MockSnap(c, `
   433  name: gadget
   434  type: gadget
   435  version: 1
   436  `, si)
   437  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   438  		SnapType: "gadget",
   439  		Active:   true,
   440  		Sequence: []*snap.SideInfo{si},
   441  		Current:  si.Revision,
   442  	})
   443  
   444  	const yaml = `name: zgadget
   445  type: gadget
   446  version: 2
   447  `
   448  
   449  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   450  	info.SnapID = "zgadget-id"
   451  	c.Assert(err, IsNil)
   452  
   453  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   454  		return info, emptyContainer(c), nil
   455  	}
   456  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   457  	defer restore()
   458  
   459  	st.Unlock()
   460  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   461  	st.Lock()
   462  	c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one")
   463  }
   464  
   465  func (s *checkSnapSuite) TestCheckSnapGadgetNoPrior(c *C) {
   466  	reset := release.MockOnClassic(false)
   467  	defer reset()
   468  
   469  	st := state.New(nil)
   470  	st.Lock()
   471  	defer st.Unlock()
   472  	st.Set("seeded", true)
   473  
   474  	const yaml = `name: gadget
   475  type: gadget
   476  version: 1
   477  `
   478  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   479  	c.Assert(err, IsNil)
   480  
   481  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   482  		return info, emptyContainer(c), nil
   483  	}
   484  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   485  	defer restore()
   486  
   487  	st.Unlock()
   488  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, nil)
   489  	st.Lock()
   490  	c.Check(err, IsNil)
   491  }
   492  
   493  func (s *checkSnapSuite) TestCheckSnapErrorOnDevModeDisallowed(c *C) {
   494  	const yaml = `name: hello
   495  version: 1.10
   496  confinement: devmode
   497  `
   498  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   499  	c.Assert(err, IsNil)
   500  
   501  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   502  		c.Check(path, Equals, "snap-path")
   503  		c.Check(si, IsNil)
   504  		return info, emptyContainer(c), nil
   505  	}
   506  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   507  	defer restore()
   508  
   509  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil)
   510  
   511  	c.Assert(err, ErrorMatches, ".* requires devmode or confinement override")
   512  }
   513  
   514  func (s *checkSnapSuite) TestCheckSnapErrorOnClassicDisallowed(c *C) {
   515  	const yaml = `name: hello
   516  version: 1.10
   517  confinement: classic
   518  `
   519  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   520  	c.Assert(err, IsNil)
   521  
   522  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   523  		c.Check(path, Equals, "snap-path")
   524  		c.Check(si, IsNil)
   525  		return info, emptyContainer(c), nil
   526  	}
   527  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   528  	defer restore()
   529  
   530  	restore = release.MockOnClassic(true)
   531  	defer restore()
   532  
   533  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil)
   534  
   535  	c.Assert(err, ErrorMatches, ".* requires classic confinement")
   536  }
   537  
   538  func (s *checkSnapSuite) TestCheckSnapErrorClassicOnCoreDisallowed(c *C) {
   539  	const yaml = `name: hello
   540  version: 1.10
   541  confinement: classic
   542  `
   543  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   544  	c.Assert(err, IsNil)
   545  
   546  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   547  		c.Check(path, Equals, "snap-path")
   548  		c.Check(si, IsNil)
   549  		return info, emptyContainer(c), nil
   550  	}
   551  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   552  	defer restore()
   553  
   554  	restore = release.MockOnClassic(false)
   555  	defer restore()
   556  
   557  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{Classic: true}, nil)
   558  
   559  	c.Assert(err, ErrorMatches, ".* requires classic confinement which is only available on classic systems")
   560  }
   561  
   562  func (s *checkSnapSuite) TestCheckSnapErrorClassicModeForStrictOrDevmode(c *C) {
   563  	const yaml = `name: hello
   564  version: 1.10
   565  confinement: strict
   566  `
   567  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   568  	c.Assert(err, IsNil)
   569  
   570  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   571  		c.Check(path, Equals, "snap-path")
   572  		c.Check(si, IsNil)
   573  		return info, emptyContainer(c), nil
   574  	}
   575  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   576  	defer restore()
   577  
   578  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{Classic: true}, nil)
   579  
   580  	c.Assert(err, ErrorMatches, `snap "hello" is not a classic confined snap`)
   581  }
   582  
   583  func (s *checkSnapSuite) TestCheckSnapKernelUpdate(c *C) {
   584  	reset := release.MockOnClassic(false)
   585  	defer reset()
   586  
   587  	st := state.New(nil)
   588  	st.Lock()
   589  	defer st.Unlock()
   590  
   591  	si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"}
   592  	snaptest.MockSnap(c, `
   593  name: kernel
   594  type: kernel
   595  version: 1
   596  `, si)
   597  	snapstate.Set(st, "kernel", &snapstate.SnapState{
   598  		SnapType: "kernel",
   599  		Active:   true,
   600  		Sequence: []*snap.SideInfo{si},
   601  		Current:  si.Revision,
   602  	})
   603  
   604  	const yaml = `name: kernel
   605  type: kernel
   606  version: 2
   607  `
   608  
   609  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   610  	info.SnapID = "kernel-id"
   611  	c.Assert(err, IsNil)
   612  
   613  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   614  		return info, emptyContainer(c), nil
   615  	}
   616  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   617  	defer restore()
   618  
   619  	st.Unlock()
   620  	err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx)
   621  	st.Lock()
   622  	c.Check(err, IsNil)
   623  }
   624  
   625  func (s *checkSnapSuite) TestCheckSnapKernelAdditionProhibitedBySnapID(c *C) {
   626  	reset := release.MockOnClassic(false)
   627  	defer reset()
   628  
   629  	st := state.New(nil)
   630  	st.Lock()
   631  	defer st.Unlock()
   632  
   633  	si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"}
   634  	snaptest.MockSnap(c, `
   635  name: kernel
   636  type: kernel
   637  version: 1
   638  `, si)
   639  	snapstate.Set(st, "kernel", &snapstate.SnapState{
   640  		SnapType: "kernel",
   641  		Active:   true,
   642  		Sequence: []*snap.SideInfo{si},
   643  		Current:  si.Revision,
   644  	})
   645  
   646  	const yaml = `name: zkernel
   647  type: kernel
   648  version: 2
   649  `
   650  
   651  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   652  	info.SnapID = "zkernel-id"
   653  	c.Assert(err, IsNil)
   654  
   655  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   656  		return info, emptyContainer(c), nil
   657  	}
   658  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   659  	defer restore()
   660  
   661  	st.Unlock()
   662  	err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx)
   663  	st.Lock()
   664  	c.Check(err, ErrorMatches, "cannot replace kernel snap with a different one")
   665  }
   666  
   667  func (s *checkSnapSuite) TestCheckSnapNoStateInfoInternalError(c *C) {
   668  	reset := release.MockOnClassic(false)
   669  	defer reset()
   670  
   671  	st := state.New(nil)
   672  	st.Lock()
   673  	defer st.Unlock()
   674  
   675  	si := &snap.SideInfo{RealName: "other-kernel", Revision: snap.R(2), SnapID: "kernel-id"}
   676  	snaptest.MockSnap(c, `
   677  name: other-kernel
   678  type: kernel
   679  version: 1
   680  `, si)
   681  	// we have a state information for snap of type kernel, but it's a
   682  	// different snap
   683  	snapstate.Set(st, "other-kernel", &snapstate.SnapState{
   684  		SnapType: "kernel",
   685  		Active:   true,
   686  		Sequence: []*snap.SideInfo{si},
   687  		Current:  si.Revision,
   688  	})
   689  
   690  	const yaml = `name: kernel
   691  type: kernel
   692  version: 2
   693  `
   694  
   695  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   696  	info.SnapID = "kernel-id"
   697  	c.Assert(err, IsNil)
   698  
   699  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   700  		return info, emptyContainer(c), nil
   701  	}
   702  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   703  	defer restore()
   704  
   705  	st.Unlock()
   706  	err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx)
   707  	st.Lock()
   708  	c.Check(err, ErrorMatches, "internal error: no state for kernel snap \"kernel\"")
   709  }
   710  
   711  func (s *checkSnapSuite) TestCheckSnapBasesErrorsIfMissing(c *C) {
   712  	st := state.New(nil)
   713  	st.Lock()
   714  	defer st.Unlock()
   715  
   716  	const yaml = `name: requires-base
   717  version: 1
   718  base: some-base
   719  `
   720  
   721  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   722  	c.Assert(err, IsNil)
   723  
   724  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   725  		return info, emptyContainer(c), nil
   726  	}
   727  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   728  	defer restore()
   729  
   730  	st.Unlock()
   731  	err = snapstate.CheckSnap(st, "snap-path", "requires-base", nil, nil, snapstate.Flags{}, nil)
   732  	st.Lock()
   733  	c.Check(err, ErrorMatches, "cannot find required base \"some-base\"")
   734  }
   735  
   736  func (s *checkSnapSuite) TestCheckSnapBasesNoneHappy(c *C) {
   737  	st := state.New(nil)
   738  	st.Lock()
   739  	defer st.Unlock()
   740  
   741  	const yaml = `name: use-base-none
   742  version: 1
   743  base: none
   744  `
   745  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   746  	c.Assert(err, IsNil)
   747  
   748  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   749  		return info, emptyContainer(c), nil
   750  	}
   751  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   752  	defer restore()
   753  
   754  	st.Unlock()
   755  	err = snapstate.CheckSnap(st, "snap-path", "use-base-none", nil, nil, snapstate.Flags{}, nil)
   756  	st.Lock()
   757  	c.Check(err, IsNil)
   758  }
   759  
   760  func (s *checkSnapSuite) TestCheckSnapBasesHappy(c *C) {
   761  	st := state.New(nil)
   762  	st.Lock()
   763  	defer st.Unlock()
   764  
   765  	si := &snap.SideInfo{RealName: "some-base", Revision: snap.R(1), SnapID: "some-base-id"}
   766  	snaptest.MockSnap(c, `
   767  name: some-base
   768  type: base
   769  version: 1
   770  `, si)
   771  	snapstate.Set(st, "some-base", &snapstate.SnapState{
   772  		SnapType: "base",
   773  		Active:   true,
   774  		Sequence: []*snap.SideInfo{si},
   775  		Current:  si.Revision,
   776  	})
   777  
   778  	const yaml = `name: requires-base
   779  version: 1
   780  base: some-base
   781  `
   782  
   783  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   784  	c.Assert(err, IsNil)
   785  
   786  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   787  		return info, emptyContainer(c), nil
   788  	}
   789  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   790  	defer restore()
   791  
   792  	st.Unlock()
   793  	err = snapstate.CheckSnap(st, "snap-path", "requires-base", nil, nil, snapstate.Flags{}, nil)
   794  	st.Lock()
   795  	c.Check(err, IsNil)
   796  }
   797  
   798  func (s *checkSnapSuite) TestCheckSnapInstanceName(c *C) {
   799  	st := state.New(nil)
   800  	st.Lock()
   801  	defer st.Unlock()
   802  
   803  	si := &snap.SideInfo{RealName: "foo", Revision: snap.R(1), SnapID: "some-base-id"}
   804  	info := snaptest.MockSnap(c, `
   805  name: foo
   806  version: 1
   807  `, si)
   808  	snapstate.Set(st, "foo", &snapstate.SnapState{
   809  		Active:   true,
   810  		Sequence: []*snap.SideInfo{si},
   811  		Current:  si.Revision,
   812  	})
   813  
   814  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   815  		return info, emptyContainer(c), nil
   816  	}
   817  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   818  	defer restore()
   819  
   820  	st.Unlock()
   821  	err := snapstate.CheckSnap(st, "snap-path", "foo_instance", nil, nil, snapstate.Flags{}, nil)
   822  	st.Lock()
   823  	c.Check(err, IsNil)
   824  
   825  	st.Unlock()
   826  	err = snapstate.CheckSnap(st, "snap-path", "bar_instance", nil, nil, snapstate.Flags{}, nil)
   827  	st.Lock()
   828  	c.Check(err, ErrorMatches, `cannot install snap "foo" using instance name "bar_instance"`)
   829  
   830  	st.Unlock()
   831  	err = snapstate.CheckSnap(st, "snap-path", "other-name", nil, nil, snapstate.Flags{}, nil)
   832  	st.Lock()
   833  	c.Check(err, ErrorMatches, `cannot install snap "foo" using instance name "other-name"`)
   834  }
   835  
   836  func (s *checkSnapSuite) TestCheckSnapCheckCallInstanceKeySet(c *C) {
   837  	const yaml = `name: foo
   838  version: 1.0`
   839  
   840  	si := &snap.SideInfo{
   841  		SnapID: "snap-id",
   842  	}
   843  
   844  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   845  		info := snaptest.MockInfo(c, yaml, si)
   846  		return info, emptyContainer(c), nil
   847  	}
   848  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   849  	defer r1()
   850  
   851  	checkCbCalled := false
   852  	checkCb := func(st *state.State, s, cur *snap.Info, sf snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error {
   853  		c.Assert(sf, NotNil)
   854  		c.Assert(s.InstanceName(), Equals, "foo_instance")
   855  		c.Assert(s.SnapName(), Equals, "foo")
   856  		c.Assert(s.SnapID, Equals, "snap-id")
   857  		checkCbCalled = true
   858  		return nil
   859  	}
   860  	r2 := snapstate.MockCheckSnapCallbacks([]snapstate.CheckSnapCallback{checkCb})
   861  	defer r2()
   862  
   863  	err := snapstate.CheckSnap(s.st, "snap-path", "foo_instance", si, nil, snapstate.Flags{}, nil)
   864  	c.Check(err, IsNil)
   865  
   866  	c.Check(checkCbCalled, Equals, true)
   867  }
   868  
   869  func (s *checkSnapSuite) TestCheckSnapCheckEpochLocal(c *C) {
   870  	si := &snap.SideInfo{
   871  		SnapID: "snap-id",
   872  	}
   873  
   874  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   875  		info := snaptest.MockInfo(c, "{name: foo, version: 1.0, epoch: 13}", si)
   876  		return info, emptyContainer(c), nil
   877  	}
   878  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   879  	defer r1()
   880  
   881  	err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, &snap.Info{}, snapstate.Flags{}, nil)
   882  	c.Check(err, ErrorMatches, `cannot refresh "foo" to local snap with epoch 13, because it can't read the current epoch of 0`)
   883  }
   884  
   885  func (s *checkSnapSuite) TestCheckSnapCheckEpochNonLocal(c *C) {
   886  	si := &snap.SideInfo{
   887  		SnapID:   "snap-id",
   888  		Revision: snap.R(42),
   889  	}
   890  
   891  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   892  		info := snaptest.MockInfo(c, "{name: foo, version: 1.0, epoch: 13}", si)
   893  		return info, emptyContainer(c), nil
   894  	}
   895  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   896  	defer r1()
   897  
   898  	err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, &snap.Info{}, snapstate.Flags{}, nil)
   899  	c.Check(err, ErrorMatches, `cannot refresh "foo" to new revision 42 with epoch 13, because it can't read the current epoch of 0`)
   900  }
   901  
   902  func (s *checkSnapSuite) TestCheckSnapBasesCoreCanBeUsedAsCore16(c *C) {
   903  	st := state.New(nil)
   904  	st.Lock()
   905  	defer st.Unlock()
   906  
   907  	si := &snap.SideInfo{RealName: "core", Revision: snap.R(1), SnapID: "core-id"}
   908  	snaptest.MockSnap(c, `
   909  name: core
   910  type: os
   911  version: 1
   912  `, si)
   913  	snapstate.Set(st, "core", &snapstate.SnapState{
   914  		SnapType: "os",
   915  		Active:   true,
   916  		Sequence: []*snap.SideInfo{si},
   917  		Current:  si.Revision,
   918  	})
   919  
   920  	const yaml = `name: requires-core16
   921  version: 1
   922  base: core16
   923  `
   924  
   925  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   926  	c.Assert(err, IsNil)
   927  
   928  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   929  		return info, emptyContainer(c), nil
   930  	}
   931  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   932  	defer restore()
   933  
   934  	st.Unlock()
   935  	err = snapstate.CheckSnap(st, "snap-path", "requires-core16", nil, nil, snapstate.Flags{}, nil)
   936  	st.Lock()
   937  	c.Check(err, IsNil)
   938  }
   939  
   940  func (s *checkSnapSuite) TestCheckSnapdHappy(c *C) {
   941  	st := state.New(nil)
   942  	st.Lock()
   943  	defer st.Unlock()
   944  
   945  	for _, t := range []struct {
   946  		yaml   string
   947  		errStr string
   948  	}{
   949  		{"name: snapd\nversion: 1\ntype: snapd", ""},
   950  		{"name: some-snap\nversion: 1\ntype: snapd", `cannot install snap "some-snap" of type "snapd" with a name other than "snapd"`},
   951  		{"name: snapd_instance\nversion: 1\ntype: snapd", `cannot install snap "snapd_instance" of type "snapd" with a name other than "snapd"`},
   952  	} {
   953  		info, err := snap.InfoFromSnapYaml([]byte(t.yaml))
   954  		c.Assert(err, IsNil)
   955  
   956  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   957  			return info, emptyContainer(c), nil
   958  		}
   959  		restore := snapstate.MockOpenSnapFile(openSnapFile)
   960  		defer restore()
   961  
   962  		st.Unlock()
   963  		err = snapstate.CheckSnap(st, "snap-path", "snapd", nil, nil, snapstate.Flags{}, nil)
   964  		st.Lock()
   965  		if t.errStr == "" {
   966  			c.Check(err, IsNil)
   967  		} else {
   968  			c.Check(err, ErrorMatches, t.errStr)
   969  		}
   970  	}
   971  }
   972  
   973  // Note, invalid usernames checked in snap/info_snap_yaml.go
   974  var systemUsernamesTests = []struct {
   975  	sysIDs      string
   976  	classic     bool
   977  	noRangeUser bool
   978  	noUser      bool
   979  	scVer       string
   980  	error       string
   981  }{{
   982  	sysIDs: "snap_daemon: shared",
   983  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   984  }, {
   985  	sysIDs: "snap_daemon:\n    scope: shared",
   986  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   987  }, {
   988  	sysIDs: "snap_daemon:\n    scope: private",
   989  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   990  	error:  `snap "foo" requires unsupported user scope "private" for this version of snapd`,
   991  }, {
   992  	sysIDs: "snap_daemon:\n    scope: external",
   993  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   994  	error:  `snap "foo" requires unsupported user scope "external" for this version of snapd`,
   995  }, {
   996  	sysIDs: "snap_daemon:\n    scope: other",
   997  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   998  	error:  `snap "foo" requires unsupported user scope "other"`,
   999  }, {
  1000  	sysIDs:  "snap_daemon: shared",
  1001  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1002  	classic: true,
  1003  }, {
  1004  	sysIDs:  "snap_daemon:\n    scope: shared",
  1005  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1006  	classic: true,
  1007  }, {
  1008  	sysIDs:  "snap_daemon:\n    scope: private",
  1009  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1010  	classic: true,
  1011  	error:   `snap "foo" requires unsupported user scope "private" for this version of snapd`,
  1012  }, {
  1013  	sysIDs:  "snap_daemon:\n    scope: external",
  1014  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1015  	classic: true,
  1016  	error:   `snap "foo" requires unsupported user scope "external" for this version of snapd`,
  1017  }, {
  1018  	sysIDs:  "snap_daemon:\n    scope: other",
  1019  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1020  	classic: true,
  1021  	error:   `snap "foo" requires unsupported user scope "other"`,
  1022  }, {
  1023  	sysIDs: "snap_daemon: shared\n  allowed-not: shared",
  1024  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
  1025  	error:  `snap "foo" requires unsupported system username "allowed-not"`,
  1026  }, {
  1027  	sysIDs:  "allowed-not: shared\n  snap_daemon: shared",
  1028  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1029  	classic: true,
  1030  	error:   `snap "foo" requires unsupported system username "allowed-not"`,
  1031  }, {
  1032  	sysIDs: "snap_daemon: shared",
  1033  	noUser: true,
  1034  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
  1035  	error:  `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`,
  1036  }, {
  1037  	sysIDs:  "snap_daemon: shared",
  1038  	classic: true,
  1039  	noUser:  true,
  1040  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1041  	error:   `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`,
  1042  }, {
  1043  	sysIDs: "snap_daemon: shared",
  1044  	scVer:  "dead 2.3.3 deadbeef bpf-actlog",
  1045  	error:  `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`,
  1046  }, {
  1047  	sysIDs:  "snap_daemon: shared",
  1048  	classic: true,
  1049  	scVer:   "dead 2.3.3 deadbeef bpf-actlog",
  1050  	error:   `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`,
  1051  }, {
  1052  	sysIDs: "snap_daemon: shared",
  1053  	scVer:  "dead 3.0.0 deadbeef bpf-actlog",
  1054  }, {
  1055  	sysIDs:  "snap_daemon: shared",
  1056  	classic: true,
  1057  	scVer:   "dead 3.0.0 deadbeef bpf-actlog",
  1058  }, {
  1059  	sysIDs: "snap_daemon: shared",
  1060  	scVer:  "dead 2.4.1 deadbeef -",
  1061  	error:  `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`,
  1062  }, {
  1063  	sysIDs:  "snap_daemon: shared",
  1064  	classic: true,
  1065  	scVer:   "dead 2.4.1 deadbeef -",
  1066  	error:   `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`,
  1067  }, {
  1068  	sysIDs:      "snap_daemon: shared",
  1069  	noRangeUser: true,
  1070  	scVer:       "dead 2.4.1 deadbeef bpf-actlog",
  1071  	error:       `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snapd-range-524288-root", group exists and user does not`,
  1072  }, {
  1073  	sysIDs:      "snap_daemon: shared",
  1074  	classic:     true,
  1075  	noRangeUser: true,
  1076  	scVer:       "dead 2.4.1 deadbeef bpf-actlog",
  1077  	error:       `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snapd-range-524288-root", group exists and user does not`,
  1078  }, {
  1079  	sysIDs:  "snap_daemon: shared\n  daemon: shared",
  1080  	classic: true,
  1081  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1082  	error:   `snap "foo" requires unsupported system username "daemon"`,
  1083  },
  1084  }
  1085  
  1086  func (s *checkSnapSuite) TestCheckSnapSystemUsernames(c *C) {
  1087  	for _, test := range systemUsernamesTests {
  1088  		restore := seccomp_compiler.MockCompilerVersionInfo(test.scVer)
  1089  		defer restore()
  1090  
  1091  		restore = release.MockOnClassic(test.classic)
  1092  		defer restore()
  1093  
  1094  		var osutilEnsureUserGroupCalls int
  1095  		if test.noRangeUser {
  1096  			restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error {
  1097  				return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name)
  1098  			})
  1099  		} else if test.noUser {
  1100  			restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error {
  1101  				if name == "snapd-range-524288-root" {
  1102  					return nil
  1103  				}
  1104  				return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name)
  1105  			})
  1106  		} else {
  1107  			restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error {
  1108  				osutilEnsureUserGroupCalls++
  1109  				return nil
  1110  			})
  1111  		}
  1112  		defer restore()
  1113  
  1114  		yaml := fmt.Sprintf("name: foo\nsystem-usernames:\n  %s\n", test.sysIDs)
  1115  
  1116  		info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1117  		c.Assert(err, IsNil)
  1118  
  1119  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1120  			return info, emptyContainer(c), nil
  1121  		}
  1122  		restore = snapstate.MockOpenSnapFile(openSnapFile)
  1123  		defer restore()
  1124  		err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
  1125  		if test.error != "" {
  1126  			c.Check(err, ErrorMatches, test.error)
  1127  			c.Check(osutilEnsureUserGroupCalls, Equals, 0)
  1128  		} else {
  1129  			c.Assert(err, IsNil)
  1130  			// one call for the range user, one for the system user
  1131  			c.Check(osutilEnsureUserGroupCalls, Equals, 2)
  1132  		}
  1133  	}
  1134  }
  1135  
  1136  func (s *checkSnapSuite) TestCheckSnapSystemUsernamesCallsSnapDaemon(c *C) {
  1137  	r := osutil.MockFindGid(func(groupname string) (uint64, error) {
  1138  		if groupname == "snap_daemon" || groupname == "snapd-range-524288-root" {
  1139  			return 0, user.UnknownGroupError(groupname)
  1140  		}
  1141  		return 0, fmt.Errorf("unexpected call to FindGid for %s", groupname)
  1142  	})
  1143  	defer r()
  1144  
  1145  	r = osutil.MockFindUid(func(username string) (uint64, error) {
  1146  		if username == "snap_daemon" || username == "snapd-range-524288-root" {
  1147  			return 0, user.UnknownUserError(username)
  1148  		}
  1149  		return 0, fmt.Errorf("unexpected call to FindUid for %s", username)
  1150  	})
  1151  	defer r()
  1152  
  1153  	falsePath := osutil.LookPathDefault("false", "/bin/false")
  1154  	for _, classic := range []bool{false, true} {
  1155  		restore := release.MockOnClassic(classic)
  1156  		defer restore()
  1157  
  1158  		restore = seccomp_compiler.MockCompilerVersionInfo("dead 2.4.1 deadbeef bpf-actlog")
  1159  		defer restore()
  1160  
  1161  		const yaml = `name: foo
  1162  version: 1.0
  1163  system-usernames:
  1164    snap_daemon: shared`
  1165  
  1166  		info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1167  		c.Assert(err, IsNil)
  1168  
  1169  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1170  			return info, emptyContainer(c), nil
  1171  		}
  1172  		restore = snapstate.MockOpenSnapFile(openSnapFile)
  1173  		defer restore()
  1174  
  1175  		mockGroupAdd := testutil.MockCommand(c, "groupadd", "")
  1176  		defer mockGroupAdd.Restore()
  1177  
  1178  		mockUserAdd := testutil.MockCommand(c, "useradd", "")
  1179  		defer mockUserAdd.Restore()
  1180  
  1181  		err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
  1182  		c.Assert(err, IsNil)
  1183  		if classic {
  1184  			c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{
  1185  				{"groupadd", "--system", "--gid", "524288", "snapd-range-524288-root"},
  1186  				{"groupadd", "--system", "--gid", "584788", "snap_daemon"},
  1187  			})
  1188  			c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{
  1189  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "snapd-range-524288-root"},
  1190  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "584788", "--no-user-group", "--uid", "584788", "snap_daemon"},
  1191  			})
  1192  		} else {
  1193  			c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{
  1194  				{"groupadd", "--system", "--gid", "524288", "--extrausers", "snapd-range-524288-root"},
  1195  				{"groupadd", "--system", "--gid", "584788", "--extrausers", "snap_daemon"},
  1196  			})
  1197  			c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{
  1198  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "--extrausers", "snapd-range-524288-root"},
  1199  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "584788", "--no-user-group", "--uid", "584788", "--extrausers", "snap_daemon"},
  1200  			})
  1201  
  1202  		}
  1203  	}
  1204  }
  1205  
  1206  func (s *checkSnapSuite) TestCheckSnapRemodelKernel(c *C) {
  1207  	reset := release.MockOnClassic(false)
  1208  	defer reset()
  1209  
  1210  	st := state.New(nil)
  1211  	st.Lock()
  1212  	defer st.Unlock()
  1213  
  1214  	si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"}
  1215  	snaptest.MockSnap(c, `
  1216  name: kernel
  1217  type: kernel
  1218  version: 1
  1219  `, si)
  1220  	snapstate.Set(st, "kernel", &snapstate.SnapState{
  1221  		SnapType: "kernel",
  1222  		Active:   true,
  1223  		Sequence: []*snap.SideInfo{si},
  1224  		Current:  si.Revision,
  1225  	})
  1226  
  1227  	const yaml = `name: new-kernel
  1228  type: kernel
  1229  version: 2
  1230  `
  1231  
  1232  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1233  	info.SnapID = "new-kernel-id"
  1234  	c.Assert(err, IsNil)
  1235  
  1236  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1237  		return info, emptyContainer(c), nil
  1238  	}
  1239  	restore := snapstate.MockOpenSnapFile(openSnapFile)
  1240  	defer restore()
  1241  
  1242  	// happy case, the new-kernel matches the model
  1243  	deviceCtx := &snapstatetest.TrivialDeviceContext{
  1244  		Remodeling: true,
  1245  		DeviceModel: MakeModel(map[string]interface{}{
  1246  			"kernel": "new-kernel",
  1247  			"gadget": "gadget",
  1248  		}),
  1249  	}
  1250  
  1251  	st.Unlock()
  1252  	err = snapstate.CheckSnap(st, "snap-path", "new-kernel", nil, nil, snapstate.Flags{}, deviceCtx)
  1253  	st.Lock()
  1254  	c.Check(err, IsNil)
  1255  }
  1256  
  1257  func (s *checkSnapSuite) TestCheckSnapRemodelGadget(c *C) {
  1258  	reset := release.MockOnClassic(false)
  1259  	defer reset()
  1260  
  1261  	st := state.New(nil)
  1262  	st.Lock()
  1263  	defer st.Unlock()
  1264  
  1265  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
  1266  	snaptest.MockSnap(c, `
  1267  name: gadget
  1268  type: gadget
  1269  version: 1
  1270  `, si)
  1271  	snapstate.Set(st, "gadget", &snapstate.SnapState{
  1272  		SnapType: "gadget",
  1273  		Active:   true,
  1274  		Sequence: []*snap.SideInfo{si},
  1275  		Current:  si.Revision,
  1276  	})
  1277  
  1278  	const yaml = `name: new-gadget
  1279  type: gadget
  1280  version: 2
  1281  `
  1282  
  1283  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1284  	info.SnapID = "new-gadget-id"
  1285  	c.Assert(err, IsNil)
  1286  
  1287  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1288  		return info, emptyContainer(c), nil
  1289  	}
  1290  	restore := snapstate.MockOpenSnapFile(openSnapFile)
  1291  	defer restore()
  1292  
  1293  	// happy case, the new-gadget matches the model but we do not
  1294  	// support this yet
  1295  	deviceCtx := &snapstatetest.TrivialDeviceContext{
  1296  		Remodeling: true,
  1297  		DeviceModel: MakeModel(map[string]interface{}{
  1298  			"kernel": "kernel",
  1299  			"gadget": "new-gadget",
  1300  		}),
  1301  	}
  1302  
  1303  	st.Unlock()
  1304  	err = snapstate.CheckSnap(st, "snap-path", "new-gadget", nil, nil, snapstate.Flags{}, deviceCtx)
  1305  	st.Lock()
  1306  	c.Check(err, IsNil)
  1307  }