github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/overlord/snapstate/check_snap.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-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
    21  
    22  import (
    23  	"fmt"
    24  	"regexp"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"github.com/snapcore/snapd/arch"
    29  	"github.com/snapcore/snapd/asserts"
    30  	"github.com/snapcore/snapd/logger"
    31  	"github.com/snapcore/snapd/osutil"
    32  	"github.com/snapcore/snapd/overlord/snapstate/backend"
    33  	"github.com/snapcore/snapd/overlord/state"
    34  	"github.com/snapcore/snapd/release"
    35  	seccomp_compiler "github.com/snapcore/snapd/sandbox/seccomp"
    36  	"github.com/snapcore/snapd/snap"
    37  	"github.com/snapcore/snapd/snapdtool"
    38  )
    39  
    40  // featureSet contains the flag values that can be listed in assumes entries
    41  // that this ubuntu-core actually provides.
    42  var featureSet = map[string]bool{
    43  	// Support for common data directory across revisions of a snap.
    44  	"common-data-dir": true,
    45  	// Support for the "Environment:" feature in snap.yaml
    46  	"snap-env": true,
    47  	// Support for the "command-chain" feature for apps and hooks in snap.yaml
    48  	"command-chain": true,
    49  	// Support for "kernel-assets" in gadget.yaml. I.e. having volume
    50  	// content of the style $kernel:ref`
    51  	"kernel-assets": true,
    52  }
    53  
    54  // supportedSystemUsernames for now contains the hardcoded list of system
    55  // users (and implied system group of same name) that snaps may specify. This
    56  // will eventually be moved out of here into the store.
    57  //
    58  // Since the snap is mounted read-only and to avoid problems associated with
    59  // different systems using different uids and gids for the same user name and
    60  // group name, snapd will create system-usernames where 'scope' is not
    61  // 'external' (currently snapd only supports 'scope: shared') with the
    62  // following characteristics:
    63  //
    64  // - uid and gid shall match for the specified system-username
    65  // - a snapd-allocated [ug]id for a user/group name shall never change
    66  // - snapd should avoid [ug]ids that are known to overlap with uid ranges of
    67  //   common use cases and user namespace container managers so that DAC and
    68  //   AppArmor owner match work as intended.
    69  // - [ug]id shall be < 2^31 to avoid (at least) broken devpts kernel code
    70  // - [ug]id shall be >= 524288 (0x00080000) to give plenty of room for large
    71  //   sites, default uid/gid ranges for docker (231072-296608), LXD installs
    72  //   that setup a default /etc/sub{uid,gid} (100000-165536) and podman whose
    73  //   tutorials reference setting up a specific default user and range
    74  //   (100000-165536)
    75  // - [ug]id shall be < 1,000,000 and > 1,001,000,000 (ie, 1,000,000 subordinate
    76  //   uid with 1,000,000,000 range) to avoid overlapping with LXD's minimum and
    77  //   maximum id ranges. LXD allows for any id range >= 65536 and doesn't
    78  //   perform any [ug]id overlap detection with current users
    79  // - [ug]ids assigned by snapd initially will fall within a 65536 (2^16) range
    80  //   (see below) where the first [ug]id in the range has the 16 lower bits all
    81  //   set to zero. This allows snapd to conveniently be bitwise aligned, follows
    82  //   sensible conventions (see https://systemd.io/UIDS-GIDS.html) but also
    83  //   potentially discoverable by systemd-nspawn (it assigns a different 65536
    84  //   range to each container. Its allocation algorithm is not sequential and
    85  //   may choose anything within its range that isn't already allocated. It's
    86  //   detection algorithm includes (effectively) performing a getpwent()
    87  //   operation on CANDIDATE_UID & 0XFFFF0000 and selecting another range if it
    88  //   is assigned).
    89  //
    90  // What [ug]id range(s) should snapd use?
    91  //
    92  // While snapd does not employ user namespaces, it will operate on systems with
    93  // container managers that do and will assign from a range of [ug]ids. It is
    94  // desirable that snapd assigns [ug]ids that minimally conflict with the system
    95  // and other software (potential conflicts with admin-assigned ranges in
    96  // /etc/subuid and /etc/subgid cannot be avoided, but can be documented as well
    97  // as detected/logged). Overlapping with container managers is non-fatal for
    98  // snapd and the container, but introduces the possibility that a uid in the
    99  // container matches a uid a snap is using, which is undesirable in terms of
   100  // security (eg, DoS via ulimit, same ownership of files between container and
   101  // snap (even if the other's files are otherwise inaccessible), etc).
   102  //
   103  // snapd shall assign [ug]ids from range(s) of 65536 where the lowest value in
   104  // the range has the 16 lower bits all set to zero (initially just one range,
   105  // but snapd can add more as needed).
   106  //
   107  // To avoid [ug]id overlaps, snapd shall only assign [ug]ids >= 524288
   108  // (0x00080000) and <= 983040 (0x000F0000, ie the first 65536 range under LXD's
   109  // minimum where the lower 16 bits are all zeroes). While [ug]ids >= 1001062400
   110  // (0x3BAB0000, the first 65536 range above LXD's maximum where the lower 16
   111  // bits are all zeroes) would also avoid overlap, considering nested containers
   112  // (eg, LXD snap runs a container that runs a container that runs snapd),
   113  // choosing >= 1001062400 would mean that the admin would need to increase the
   114  // LXD id range for these containers for snapd to be allowed to create its
   115  // [ug]ids in the deeply nested containers. The requirements would both be an
   116  // administrative burden and artificially limit the number of deeply nested
   117  // containers the host could have.
   118  //
   119  // Looking at the LSB and distribution defaults for login.defs, we can observe
   120  // uids and gids in the system's initial 65536 range (ie, 0-65536):
   121  //
   122  // - 0-99        LSB-suggested statically assigned range (eg, root, daemon,
   123  //               etc)
   124  // - 0           mandatory 'root' user
   125  // - 100-499     LSB-suggested dynamically assigned range for system users
   126  //               (distributions often prefer a higher range, see below)
   127  // - 500-999     typical distribution default for dynamically assigned range
   128  //               for system users (some distributions use a smaller
   129  //               SYS_[GU]ID_MIN)
   130  // - 1000-60000  typical distribution default for dynamically assigned range
   131  //               for regular users
   132  // - 65535 (-1)  should not be assigned since '-1' might be evaluated as this
   133  //               with set[ug]id* and chown families of functions
   134  // - 65534 (-2)  nobody/nogroup user for NFS/etc [ug]id anonymous squashing
   135  // - 65519-65533 systemd recommended reserved range for site-local anonymous
   136  //               additions, etc
   137  //
   138  // To facilitate potential future use cases within the 65536 range snapd will
   139  // assign from, snapd will only assign from the following subset of ranges
   140  // relative to the range minimum (ie, its 'base' which has the lower 16 bits
   141  // all set to zero):
   142  //
   143  // - 60500-60999 'scope: shared' system-usernames
   144  // - 61000-65519 'scope: private' system-usernames
   145  //
   146  // Since the first [ug]id range must be >= 524288 and <= 983040 (see above) and
   147  // following the above guide for system-usernames [ug]ids within this 65536
   148  // range, the lowest 'scope: shared' user in this range is 584788 (0x0008EC54).
   149  //
   150  // Since this number is within systemd-nspawn's range of 524288-1879048191
   151  // (0x00080000-0x6FFFFFFF), the number's lower 16 bits are not all zeroes so
   152  // systemd-nspawn won't detect this allocation and could potentially assign the
   153  // 65536 range starting at 0x00080000 to a container. snapd will therefore also
   154  // create the 'snapd-range-524288-root' user and group with [ug]id 524288 to
   155  // work within systemd-nspawn's collision detection. This user/group will not
   156  // be assigned to snaps at this time.
   157  //
   158  // In short (phew!), use the following:
   159  //
   160  // $ snappy-debug.id-range 524288 # 0x00080000
   161  // Host range:              524288-589823 (00080000-0008ffff; 0-65535)
   162  // LSB static range:        524288-524387 (00080000-00080063; 0-99)
   163  // Useradd system range:    524788-525287 (000801f4-000803e7; 500-999)
   164  // Useradd regular range:   525288-584288 (000803e8-0008ea60; 1000-60000)
   165  // Snapd system range:      584788-585287 (0008ec54-0008ee47; 60500-60999)
   166  // Snapd private range:     585288-589807 (0008ee48-0008ffef; 61000-65519)
   167  //
   168  // Snapd is of course free to add more ranges (eg, 589824 (0x00090000)) with
   169  // new snapd-range-<base>-root users, or to allocate differently within its
   170  // 65536 range in the future (sequentially assigned [ug]ids are not required),
   171  // but for now start very regimented to avoid as many problems as possible.
   172  //
   173  // References:
   174  // https://forum.snapcraft.io/t/multiple-users-and-groups-in-snaps/
   175  // https://systemd.io/UIDS-GIDS.html
   176  // https://docs.docker.com/engine/security/userns-remap/
   177  // https://github.com/lxc/lxd/blob/master/doc/userns-idmap.md
   178  var supportedSystemUsernames = map[string]uint32{
   179  	"snap_daemon": 584788,
   180  }
   181  
   182  func checkAssumes(si *snap.Info) error {
   183  	missing := ([]string)(nil)
   184  	for _, flag := range si.Assumes {
   185  		if strings.HasPrefix(flag, "snapd") && checkVersion(flag[5:]) {
   186  			continue
   187  		}
   188  		if !featureSet[flag] {
   189  			missing = append(missing, flag)
   190  		}
   191  	}
   192  	if len(missing) > 0 {
   193  		hint := "try to refresh the core or snapd snaps"
   194  		if release.OnClassic {
   195  			hint = "try to update snapd and refresh the core snap"
   196  		}
   197  		return fmt.Errorf("snap %q assumes unsupported features: %s (%s)", si.InstanceName(), strings.Join(missing, ", "), hint)
   198  	}
   199  	return nil
   200  }
   201  
   202  // regular expression which matches a version expressed as groups of digits
   203  // separated with dots, with optional non-numbers afterwards
   204  var versionExp = regexp.MustCompile(`^(?:[1-9][0-9]*)(?:\.(?:[0-9]+))*`)
   205  
   206  func checkVersion(version string) bool {
   207  	// double check that the input looks like a snapd version
   208  	reqVersionNumMatch := versionExp.FindStringSubmatch(version)
   209  	if reqVersionNumMatch == nil {
   210  		return false
   211  	}
   212  	// this check ensures that no one can use an assumes like snapd2.48.3~pre2
   213  	// or snapd2.48.5+20.10, as modifiers past the version number are not meant
   214  	// to be relied on for snaps via assumes, however the check against the real
   215  	// snapd version number below allows such non-numeric modifiers since real
   216  	// snapds do have versions like that (for example debian pkg of snapd)
   217  	if reqVersionNumMatch[0] != version {
   218  		return false
   219  	}
   220  
   221  	req := strings.Split(reqVersionNumMatch[0], ".")
   222  
   223  	if snapdtool.Version == "unknown" {
   224  		return true // Development tree.
   225  	}
   226  
   227  	// We could (should?) use strutil.VersionCompare here and simplify
   228  	// this code (see PR#7344). However this would change current
   229  	// behavior, i.e. "2.41~pre1" would *not* match [snapd2.41] anymore
   230  	// (which the code below does).
   231  	curVersionNumMatch := versionExp.FindStringSubmatch(snapdtool.Version)
   232  	if curVersionNumMatch == nil {
   233  		return false
   234  	}
   235  	cur := strings.Split(curVersionNumMatch[0], ".")
   236  
   237  	for i := range req {
   238  		if i == len(cur) {
   239  			// we hit the end of the elements of the current version number and have
   240  			// more required version numbers left, so this doesn't match, if the
   241  			// previous element was higher we would have broken out already, so the
   242  			// only case left here is where we have version requirements that are
   243  			// not met
   244  			return false
   245  		}
   246  		reqN, err1 := strconv.Atoi(req[i])
   247  		curN, err2 := strconv.Atoi(cur[i])
   248  		if err1 != nil || err2 != nil {
   249  			panic("internal error: version regexp is broken")
   250  		}
   251  		if curN != reqN {
   252  			return curN > reqN
   253  		}
   254  	}
   255  
   256  	return true
   257  }
   258  
   259  type SnapNeedsDevModeError struct {
   260  	Snap string
   261  }
   262  
   263  func (e *SnapNeedsDevModeError) Error() string {
   264  	return fmt.Sprintf("snap %q requires devmode or confinement override", e.Snap)
   265  }
   266  
   267  type SnapNeedsClassicError struct {
   268  	Snap string
   269  }
   270  
   271  func (e *SnapNeedsClassicError) Error() string {
   272  	return fmt.Sprintf("snap %q requires classic confinement", e.Snap)
   273  }
   274  
   275  type SnapNeedsClassicSystemError struct {
   276  	Snap string
   277  }
   278  
   279  func (e *SnapNeedsClassicSystemError) Error() string {
   280  	return fmt.Sprintf("snap %q requires classic confinement which is only available on classic systems", e.Snap)
   281  }
   282  
   283  type SnapNotClassicError struct {
   284  	Snap string
   285  }
   286  
   287  func (e *SnapNotClassicError) Error() string {
   288  	return fmt.Sprintf("snap %q is not a classic confined snap", e.Snap)
   289  }
   290  
   291  // determine whether the flags (and system overrides thereof) are
   292  // compatible with the given *snap.Info
   293  func validateFlagsForInfo(info *snap.Info, snapst *SnapState, flags Flags) error {
   294  	if flags.Classic && !info.NeedsClassic() {
   295  		return &SnapNotClassicError{Snap: info.InstanceName()}
   296  	}
   297  
   298  	switch c := info.Confinement; c {
   299  	case snap.StrictConfinement, "":
   300  		// strict is always fine
   301  		return nil
   302  	case snap.DevModeConfinement:
   303  		// --devmode needs to be specified every time (==> ignore snapst)
   304  		if flags.DevModeAllowed() {
   305  			return nil
   306  		}
   307  		return &SnapNeedsDevModeError{
   308  			Snap: info.InstanceName(),
   309  		}
   310  	case snap.ClassicConfinement:
   311  		if !release.OnClassic {
   312  			return &SnapNeedsClassicSystemError{Snap: info.InstanceName()}
   313  		}
   314  
   315  		if flags.Classic {
   316  			return nil
   317  		}
   318  
   319  		if snapst != nil && snapst.Flags.Classic {
   320  			return nil
   321  		}
   322  
   323  		return &SnapNeedsClassicError{
   324  			Snap: info.InstanceName(),
   325  		}
   326  	default:
   327  		return fmt.Errorf("unknown confinement %q", c)
   328  	}
   329  }
   330  
   331  // do a reasonably lightweight check that a snap described by Info,
   332  // with the given SnapState and the user-specified Flags should be
   333  // installable on the current system.
   334  func validateInfoAndFlags(info *snap.Info, snapst *SnapState, flags Flags) error {
   335  	if err := validateFlagsForInfo(info, snapst, flags); err != nil {
   336  		return err
   337  	}
   338  
   339  	// verify we have a valid architecture
   340  	if !arch.IsSupportedArchitecture(info.Architectures) {
   341  		return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", info.InstanceName(), strings.Join(info.Architectures, ", "), arch.DpkgArchitecture())
   342  	}
   343  
   344  	// check assumes
   345  	if err := checkAssumes(info); err != nil {
   346  		return err
   347  	}
   348  
   349  	// check and create system-usernames
   350  	if err := checkAndCreateSystemUsernames(info); err != nil {
   351  		return err
   352  	}
   353  
   354  	return nil
   355  }
   356  
   357  var openSnapFile = backend.OpenSnapFile
   358  
   359  func validateContainer(c snap.Container, s *snap.Info, logf func(format string, v ...interface{})) error {
   360  	err := snap.ValidateContainer(c, s, logf)
   361  	if err == nil {
   362  		return nil
   363  	}
   364  	return fmt.Errorf("%v; contact developer", err)
   365  }
   366  
   367  // checkSnap ensures that the snap can be installed.
   368  func checkSnap(st *state.State, snapFilePath, instanceName string, si *snap.SideInfo, curInfo *snap.Info, flags Flags, deviceCtx DeviceContext) error {
   369  	// This assumes that the snap was already verified or --dangerous was used.
   370  
   371  	s, c, err := openSnapFile(snapFilePath, si)
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	if err := validateInfoAndFlags(s, nil, flags); err != nil {
   377  		return err
   378  	}
   379  
   380  	if err := validateContainer(c, s, logger.Noticef); err != nil {
   381  		return err
   382  	}
   383  
   384  	snapName, instanceKey := snap.SplitInstanceName(instanceName)
   385  	// update instance key to what was requested
   386  	s.InstanceKey = instanceKey
   387  
   388  	st.Lock()
   389  	defer st.Unlock()
   390  
   391  	// allow registered checks to run first as they may produce more
   392  	// precise errors
   393  	for _, check := range checkSnapCallbacks {
   394  		err := check(st, s, curInfo, c, flags, deviceCtx)
   395  		if err != nil {
   396  			return err
   397  		}
   398  	}
   399  
   400  	if snapName != s.SnapName() {
   401  		return fmt.Errorf("cannot install snap %q using instance name %q", s.SnapName(), instanceName)
   402  	}
   403  
   404  	return nil
   405  }
   406  
   407  // CheckSnapCallback defines callbacks for checking a snap for installation or refresh.
   408  type CheckSnapCallback func(st *state.State, snap, curSnap *snap.Info, snapf snap.Container, flags Flags, deviceCtx DeviceContext) error
   409  
   410  var checkSnapCallbacks []CheckSnapCallback
   411  
   412  // AddCheckSnapCallback installs a callback to check a snap for installation or refresh.
   413  func AddCheckSnapCallback(check CheckSnapCallback) {
   414  	checkSnapCallbacks = append(checkSnapCallbacks, check)
   415  }
   416  
   417  func MockCheckSnapCallbacks(checks []CheckSnapCallback) (restore func()) {
   418  	prev := checkSnapCallbacks
   419  	checkSnapCallbacks = checks
   420  	return func() {
   421  		checkSnapCallbacks = prev
   422  	}
   423  }
   424  
   425  func checkSnapdName(st *state.State, snapInfo, curInfo *snap.Info, _ snap.Container, flags Flags, deviceCtx DeviceContext) error {
   426  	if snapInfo.Type() != snap.TypeSnapd {
   427  		// not a relevant check
   428  		return nil
   429  	}
   430  	if snapInfo.InstanceName() != "snapd" {
   431  		return fmt.Errorf(`cannot install snap %q of type "snapd" with a name other than "snapd"`, snapInfo.InstanceName())
   432  	}
   433  
   434  	return nil
   435  }
   436  
   437  func checkCoreName(st *state.State, snapInfo, curInfo *snap.Info, _ snap.Container, flags Flags, deviceCtx DeviceContext) error {
   438  	if snapInfo.Type() != snap.TypeOS {
   439  		// not a relevant check
   440  		return nil
   441  	}
   442  	if curInfo != nil {
   443  		// already one of these installed
   444  		return nil
   445  	}
   446  	core, err := coreInfo(st)
   447  	if err == state.ErrNoState {
   448  		return nil
   449  	}
   450  	if err != nil {
   451  		return err
   452  	}
   453  
   454  	// Allow installing "core" even if "ubuntu-core" is already
   455  	// installed. Ideally we should only allow this if we know
   456  	// this install is part of the ubuntu-core->core transition
   457  	// (e.g. via a flag) because if this happens outside of this
   458  	// transition we will end up with not connected interface
   459  	// connections in the "core" snap. But the transition will
   460  	// kick in automatically quickly so an extra flag is overkill.
   461  	if snapInfo.InstanceName() == "core" && core.InstanceName() == "ubuntu-core" {
   462  		return nil
   463  	}
   464  
   465  	// but generally do not allow to have two cores installed
   466  	if core.InstanceName() != snapInfo.InstanceName() {
   467  		return fmt.Errorf("cannot install core snap %q when core snap %q is already present", snapInfo.InstanceName(), core.InstanceName())
   468  	}
   469  
   470  	return nil
   471  }
   472  
   473  func checkGadgetOrKernel(st *state.State, snapInfo, curInfo *snap.Info, snapf snap.Container, flags Flags, deviceCtx DeviceContext) error {
   474  	typ := snapInfo.Type()
   475  	kind := ""
   476  	var whichName func(*asserts.Model) string
   477  	switch typ {
   478  	case snap.TypeGadget:
   479  		kind = "gadget"
   480  		whichName = (*asserts.Model).Gadget
   481  	case snap.TypeKernel:
   482  		kind = "kernel"
   483  		whichName = (*asserts.Model).Kernel
   484  	default:
   485  		// not a relevant check
   486  		return nil
   487  	}
   488  
   489  	ok, err := HasSnapOfType(st, typ)
   490  	if err != nil {
   491  		return fmt.Errorf("cannot detect original %s snap: %v", kind, err)
   492  	}
   493  	// in firstboot we have no gadget/kernel yet - that is ok
   494  	// first install rules are in devicestate!
   495  	if !ok {
   496  		return nil
   497  	}
   498  
   499  	currentSnap, err := infoForDeviceSnap(st, deviceCtx, kind, whichName)
   500  	if err == state.ErrNoState {
   501  		// check if we are in the remodel case
   502  		if deviceCtx != nil && deviceCtx.ForRemodeling() {
   503  			if whichName(deviceCtx.Model()) == snapInfo.InstanceName() {
   504  				return nil
   505  			}
   506  		}
   507  		return fmt.Errorf("internal error: no state for %s snap %q", kind, snapInfo.InstanceName())
   508  	}
   509  	if err != nil {
   510  		return fmt.Errorf("cannot find original %s snap: %v", kind, err)
   511  	}
   512  
   513  	if currentSnap.SnapID != "" && snapInfo.SnapID == "" {
   514  		return fmt.Errorf("cannot replace signed %s snap with an unasserted one", kind)
   515  	}
   516  
   517  	if currentSnap.SnapID != "" && snapInfo.SnapID != "" {
   518  		if currentSnap.SnapID == snapInfo.SnapID {
   519  			// same snap
   520  			return nil
   521  		}
   522  		return fmt.Errorf("cannot replace %s snap with a different one", kind)
   523  	}
   524  
   525  	if currentSnap.InstanceName() != snapInfo.InstanceName() {
   526  		return fmt.Errorf("cannot replace %s snap with a different one", kind)
   527  	}
   528  
   529  	return nil
   530  }
   531  
   532  func checkBases(st *state.State, snapInfo, curInfo *snap.Info, _ snap.Container, flags Flags, deviceCtx DeviceContext) error {
   533  	// check if this is relevant
   534  	if snapInfo.Type() != snap.TypeApp && snapInfo.Type() != snap.TypeGadget {
   535  		return nil
   536  	}
   537  	if snapInfo.Base == "" {
   538  		return nil
   539  	}
   540  	if snapInfo.Base == "none" {
   541  		return nil
   542  	}
   543  
   544  	snapStates, err := All(st)
   545  	if err != nil {
   546  		return err
   547  	}
   548  	for otherSnap, snapst := range snapStates {
   549  		typ, err := snapst.Type()
   550  		if err != nil {
   551  			return err
   552  		}
   553  		if typ == snap.TypeBase && otherSnap == snapInfo.Base {
   554  			return nil
   555  		}
   556  		// core can be used instead for core16
   557  		if snapInfo.Base == "core16" && otherSnap == "core" {
   558  			return nil
   559  		}
   560  	}
   561  
   562  	return fmt.Errorf("cannot find required base %q", snapInfo.Base)
   563  }
   564  
   565  func checkEpochs(_ *state.State, snapInfo, curInfo *snap.Info, _ snap.Container, _ Flags, deviceCtx DeviceContext) error {
   566  	if curInfo == nil {
   567  		return nil
   568  	}
   569  	if snapInfo.Epoch.CanRead(curInfo.Epoch) {
   570  		return nil
   571  	}
   572  	desc := "local snap"
   573  	if snapInfo.SideInfo.Revision.Store() {
   574  		desc = fmt.Sprintf("new revision %s", snapInfo.SideInfo.Revision)
   575  	}
   576  
   577  	return fmt.Errorf("cannot refresh %q to %s with epoch %s, because it can't read the current epoch of %s", snapInfo.InstanceName(), desc, snapInfo.Epoch, curInfo.Epoch)
   578  }
   579  
   580  // check that the snap installed in the system (via snapst) can be
   581  // upgraded to info (i.e. that info's epoch can read sanpst's epoch)
   582  func earlyEpochCheck(info *snap.Info, snapst *SnapState) error {
   583  	if snapst == nil {
   584  		// no snapst, no problem
   585  		return nil
   586  	}
   587  	cur, err := snapst.CurrentInfo()
   588  	if err != nil {
   589  		if err == ErrNoCurrent {
   590  			// refreshing a disabled snap (maybe via InstallPath)
   591  			return nil
   592  		}
   593  		return err
   594  	}
   595  
   596  	return checkEpochs(nil, info, cur, nil, Flags{}, nil)
   597  }
   598  
   599  func earlyChecks(st *state.State, snapst *SnapState, update *snap.Info, flags Flags) (Flags, error) {
   600  	flags, err := ensureInstallPreconditions(st, update, flags, snapst)
   601  	if err != nil {
   602  		return flags, err
   603  	}
   604  
   605  	if err := earlyEpochCheck(update, snapst); err != nil {
   606  		return flags, err
   607  	}
   608  	return flags, nil
   609  }
   610  
   611  // check that the listed system users are valid
   612  var osutilEnsureUserGroup = osutil.EnsureUserGroup
   613  
   614  func validateSystemUsernames(si *snap.Info) error {
   615  	for _, user := range si.SystemUsernames {
   616  		if _, ok := supportedSystemUsernames[user.Name]; !ok {
   617  			return fmt.Errorf(`snap %q requires unsupported system username "%s"`, si.InstanceName(), user.Name)
   618  		}
   619  
   620  		switch user.Scope {
   621  		case "shared":
   622  			// this is supported
   623  			continue
   624  		case "private", "external":
   625  			// not supported yet
   626  			return fmt.Errorf(`snap %q requires unsupported user scope "%s" for this version of snapd`, si.InstanceName(), user.Scope)
   627  		default:
   628  			return fmt.Errorf(`snap %q requires unsupported user scope "%s"`, si.InstanceName(), user.Scope)
   629  		}
   630  	}
   631  	return nil
   632  }
   633  
   634  func checkAndCreateSystemUsernames(si *snap.Info) error {
   635  	// No need to check support if no system-usernames
   636  	if len(si.SystemUsernames) == 0 {
   637  		return nil
   638  	}
   639  
   640  	// Run /.../snap-seccomp version-info
   641  	vi, err := seccomp_compiler.CompilerVersionInfo(snapdtool.InternalToolPath)
   642  	if err != nil {
   643  		return fmt.Errorf("cannot obtain seccomp compiler information: %v", err)
   644  	}
   645  
   646  	// If the system doesn't support robust argument filtering then we
   647  	// can't support system-usernames
   648  	if err := vi.SupportsRobustArgumentFiltering(); err != nil {
   649  		if re, ok := err.(*seccomp_compiler.BuildTimeRequirementError); ok {
   650  			return fmt.Errorf("snap %q system usernames require a snapd built against %s", si.InstanceName(), re.RequirementsString())
   651  		}
   652  		return err
   653  	}
   654  
   655  	// first validate
   656  	if err := validateSystemUsernames(si); err != nil {
   657  		return err
   658  	}
   659  
   660  	// then create
   661  	// TODO: move user creation to a more appropriate place like "link-snap"
   662  	extrausers := !release.OnClassic
   663  	for _, user := range si.SystemUsernames {
   664  		id := supportedSystemUsernames[user.Name]
   665  		switch user.Scope {
   666  		case "shared":
   667  			// Create the snapd-range-<base>-root user and group so
   668  			// systemd-nspawn can avoid our range. Our ranges will always
   669  			// be in 65536 chunks, so mask off the lower bits to obtain our
   670  			// base (see above)
   671  			rangeStart := id & 0xFFFF0000
   672  			rangeName := fmt.Sprintf("snapd-range-%d-root", rangeStart)
   673  			if err := osutilEnsureUserGroup(rangeName, rangeStart, extrausers); err != nil {
   674  				return fmt.Errorf(`cannot ensure users for snap %q required system username "%s": %v`, si.InstanceName(), user.Name, err)
   675  			}
   676  
   677  			// Create the requested user and group
   678  			if err := osutilEnsureUserGroup(user.Name, id, extrausers); err != nil {
   679  				return fmt.Errorf(`cannot ensure users for snap %q required system username "%s": %v`, si.InstanceName(), user.Name, err)
   680  			}
   681  		}
   682  	}
   683  	return nil
   684  }
   685  
   686  func init() {
   687  	AddCheckSnapCallback(checkCoreName)
   688  	AddCheckSnapCallback(checkSnapdName)
   689  	AddCheckSnapCallback(checkGadgetOrKernel)
   690  	AddCheckSnapCallback(checkBases)
   691  	AddCheckSnapCallback(checkEpochs)
   692  }