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