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