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