github.com/tompreston/snapd@v0.0.0-20210817193607-954edfcb9611/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 snapID string 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_microk8s: shared", 1036 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1037 snapID: "some-uninteresting-snap-id", 1038 error: `snap "foo" is not allowed to use the system user "snap_microk8s"`, 1039 }, { 1040 snapID: "EaXqgt1lyCaxKaQCU349mlodBkDCXRcg", // microk8s 1041 sysIDs: "snap_microk8s: shared", 1042 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1043 }, { 1044 // missing snap ID, therefore installation allowed 1045 sysIDs: "snap_microk8s:\n scope: shared", 1046 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1047 }, { 1048 sysIDs: "snap_daemon:\n scope: private", 1049 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1050 error: `snap "foo" requires unsupported user scope "private" for this version of snapd`, 1051 }, { 1052 sysIDs: "snap_daemon:\n scope: external", 1053 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1054 error: `snap "foo" requires unsupported user scope "external" for this version of snapd`, 1055 }, { 1056 sysIDs: "snap_daemon:\n scope: other", 1057 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1058 error: `snap "foo" requires unsupported user scope "other"`, 1059 }, { 1060 sysIDs: "snap_daemon: shared", 1061 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1062 classic: true, 1063 }, { 1064 sysIDs: "snap_daemon:\n scope: shared", 1065 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1066 classic: true, 1067 }, { 1068 sysIDs: "snap_daemon:\n scope: private", 1069 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1070 classic: true, 1071 error: `snap "foo" requires unsupported user scope "private" for this version of snapd`, 1072 }, { 1073 sysIDs: "snap_daemon:\n scope: external", 1074 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1075 classic: true, 1076 error: `snap "foo" requires unsupported user scope "external" for this version of snapd`, 1077 }, { 1078 sysIDs: "snap_daemon:\n scope: other", 1079 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1080 classic: true, 1081 error: `snap "foo" requires unsupported user scope "other"`, 1082 }, { 1083 sysIDs: "snap_daemon: shared\n allowed-not: shared", 1084 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1085 error: `snap "foo" requires unsupported system username "allowed-not"`, 1086 }, { 1087 sysIDs: "allowed-not: shared\n snap_daemon: shared", 1088 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1089 classic: true, 1090 error: `snap "foo" requires unsupported system username "allowed-not"`, 1091 }, { 1092 sysIDs: "snap_daemon: shared", 1093 noUser: true, 1094 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1095 error: `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`, 1096 }, { 1097 sysIDs: "snap_daemon: shared", 1098 classic: true, 1099 noUser: true, 1100 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1101 error: `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`, 1102 }, { 1103 sysIDs: "snap_daemon: shared", 1104 scVer: "dead 2.3.3 deadbeef bpf-actlog", 1105 error: `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`, 1106 }, { 1107 sysIDs: "snap_daemon: shared", 1108 classic: true, 1109 scVer: "dead 2.3.3 deadbeef bpf-actlog", 1110 error: `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`, 1111 }, { 1112 sysIDs: "snap_daemon: shared", 1113 scVer: "dead 3.0.0 deadbeef bpf-actlog", 1114 }, { 1115 sysIDs: "snap_daemon: shared", 1116 classic: true, 1117 scVer: "dead 3.0.0 deadbeef bpf-actlog", 1118 }, { 1119 sysIDs: "snap_daemon: shared", 1120 scVer: "dead 2.4.1 deadbeef -", 1121 error: `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`, 1122 }, { 1123 sysIDs: "snap_daemon: shared", 1124 classic: true, 1125 scVer: "dead 2.4.1 deadbeef -", 1126 error: `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`, 1127 }, { 1128 sysIDs: "snap_daemon: shared", 1129 noRangeUser: true, 1130 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1131 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`, 1132 }, { 1133 sysIDs: "snap_daemon: shared", 1134 classic: true, 1135 noRangeUser: true, 1136 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1137 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`, 1138 }, { 1139 sysIDs: "snap_daemon: shared\n daemon: shared", 1140 classic: true, 1141 scVer: "dead 2.4.1 deadbeef bpf-actlog", 1142 error: `snap "foo" requires unsupported system username "daemon"`, 1143 }, 1144 } 1145 1146 func (s *checkSnapSuite) TestCheckSnapSystemUsernames(c *C) { 1147 for _, test := range systemUsernamesTests { 1148 restore := seccomp_compiler.MockCompilerVersionInfo(test.scVer) 1149 defer restore() 1150 1151 restore = release.MockOnClassic(test.classic) 1152 defer restore() 1153 1154 var osutilEnsureUserGroupCalls int 1155 if test.noRangeUser { 1156 restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error { 1157 return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name) 1158 }) 1159 } else if test.noUser { 1160 restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error { 1161 if name == "snapd-range-524288-root" { 1162 return nil 1163 } 1164 return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name) 1165 }) 1166 } else { 1167 restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error { 1168 osutilEnsureUserGroupCalls++ 1169 return nil 1170 }) 1171 } 1172 defer restore() 1173 1174 yaml := fmt.Sprintf("name: foo\nsystem-usernames:\n %s\n", test.sysIDs) 1175 1176 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1177 c.Assert(err, IsNil) 1178 info.SnapID = test.snapID 1179 1180 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1181 return info, emptyContainer(c), nil 1182 } 1183 restore = snapstate.MockOpenSnapFile(openSnapFile) 1184 defer restore() 1185 err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil) 1186 if test.error != "" { 1187 c.Check(err, ErrorMatches, test.error) 1188 c.Check(osutilEnsureUserGroupCalls, Equals, 0) 1189 } else { 1190 c.Assert(err, IsNil) 1191 // one call for the range user, one for the system user 1192 c.Check(osutilEnsureUserGroupCalls, Equals, 2) 1193 } 1194 } 1195 } 1196 1197 func (s *checkSnapSuite) TestCheckSnapSystemUsernamesCallsSnapDaemon(c *C) { 1198 const yaml = `name: foo 1199 version: 1.0 1200 system-usernames: 1201 snap_daemon: shared` 1202 1203 s.testCheckSnapSystemUsernamesCallsCommon(c, "snap_daemon", "584788", yaml) 1204 } 1205 1206 func (s *checkSnapSuite) TestCheckSnapSystemUsernamesCallsSnapMicrok8s(c *C) { 1207 const yaml = `name: microk8s 1208 version: 1.0 1209 system-usernames: 1210 snap_microk8s: shared` 1211 1212 s.testCheckSnapSystemUsernamesCallsCommon(c, "snap_microk8s", "584789", yaml) 1213 } 1214 1215 func (s *checkSnapSuite) testCheckSnapSystemUsernamesCallsCommon(c *C, expectedUser, expectedID, yaml string) { 1216 r := osutil.MockFindGid(func(groupname string) (uint64, error) { 1217 if groupname == expectedUser || groupname == "snapd-range-524288-root" { 1218 return 0, user.UnknownGroupError(groupname) 1219 } 1220 return 0, fmt.Errorf("unexpected call to FindGid for %s", groupname) 1221 }) 1222 defer r() 1223 1224 r = osutil.MockFindUid(func(username string) (uint64, error) { 1225 if username == expectedUser || username == "snapd-range-524288-root" { 1226 return 0, user.UnknownUserError(username) 1227 } 1228 return 0, fmt.Errorf("unexpected call to FindUid for %s", username) 1229 }) 1230 defer r() 1231 1232 falsePath := osutil.LookPathDefault("false", "/bin/false") 1233 for _, classic := range []bool{false, true} { 1234 restore := release.MockOnClassic(classic) 1235 defer restore() 1236 1237 restore = seccomp_compiler.MockCompilerVersionInfo("dead 2.4.1 deadbeef bpf-actlog") 1238 defer restore() 1239 1240 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1241 c.Assert(err, IsNil) 1242 1243 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1244 return info, emptyContainer(c), nil 1245 } 1246 restore = snapstate.MockOpenSnapFile(openSnapFile) 1247 defer restore() 1248 1249 mockGroupAdd := testutil.MockCommand(c, "groupadd", "") 1250 defer mockGroupAdd.Restore() 1251 1252 mockUserAdd := testutil.MockCommand(c, "useradd", "") 1253 defer mockUserAdd.Restore() 1254 1255 err = snapstate.CheckSnap(s.st, "snap-path", info.SnapName(), nil, nil, snapstate.Flags{}, nil) 1256 c.Assert(err, IsNil) 1257 if classic { 1258 c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{ 1259 {"groupadd", "--system", "--gid", "524288", "snapd-range-524288-root"}, 1260 {"groupadd", "--system", "--gid", expectedID, expectedUser}, 1261 }) 1262 c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{ 1263 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "snapd-range-524288-root"}, 1264 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", expectedID, "--no-user-group", "--uid", expectedID, expectedUser}, 1265 }) 1266 } else { 1267 c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{ 1268 {"groupadd", "--system", "--gid", "524288", "--extrausers", "snapd-range-524288-root"}, 1269 {"groupadd", "--system", "--gid", expectedID, "--extrausers", expectedUser}, 1270 }) 1271 c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{ 1272 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "--extrausers", "snapd-range-524288-root"}, 1273 {"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", expectedID, "--no-user-group", "--uid", expectedID, "--extrausers", expectedUser}, 1274 }) 1275 1276 } 1277 } 1278 } 1279 1280 func (s *checkSnapSuite) TestCheckSnapRemodelKernel(c *C) { 1281 reset := release.MockOnClassic(false) 1282 defer reset() 1283 1284 st := state.New(nil) 1285 st.Lock() 1286 defer st.Unlock() 1287 1288 si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"} 1289 snaptest.MockSnap(c, ` 1290 name: kernel 1291 type: kernel 1292 version: 1 1293 `, si) 1294 snapstate.Set(st, "kernel", &snapstate.SnapState{ 1295 SnapType: "kernel", 1296 Active: true, 1297 Sequence: []*snap.SideInfo{si}, 1298 Current: si.Revision, 1299 }) 1300 1301 const yaml = `name: new-kernel 1302 type: kernel 1303 version: 2 1304 ` 1305 1306 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1307 info.SnapID = "new-kernel-id" 1308 c.Assert(err, IsNil) 1309 1310 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1311 return info, emptyContainer(c), nil 1312 } 1313 restore := snapstate.MockOpenSnapFile(openSnapFile) 1314 defer restore() 1315 1316 // happy case, the new-kernel matches the model 1317 deviceCtx := &snapstatetest.TrivialDeviceContext{ 1318 Remodeling: true, 1319 DeviceModel: MakeModel(map[string]interface{}{ 1320 "kernel": "new-kernel", 1321 "gadget": "gadget", 1322 }), 1323 } 1324 1325 st.Unlock() 1326 err = snapstate.CheckSnap(st, "snap-path", "new-kernel", nil, nil, snapstate.Flags{}, deviceCtx) 1327 st.Lock() 1328 c.Check(err, IsNil) 1329 } 1330 1331 func (s *checkSnapSuite) TestCheckSnapRemodelGadget(c *C) { 1332 reset := release.MockOnClassic(false) 1333 defer reset() 1334 1335 st := state.New(nil) 1336 st.Lock() 1337 defer st.Unlock() 1338 1339 si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"} 1340 snaptest.MockSnap(c, ` 1341 name: gadget 1342 type: gadget 1343 version: 1 1344 `, si) 1345 snapstate.Set(st, "gadget", &snapstate.SnapState{ 1346 SnapType: "gadget", 1347 Active: true, 1348 Sequence: []*snap.SideInfo{si}, 1349 Current: si.Revision, 1350 }) 1351 1352 const yaml = `name: new-gadget 1353 type: gadget 1354 version: 2 1355 ` 1356 1357 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 1358 info.SnapID = "new-gadget-id" 1359 c.Assert(err, IsNil) 1360 1361 var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { 1362 return info, emptyContainer(c), nil 1363 } 1364 restore := snapstate.MockOpenSnapFile(openSnapFile) 1365 defer restore() 1366 1367 // happy case, the new-gadget matches the model but we do not 1368 // support this yet 1369 deviceCtx := &snapstatetest.TrivialDeviceContext{ 1370 Remodeling: true, 1371 DeviceModel: MakeModel(map[string]interface{}{ 1372 "kernel": "kernel", 1373 "gadget": "new-gadget", 1374 }), 1375 } 1376 1377 st.Unlock() 1378 err = snapstate.CheckSnap(st, "snap-path", "new-gadget", nil, nil, snapstate.Flags{}, deviceCtx) 1379 st.Lock() 1380 c.Check(err, IsNil) 1381 }