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