github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/boot/bootchain_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 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 boot_test 21 22 import ( 23 "encoding/json" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "sort" 28 29 . "gopkg.in/check.v1" 30 31 "github.com/snapcore/snapd/boot" 32 "github.com/snapcore/snapd/bootloader" 33 "github.com/snapcore/snapd/dirs" 34 "github.com/snapcore/snapd/secboot" 35 "github.com/snapcore/snapd/testutil" 36 ) 37 38 type bootchainSuite struct { 39 testutil.BaseTest 40 41 rootDir string 42 } 43 44 var _ = Suite(&bootchainSuite{}) 45 46 func (s *bootchainSuite) SetUpTest(c *C) { 47 s.BaseTest.SetUpTest(c) 48 s.rootDir = c.MkDir() 49 s.AddCleanup(func() { dirs.SetRootDir("/") }) 50 dirs.SetRootDir(s.rootDir) 51 52 c.Assert(os.MkdirAll(filepath.Join(dirs.SnapBootAssetsDir), 0755), IsNil) 53 } 54 55 func (s *bootchainSuite) TestBootAssetsSort(c *C) { 56 // by role 57 d := []boot.BootAsset{ 58 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"b", "c"}}, 59 {Role: bootloader.RoleRecovery, Name: "1ist", Hashes: []string{"b", "c"}}, 60 } 61 sort.Sort(boot.ByBootAssetOrder(d)) 62 c.Check(d, DeepEquals, []boot.BootAsset{ 63 {Role: bootloader.RoleRecovery, Name: "1ist", Hashes: []string{"b", "c"}}, 64 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"b", "c"}}, 65 }) 66 67 // by name 68 d = []boot.BootAsset{ 69 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"d", "e"}}, 70 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d", "e"}}, 71 } 72 sort.Sort(boot.ByBootAssetOrder(d)) 73 c.Check(d, DeepEquals, []boot.BootAsset{ 74 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d", "e"}}, 75 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"d", "e"}}, 76 }) 77 78 // by hash list length 79 d = []boot.BootAsset{ 80 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"a", "f"}}, 81 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"d"}}, 82 } 83 sort.Sort(boot.ByBootAssetOrder(d)) 84 c.Check(d, DeepEquals, []boot.BootAsset{ 85 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"d"}}, 86 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"a", "f"}}, 87 }) 88 89 // hash list entries 90 d = []boot.BootAsset{ 91 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"b", "d"}}, 92 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"b", "c"}}, 93 } 94 sort.Sort(boot.ByBootAssetOrder(d)) 95 c.Check(d, DeepEquals, []boot.BootAsset{ 96 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"b", "c"}}, 97 {Role: bootloader.RoleRunMode, Name: "1ist", Hashes: []string{"b", "d"}}, 98 }) 99 100 d = []boot.BootAsset{ 101 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 102 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b"}}, 103 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 104 {Role: bootloader.RoleRunMode, Name: "1oader", Hashes: []string{"d", "e"}}, 105 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d", "e"}}, 106 {Role: bootloader.RoleRunMode, Name: "0oader", Hashes: []string{"x", "z"}}, 107 } 108 sort.Sort(boot.ByBootAssetOrder(d)) 109 c.Check(d, DeepEquals, []boot.BootAsset{ 110 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d", "e"}}, 111 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b"}}, 112 {Role: bootloader.RoleRunMode, Name: "0oader", Hashes: []string{"x", "z"}}, 113 {Role: bootloader.RoleRunMode, Name: "1oader", Hashes: []string{"d", "e"}}, 114 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 115 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 116 }) 117 118 // d is already sorted, sort it again 119 sort.Sort(boot.ByBootAssetOrder(d)) 120 // still the same 121 c.Check(d, DeepEquals, []boot.BootAsset{ 122 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d", "e"}}, 123 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b"}}, 124 {Role: bootloader.RoleRunMode, Name: "0oader", Hashes: []string{"x", "z"}}, 125 {Role: bootloader.RoleRunMode, Name: "1oader", Hashes: []string{"d", "e"}}, 126 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 127 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 128 }) 129 130 // 2 identical entries 131 d = []boot.BootAsset{ 132 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"x", "z"}}, 133 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"x", "z"}}, 134 } 135 sort.Sort(boot.ByBootAssetOrder(d)) 136 c.Check(d, DeepEquals, []boot.BootAsset{ 137 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"x", "z"}}, 138 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"x", "z"}}, 139 }) 140 141 } 142 143 func (s *bootchainSuite) TestBootAssetsPredictable(c *C) { 144 // by role 145 ba := boot.BootAsset{ 146 Role: bootloader.RoleRunMode, Name: "list", Hashes: []string{"b", "a"}, 147 } 148 pred := boot.ToPredictableBootAsset(&ba) 149 c.Check(pred, DeepEquals, &boot.BootAsset{ 150 Role: bootloader.RoleRunMode, Name: "list", Hashes: []string{"a", "b"}, 151 }) 152 // original structure is not changed 153 c.Check(ba, DeepEquals, boot.BootAsset{ 154 Role: bootloader.RoleRunMode, Name: "list", Hashes: []string{"b", "a"}, 155 }) 156 157 // try to make a predictable struct predictable once more 158 predAgain := boot.ToPredictableBootAsset(pred) 159 c.Check(predAgain, DeepEquals, pred) 160 161 baNil := boot.ToPredictableBootAsset(nil) 162 c.Check(baNil, IsNil) 163 } 164 165 func (s *bootchainSuite) TestBootChainMarshalOnlyAssets(c *C) { 166 pbNil := boot.ToPredictableBootChain(nil) 167 c.Check(pbNil, IsNil) 168 169 bc := &boot.BootChain{ 170 AssetChain: []boot.BootAsset{ 171 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 172 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b"}}, 173 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"d", "c"}}, 174 {Role: bootloader.RoleRunMode, Name: "1oader", Hashes: []string{"e", "d"}}, 175 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"e", "d"}}, 176 {Role: bootloader.RoleRunMode, Name: "0oader", Hashes: []string{"z", "x"}}, 177 }, 178 } 179 180 predictableBc := boot.ToPredictableBootChain(bc) 181 182 c.Check(predictableBc, DeepEquals, &boot.BootChain{ 183 // assets are sorted 184 AssetChain: []boot.BootAsset{ 185 // hash lists are sorted 186 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d", "e"}}, 187 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b"}}, 188 {Role: bootloader.RoleRunMode, Name: "0oader", Hashes: []string{"x", "z"}}, 189 {Role: bootloader.RoleRunMode, Name: "1oader", Hashes: []string{"d", "e"}}, 190 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 191 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 192 }, 193 }) 194 195 d, err := json.Marshal(predictableBc) 196 c.Assert(err, IsNil) 197 c.Check(string(d), Equals, `{"brand-id":"","model":"","grade":"","model-sign-key-id":"","asset-chain":[{"role":"recovery","name":"loader","hashes":["d","e"]},{"role":"recovery","name":"shim","hashes":["b"]},{"role":"run-mode","name":"0oader","hashes":["x","z"]},{"role":"run-mode","name":"1oader","hashes":["d","e"]},{"role":"run-mode","name":"loader","hashes":["z"]},{"role":"run-mode","name":"loader","hashes":["c","d"]}],"kernel":"","kernel-revision":"","kernel-cmdlines":null}`) 198 199 // already predictable, but try again 200 alreadySortedBc := boot.ToPredictableBootChain(predictableBc) 201 c.Check(alreadySortedBc, DeepEquals, predictableBc) 202 203 // boot chain with 2 identical assets 204 bcIdenticalAssets := &boot.BootChain{ 205 AssetChain: []boot.BootAsset{ 206 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 207 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z"}}, 208 }, 209 } 210 sortedBcIdentical := boot.ToPredictableBootChain(bcIdenticalAssets) 211 c.Check(sortedBcIdentical, DeepEquals, bcIdenticalAssets) 212 } 213 214 func (s *bootchainSuite) TestBootChainMarshalFull(c *C) { 215 bc := &boot.BootChain{ 216 BrandID: "mybrand", 217 Model: "foo", 218 Grade: "dangerous", 219 ModelSignKeyID: "my-key-id", 220 // asset chain will get sorted when marshaling 221 AssetChain: []boot.BootAsset{ 222 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 223 // hash list will get sorted 224 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b", "a"}}, 225 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d"}}, 226 }, 227 Kernel: "pc-kernel", 228 KernelRevision: "1234", 229 KernelCmdlines: []string{`foo=bar baz=0x123`, `a=1`}, 230 } 231 232 uc20model := makeMockUC20Model() 233 bc.SetModelAssertion(uc20model) 234 kernelBootFile := bootloader.NewBootFile("pc-kernel", "/foo", bootloader.RoleRecovery) 235 bc.SetKernelBootFile(kernelBootFile) 236 237 expectedPredictableBc := &boot.BootChain{ 238 BrandID: "mybrand", 239 Model: "foo", 240 Grade: "dangerous", 241 ModelSignKeyID: "my-key-id", 242 // assets are sorted 243 AssetChain: []boot.BootAsset{ 244 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d"}}, 245 // hash lists are sorted 246 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"a", "b"}}, 247 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 248 }, 249 Kernel: "pc-kernel", 250 KernelRevision: "1234", 251 KernelCmdlines: []string{`a=1`, `foo=bar baz=0x123`}, 252 } 253 // those can't be set directly, but are copied as well 254 expectedPredictableBc.SetModelAssertion(uc20model) 255 expectedPredictableBc.SetKernelBootFile(kernelBootFile) 256 257 predictableBc := boot.ToPredictableBootChain(bc) 258 c.Check(predictableBc, DeepEquals, expectedPredictableBc) 259 260 d, err := json.Marshal(predictableBc) 261 c.Assert(err, IsNil) 262 c.Check(string(d), Equals, `{"brand-id":"mybrand","model":"foo","grade":"dangerous","model-sign-key-id":"my-key-id","asset-chain":[{"role":"recovery","name":"loader","hashes":["d"]},{"role":"recovery","name":"shim","hashes":["a","b"]},{"role":"run-mode","name":"loader","hashes":["c","d"]}],"kernel":"pc-kernel","kernel-revision":"1234","kernel-cmdlines":["a=1","foo=bar baz=0x123"]}`) 263 264 expectedOriginal := &boot.BootChain{ 265 BrandID: "mybrand", 266 Model: "foo", 267 Grade: "dangerous", 268 ModelSignKeyID: "my-key-id", 269 // asset chain will get sorted when marshaling 270 AssetChain: []boot.BootAsset{ 271 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 272 // hash list will get sorted 273 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b", "a"}}, 274 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d"}}, 275 }, 276 Kernel: "pc-kernel", 277 KernelRevision: "1234", 278 KernelCmdlines: []string{`foo=bar baz=0x123`, `a=1`}, 279 } 280 expectedOriginal.SetModelAssertion(uc20model) 281 expectedOriginal.SetKernelBootFile(kernelBootFile) 282 // original structure has not been modified 283 c.Check(bc, DeepEquals, expectedOriginal) 284 } 285 286 func (s *bootchainSuite) TestBootChainEqualForResealComplex(c *C) { 287 bc := []boot.BootChain{ 288 { 289 BrandID: "mybrand", 290 Model: "foo", 291 Grade: "dangerous", 292 ModelSignKeyID: "my-key-id", 293 AssetChain: []boot.BootAsset{ 294 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 295 // hash list will get sorted 296 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"b", "a"}}, 297 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d"}}, 298 }, 299 Kernel: "pc-kernel", 300 KernelRevision: "1234", 301 KernelCmdlines: []string{`foo=bar baz=0x123`}, 302 }, 303 } 304 pb := boot.ToPredictableBootChains(bc) 305 // sorted variant 306 pbOther := boot.PredictableBootChains{ 307 { 308 BrandID: "mybrand", 309 Model: "foo", 310 Grade: "dangerous", 311 ModelSignKeyID: "my-key-id", 312 AssetChain: []boot.BootAsset{ 313 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"d"}}, 314 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"a", "b"}}, 315 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 316 }, 317 Kernel: "pc-kernel", 318 KernelRevision: "1234", 319 KernelCmdlines: []string{`foo=bar baz=0x123`}, 320 }, 321 } 322 eq := boot.PredictableBootChainsEqualForReseal(pb, pbOther) 323 c.Check(eq, Equals, true, Commentf("not equal\none: %v\nother: %v", pb, pbOther)) 324 } 325 326 func (s *bootchainSuite) TestPredictableBootChainsEqualForResealSimple(c *C) { 327 var pbNil boot.PredictableBootChains 328 329 c.Check(boot.PredictableBootChainsEqualForReseal(pbNil, pbNil), Equals, true) 330 331 bcJustOne := []boot.BootChain{ 332 { 333 BrandID: "mybrand", 334 Model: "foo", 335 Grade: "dangerous", 336 ModelSignKeyID: "my-key-id", 337 AssetChain: []boot.BootAsset{ 338 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 339 }, 340 Kernel: "pc-kernel-other", 341 KernelRevision: "1234", 342 KernelCmdlines: []string{`foo`}, 343 }, 344 } 345 pbJustOne := boot.ToPredictableBootChains(bcJustOne) 346 // equal with self 347 c.Check(boot.PredictableBootChainsEqualForReseal(pbJustOne, pbJustOne), Equals, true) 348 349 // equal with nil? 350 c.Check(boot.PredictableBootChainsEqualForReseal(pbJustOne, pbNil), Equals, false) 351 352 bcMoreAssets := []boot.BootChain{ 353 { 354 BrandID: "mybrand", 355 Model: "foo", 356 Grade: "dangerous", 357 ModelSignKeyID: "my-key-id", 358 AssetChain: []boot.BootAsset{ 359 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"c", "d"}}, 360 }, 361 Kernel: "pc-kernel-other", 362 KernelRevision: "1234", 363 KernelCmdlines: []string{`foo`}, 364 }, { 365 BrandID: "mybrand", 366 Model: "foo", 367 Grade: "dangerous", 368 ModelSignKeyID: "my-key-id", 369 AssetChain: []boot.BootAsset{ 370 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"d", "e"}}, 371 }, 372 Kernel: "pc-kernel-other", 373 KernelRevision: "1234", 374 KernelCmdlines: []string{`foo`}, 375 }, 376 } 377 378 pbMoreAssets := boot.ToPredictableBootChains(bcMoreAssets) 379 380 c.Check(boot.PredictableBootChainsEqualForReseal(pbMoreAssets, pbJustOne), Equals, false) 381 // with self 382 c.Check(boot.PredictableBootChainsEqualForReseal(pbMoreAssets, pbMoreAssets), Equals, true) 383 } 384 385 func (s *bootchainSuite) TestPredictableBootChainsFullMarshal(c *C) { 386 // chains will be sorted 387 chains := []boot.BootChain{ 388 { 389 BrandID: "mybrand", 390 Model: "foo", 391 Grade: "signed", 392 ModelSignKeyID: "my-key-id", 393 // assets will be sorted 394 AssetChain: []boot.BootAsset{ 395 // hashes will be sorted 396 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"x", "y"}}, 397 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"c", "d"}}, 398 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"z", "x"}}, 399 }, 400 Kernel: "pc-kernel-other", 401 KernelRevision: "2345", 402 KernelCmdlines: []string{`snapd_recovery_mode=run foo`}, 403 }, { 404 BrandID: "mybrand", 405 Model: "foo", 406 Grade: "dangerous", 407 ModelSignKeyID: "my-key-id", 408 // assets will be sorted 409 AssetChain: []boot.BootAsset{ 410 // hashes will be sorted 411 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"y", "x"}}, 412 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"c", "d"}}, 413 {Role: bootloader.RoleRunMode, Name: "loader", Hashes: []string{"b", "a"}}, 414 }, 415 Kernel: "pc-kernel-other", 416 KernelRevision: "1234", 417 KernelCmdlines: []string{`snapd_recovery_mode=run foo`}, 418 }, { 419 // recovery system 420 BrandID: "mybrand", 421 Model: "foo", 422 Grade: "dangerous", 423 ModelSignKeyID: "my-key-id", 424 // will be sorted 425 AssetChain: []boot.BootAsset{ 426 {Role: bootloader.RoleRecovery, Name: "shim", Hashes: []string{"y", "x"}}, 427 {Role: bootloader.RoleRecovery, Name: "loader", Hashes: []string{"c", "d"}}, 428 }, 429 Kernel: "pc-kernel-other", 430 KernelRevision: "12", 431 KernelCmdlines: []string{ 432 // will be sorted 433 `snapd_recovery_mode=recover snapd_recovery_system=23 foo`, 434 `snapd_recovery_mode=recover snapd_recovery_system=12 foo`, 435 }, 436 }, 437 } 438 439 predictableChains := boot.ToPredictableBootChains(chains) 440 d, err := json.Marshal(predictableChains) 441 c.Assert(err, IsNil) 442 443 var data []map[string]interface{} 444 err = json.Unmarshal(d, &data) 445 c.Assert(err, IsNil) 446 c.Check(data, DeepEquals, []map[string]interface{}{ 447 { 448 "model": "foo", 449 "brand-id": "mybrand", 450 "grade": "dangerous", 451 "model-sign-key-id": "my-key-id", 452 "kernel": "pc-kernel-other", 453 "kernel-revision": "12", 454 "kernel-cmdlines": []interface{}{ 455 `snapd_recovery_mode=recover snapd_recovery_system=12 foo`, 456 `snapd_recovery_mode=recover snapd_recovery_system=23 foo`, 457 }, 458 "asset-chain": []interface{}{ 459 map[string]interface{}{"role": "recovery", "name": "loader", "hashes": []interface{}{"c", "d"}}, 460 map[string]interface{}{"role": "recovery", "name": "shim", "hashes": []interface{}{"x", "y"}}, 461 }, 462 }, { 463 "model": "foo", 464 "brand-id": "mybrand", 465 "grade": "dangerous", 466 "model-sign-key-id": "my-key-id", 467 "kernel": "pc-kernel-other", 468 "kernel-revision": "1234", 469 "kernel-cmdlines": []interface{}{"snapd_recovery_mode=run foo"}, 470 "asset-chain": []interface{}{ 471 map[string]interface{}{"role": "recovery", "name": "loader", "hashes": []interface{}{"c", "d"}}, 472 map[string]interface{}{"role": "recovery", "name": "shim", "hashes": []interface{}{"x", "y"}}, 473 map[string]interface{}{"role": "run-mode", "name": "loader", "hashes": []interface{}{"a", "b"}}, 474 }, 475 }, { 476 "model": "foo", 477 "brand-id": "mybrand", 478 "grade": "signed", 479 "model-sign-key-id": "my-key-id", 480 "kernel": "pc-kernel-other", 481 "kernel-revision": "2345", 482 "kernel-cmdlines": []interface{}{"snapd_recovery_mode=run foo"}, 483 "asset-chain": []interface{}{ 484 map[string]interface{}{"role": "recovery", "name": "loader", "hashes": []interface{}{"c", "d"}}, 485 map[string]interface{}{"role": "recovery", "name": "shim", "hashes": []interface{}{"x", "y"}}, 486 map[string]interface{}{"role": "run-mode", "name": "loader", "hashes": []interface{}{"x", "z"}}, 487 }, 488 }, 489 }) 490 } 491 492 func (s *bootchainSuite) TestPredictableBootChainsFields(c *C) { 493 chainsNil := boot.ToPredictableBootChains(nil) 494 c.Check(chainsNil, IsNil) 495 496 justOne := []boot.BootChain{ 497 { 498 BrandID: "mybrand", 499 Model: "foo", 500 Grade: "signed", 501 ModelSignKeyID: "my-key-id", 502 Kernel: "pc-kernel-other", 503 KernelRevision: "2345", 504 KernelCmdlines: []string{`foo`}, 505 }, 506 } 507 predictableJustOne := boot.ToPredictableBootChains(justOne) 508 c.Check(predictableJustOne, DeepEquals, boot.PredictableBootChains(justOne)) 509 510 chainsGrade := []boot.BootChain{ 511 { 512 Grade: "signed", 513 }, { 514 Grade: "dangerous", 515 }, 516 } 517 c.Check(boot.ToPredictableBootChains(chainsGrade), DeepEquals, boot.PredictableBootChains{ 518 { 519 Grade: "dangerous", 520 }, { 521 Grade: "signed", 522 }, 523 }) 524 525 chainsKernel := []boot.BootChain{ 526 { 527 Grade: "dangerous", 528 Kernel: "foo", 529 }, { 530 Grade: "dangerous", 531 Kernel: "bar", 532 }, 533 } 534 c.Check(boot.ToPredictableBootChains(chainsKernel), DeepEquals, boot.PredictableBootChains{ 535 { 536 Grade: "dangerous", 537 Kernel: "bar", 538 }, { 539 Grade: "dangerous", 540 Kernel: "foo", 541 }, 542 }) 543 544 chainsCmdline := []boot.BootChain{ 545 { 546 Grade: "dangerous", 547 Kernel: "foo", 548 KernelCmdlines: []string{`panic=1`}, 549 }, { 550 Grade: "dangerous", 551 Kernel: "foo", 552 KernelCmdlines: []string{`a`}, 553 }, 554 } 555 c.Check(boot.ToPredictableBootChains(chainsCmdline), DeepEquals, boot.PredictableBootChains{ 556 { 557 Grade: "dangerous", 558 Kernel: "foo", 559 KernelCmdlines: []string{`a`}, 560 }, { 561 Grade: "dangerous", 562 Kernel: "foo", 563 KernelCmdlines: []string{`panic=1`}, 564 }, 565 }) 566 567 chainsModel := []boot.BootChain{ 568 { 569 Model: "fridge", 570 Grade: "dangerous", 571 Kernel: "foo", 572 KernelCmdlines: []string{`panic=1`}, 573 }, { 574 Model: "box", 575 Grade: "dangerous", 576 Kernel: "foo", 577 KernelCmdlines: []string{`panic=1`}, 578 }, 579 } 580 c.Check(boot.ToPredictableBootChains(chainsModel), DeepEquals, boot.PredictableBootChains{ 581 { 582 Model: "box", 583 Grade: "dangerous", 584 Kernel: "foo", 585 KernelCmdlines: []string{`panic=1`}, 586 }, { 587 Model: "fridge", 588 Grade: "dangerous", 589 Kernel: "foo", 590 KernelCmdlines: []string{`panic=1`}, 591 }, 592 }) 593 594 chainsBrand := []boot.BootChain{ 595 { 596 BrandID: "foo", 597 Model: "box", 598 Grade: "dangerous", 599 Kernel: "foo", 600 KernelCmdlines: []string{`panic=1`}, 601 }, { 602 BrandID: "acme", 603 Model: "box", 604 Grade: "dangerous", 605 Kernel: "foo", 606 KernelCmdlines: []string{`panic=1`}, 607 }, 608 } 609 c.Check(boot.ToPredictableBootChains(chainsBrand), DeepEquals, boot.PredictableBootChains{ 610 { 611 BrandID: "acme", 612 Model: "box", 613 Grade: "dangerous", 614 Kernel: "foo", 615 KernelCmdlines: []string{`panic=1`}, 616 }, { 617 BrandID: "foo", 618 Model: "box", 619 Grade: "dangerous", 620 Kernel: "foo", 621 KernelCmdlines: []string{`panic=1`}, 622 }, 623 }) 624 625 chainsKeyID := []boot.BootChain{ 626 { 627 BrandID: "foo", 628 Model: "box", 629 Grade: "dangerous", 630 Kernel: "foo", 631 KernelCmdlines: []string{`panic=1`}, 632 ModelSignKeyID: "key-2", 633 }, { 634 BrandID: "foo", 635 Model: "box", 636 Grade: "dangerous", 637 Kernel: "foo", 638 KernelCmdlines: []string{`panic=1`}, 639 ModelSignKeyID: "key-1", 640 }, 641 } 642 c.Check(boot.ToPredictableBootChains(chainsKeyID), DeepEquals, boot.PredictableBootChains{ 643 { 644 BrandID: "foo", 645 Model: "box", 646 Grade: "dangerous", 647 Kernel: "foo", 648 KernelCmdlines: []string{`panic=1`}, 649 ModelSignKeyID: "key-1", 650 }, { 651 BrandID: "foo", 652 Model: "box", 653 Grade: "dangerous", 654 Kernel: "foo", 655 KernelCmdlines: []string{`panic=1`}, 656 ModelSignKeyID: "key-2", 657 }, 658 }) 659 660 chainsAssets := []boot.BootChain{ 661 { 662 BrandID: "foo", 663 Model: "box", 664 Grade: "dangerous", 665 ModelSignKeyID: "key-1", 666 AssetChain: []boot.BootAsset{ 667 // will be sorted 668 {Hashes: []string{"b", "a"}}, 669 }, 670 Kernel: "foo", 671 KernelCmdlines: []string{`panic=1`}, 672 }, { 673 BrandID: "foo", 674 Model: "box", 675 Grade: "dangerous", 676 ModelSignKeyID: "key-1", 677 AssetChain: []boot.BootAsset{ 678 {Hashes: []string{"b"}}, 679 }, 680 Kernel: "foo", 681 KernelCmdlines: []string{`panic=1`}, 682 }, 683 } 684 c.Check(boot.ToPredictableBootChains(chainsAssets), DeepEquals, boot.PredictableBootChains{ 685 { 686 BrandID: "foo", 687 Model: "box", 688 Grade: "dangerous", 689 ModelSignKeyID: "key-1", 690 AssetChain: []boot.BootAsset{ 691 {Hashes: []string{"b"}}, 692 }, 693 Kernel: "foo", 694 KernelCmdlines: []string{`panic=1`}, 695 }, { 696 BrandID: "foo", 697 Model: "box", 698 Grade: "dangerous", 699 ModelSignKeyID: "key-1", 700 AssetChain: []boot.BootAsset{ 701 {Hashes: []string{"a", "b"}}, 702 }, 703 Kernel: "foo", 704 KernelCmdlines: []string{`panic=1`}, 705 }, 706 }) 707 708 chainsFewerAssets := []boot.BootChain{ 709 { 710 AssetChain: []boot.BootAsset{ 711 {Hashes: []string{"b", "a"}}, 712 {Hashes: []string{"c", "d"}}, 713 }, 714 }, { 715 AssetChain: []boot.BootAsset{ 716 {Hashes: []string{"b"}}, 717 }, 718 }, 719 } 720 c.Check(boot.ToPredictableBootChains(chainsFewerAssets), DeepEquals, boot.PredictableBootChains{ 721 { 722 AssetChain: []boot.BootAsset{ 723 {Hashes: []string{"b"}}, 724 }, 725 }, { 726 AssetChain: []boot.BootAsset{ 727 {Hashes: []string{"a", "b"}}, 728 {Hashes: []string{"c", "d"}}, 729 }, 730 }, 731 }) 732 733 // not confused if 2 chains are identical 734 chainsIdenticalAssets := []boot.BootChain{ 735 { 736 BrandID: "foo", 737 Model: "box", 738 ModelSignKeyID: "key-1", 739 AssetChain: []boot.BootAsset{ 740 {Name: "asset", Hashes: []string{"a", "b"}}, 741 {Name: "asset", Hashes: []string{"a", "b"}}, 742 }, 743 Grade: "dangerous", 744 Kernel: "foo", 745 KernelCmdlines: []string{`panic=1`}, 746 }, { 747 BrandID: "foo", 748 Model: "box", 749 Grade: "dangerous", 750 ModelSignKeyID: "key-1", 751 AssetChain: []boot.BootAsset{ 752 {Name: "asset", Hashes: []string{"a", "b"}}, 753 {Name: "asset", Hashes: []string{"a", "b"}}, 754 }, 755 Kernel: "foo", 756 KernelCmdlines: []string{`panic=1`}, 757 }, 758 } 759 c.Check(boot.ToPredictableBootChains(chainsIdenticalAssets), DeepEquals, boot.PredictableBootChains(chainsIdenticalAssets)) 760 } 761 762 func (s *bootchainSuite) TestPredictableBootChainsSortOrder(c *C) { 763 // check that sort order is model info, assets, kernel, kernel cmdline 764 765 chains := []boot.BootChain{ 766 { 767 Model: "b", 768 AssetChain: []boot.BootAsset{ 769 {Name: "asset", Hashes: []string{"y"}}, 770 }, 771 Kernel: "k1", 772 KernelCmdlines: []string{"cm=1"}, 773 }, 774 { 775 Model: "b", 776 AssetChain: []boot.BootAsset{ 777 {Name: "asset", Hashes: []string{"y"}}, 778 }, 779 Kernel: "k2", 780 KernelCmdlines: []string{"cm=1"}, 781 }, 782 { 783 Model: "a", 784 AssetChain: []boot.BootAsset{ 785 {Name: "asset", Hashes: []string{"y"}}, 786 }, 787 Kernel: "k1", 788 KernelCmdlines: []string{"cm=1"}, 789 }, 790 { 791 Model: "a", 792 AssetChain: []boot.BootAsset{ 793 {Name: "asset", Hashes: []string{"y"}}, 794 }, 795 Kernel: "k2", 796 KernelCmdlines: []string{"cm=1"}, 797 }, 798 { 799 Model: "b", 800 AssetChain: []boot.BootAsset{ 801 {Name: "asset", Hashes: []string{"y"}}, 802 }, 803 Kernel: "k1", 804 KernelCmdlines: []string{"cm=2"}, 805 }, 806 { 807 Model: "b", 808 AssetChain: []boot.BootAsset{ 809 {Name: "asset", Hashes: []string{"y"}}, 810 }, 811 Kernel: "k2", 812 KernelCmdlines: []string{"cm=2"}, 813 }, 814 { 815 Model: "a", 816 AssetChain: []boot.BootAsset{ 817 {Name: "asset", Hashes: []string{"y"}}, 818 }, 819 Kernel: "k1", 820 KernelCmdlines: []string{"cm=2"}, 821 }, 822 { 823 Model: "a", 824 AssetChain: []boot.BootAsset{ 825 {Name: "asset", Hashes: []string{"y"}}, 826 }, 827 Kernel: "k2", 828 KernelCmdlines: []string{"cm=2"}, 829 }, 830 { 831 Model: "b", 832 AssetChain: []boot.BootAsset{ 833 {Name: "asset", Hashes: []string{"x"}}, 834 }, 835 Kernel: "k1", 836 KernelCmdlines: []string{"cm=1"}, 837 }, 838 { 839 Model: "b", 840 AssetChain: []boot.BootAsset{ 841 {Name: "asset", Hashes: []string{"x"}}, 842 }, 843 Kernel: "k2", 844 KernelCmdlines: []string{"cm=1"}, 845 }, 846 { 847 Model: "a", 848 AssetChain: []boot.BootAsset{ 849 {Name: "asset", Hashes: []string{"x"}}, 850 }, 851 Kernel: "k1", 852 KernelCmdlines: []string{"cm=1"}, 853 }, 854 { 855 Model: "a", 856 AssetChain: []boot.BootAsset{ 857 {Name: "asset", Hashes: []string{"x"}}, 858 }, 859 Kernel: "k2", 860 KernelCmdlines: []string{"cm=1"}, 861 }, 862 { 863 Model: "b", 864 AssetChain: []boot.BootAsset{ 865 {Name: "asset", Hashes: []string{"x"}}, 866 }, 867 Kernel: "k1", 868 KernelCmdlines: []string{"cm=2"}, 869 }, 870 { 871 Model: "b", 872 AssetChain: []boot.BootAsset{ 873 {Name: "asset", Hashes: []string{"x"}}, 874 }, 875 Kernel: "k2", 876 KernelCmdlines: []string{"cm=2"}, 877 }, 878 { 879 Model: "a", 880 AssetChain: []boot.BootAsset{ 881 {Name: "asset", Hashes: []string{"x"}}, 882 }, 883 Kernel: "k1", 884 KernelCmdlines: []string{"cm=2"}, 885 }, 886 { 887 Model: "a", 888 AssetChain: []boot.BootAsset{ 889 {Name: "asset", Hashes: []string{"x"}}, 890 }, 891 Kernel: "k2", 892 KernelCmdlines: []string{"cm=2"}, 893 }, 894 { 895 Model: "a", 896 AssetChain: []boot.BootAsset{ 897 {Name: "asset", Hashes: []string{"y"}}, 898 }, 899 Kernel: "k2", 900 KernelCmdlines: []string{"cm=1", "cm=2"}, 901 }, 902 { 903 Model: "a", 904 AssetChain: []boot.BootAsset{ 905 {Name: "asset", Hashes: []string{"y"}}, 906 }, 907 Kernel: "k1", 908 KernelCmdlines: []string{"cm=1", "cm=2"}, 909 }, 910 } 911 predictable := boot.ToPredictableBootChains(chains) 912 c.Check(predictable, DeepEquals, boot.PredictableBootChains{ 913 { 914 Model: "a", 915 AssetChain: []boot.BootAsset{ 916 {Name: "asset", Hashes: []string{"x"}}, 917 }, 918 Kernel: "k1", 919 KernelCmdlines: []string{"cm=1"}, 920 }, 921 { 922 Model: "a", 923 AssetChain: []boot.BootAsset{ 924 {Name: "asset", Hashes: []string{"x"}}, 925 }, 926 Kernel: "k1", 927 KernelCmdlines: []string{"cm=2"}, 928 }, 929 { 930 Model: "a", 931 AssetChain: []boot.BootAsset{ 932 {Name: "asset", Hashes: []string{"x"}}, 933 }, 934 Kernel: "k2", 935 KernelCmdlines: []string{"cm=1"}, 936 }, 937 { 938 Model: "a", 939 AssetChain: []boot.BootAsset{ 940 {Name: "asset", Hashes: []string{"x"}}, 941 }, 942 Kernel: "k2", 943 KernelCmdlines: []string{"cm=2"}, 944 }, 945 { 946 Model: "a", 947 AssetChain: []boot.BootAsset{ 948 {Name: "asset", Hashes: []string{"y"}}, 949 }, 950 Kernel: "k1", 951 KernelCmdlines: []string{"cm=1"}, 952 }, 953 { 954 Model: "a", 955 AssetChain: []boot.BootAsset{ 956 {Name: "asset", Hashes: []string{"y"}}, 957 }, 958 Kernel: "k1", 959 KernelCmdlines: []string{"cm=2"}, 960 }, 961 { 962 Model: "a", 963 AssetChain: []boot.BootAsset{ 964 {Name: "asset", Hashes: []string{"y"}}, 965 }, 966 Kernel: "k1", 967 KernelCmdlines: []string{"cm=1", "cm=2"}, 968 }, 969 { 970 Model: "a", 971 AssetChain: []boot.BootAsset{ 972 {Name: "asset", Hashes: []string{"y"}}, 973 }, 974 Kernel: "k2", 975 KernelCmdlines: []string{"cm=1"}, 976 }, 977 { 978 Model: "a", 979 AssetChain: []boot.BootAsset{ 980 {Name: "asset", Hashes: []string{"y"}}, 981 }, 982 Kernel: "k2", 983 KernelCmdlines: []string{"cm=2"}, 984 }, 985 { 986 Model: "a", 987 AssetChain: []boot.BootAsset{ 988 {Name: "asset", Hashes: []string{"y"}}, 989 }, 990 Kernel: "k2", 991 KernelCmdlines: []string{"cm=1", "cm=2"}, 992 }, 993 { 994 Model: "b", 995 AssetChain: []boot.BootAsset{ 996 {Name: "asset", Hashes: []string{"x"}}, 997 }, 998 Kernel: "k1", 999 KernelCmdlines: []string{"cm=1"}, 1000 }, 1001 { 1002 Model: "b", 1003 AssetChain: []boot.BootAsset{ 1004 {Name: "asset", Hashes: []string{"x"}}, 1005 }, 1006 Kernel: "k1", 1007 KernelCmdlines: []string{"cm=2"}, 1008 }, 1009 { 1010 Model: "b", 1011 AssetChain: []boot.BootAsset{ 1012 {Name: "asset", Hashes: []string{"x"}}, 1013 }, 1014 Kernel: "k2", 1015 KernelCmdlines: []string{"cm=1"}, 1016 }, 1017 { 1018 Model: "b", 1019 AssetChain: []boot.BootAsset{ 1020 {Name: "asset", Hashes: []string{"x"}}, 1021 }, 1022 Kernel: "k2", 1023 KernelCmdlines: []string{"cm=2"}, 1024 }, 1025 { 1026 Model: "b", 1027 AssetChain: []boot.BootAsset{ 1028 {Name: "asset", Hashes: []string{"y"}}, 1029 }, 1030 Kernel: "k1", 1031 KernelCmdlines: []string{"cm=1"}, 1032 }, 1033 { 1034 Model: "b", 1035 AssetChain: []boot.BootAsset{ 1036 {Name: "asset", Hashes: []string{"y"}}, 1037 }, 1038 Kernel: "k1", 1039 KernelCmdlines: []string{"cm=2"}, 1040 }, 1041 { 1042 Model: "b", 1043 AssetChain: []boot.BootAsset{ 1044 {Name: "asset", Hashes: []string{"y"}}, 1045 }, 1046 Kernel: "k2", 1047 KernelCmdlines: []string{"cm=1"}, 1048 }, 1049 { 1050 Model: "b", 1051 AssetChain: []boot.BootAsset{ 1052 {Name: "asset", Hashes: []string{"y"}}, 1053 }, 1054 Kernel: "k2", 1055 KernelCmdlines: []string{"cm=2"}, 1056 }, 1057 }) 1058 } 1059 1060 func printChain(c *C, chain *secboot.LoadChain, prefix string) { 1061 c.Logf("%v %v", prefix, chain.BootFile) 1062 for _, n := range chain.Next { 1063 printChain(c, n, prefix+"-") 1064 } 1065 } 1066 1067 // cPath returns a path under boot assets cache directory 1068 func cPath(p string) string { 1069 return filepath.Join(dirs.SnapBootAssetsDir, p) 1070 } 1071 1072 // nbf is bootloader.NewBootFile but shorter 1073 var nbf = bootloader.NewBootFile 1074 1075 func (s *bootchainSuite) TestBootAssetsToLoadChainTrivialKernel(c *C) { 1076 kbl := bootloader.NewBootFile("pc-kernel", "kernel.efi", bootloader.RoleRunMode) 1077 1078 chains, err := boot.BootAssetsToLoadChains(nil, kbl, nil) 1079 c.Assert(err, IsNil) 1080 1081 c.Check(chains, DeepEquals, []*secboot.LoadChain{ 1082 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode)), 1083 }) 1084 } 1085 1086 func (s *bootchainSuite) TestBootAssetsToLoadChainErr(c *C) { 1087 kbl := bootloader.NewBootFile("pc-kernel", "kernel.efi", bootloader.RoleRunMode) 1088 1089 assets := []boot.BootAsset{ 1090 {Name: "shim", Hashes: []string{"hash0"}, Role: bootloader.RoleRecovery}, 1091 {Name: "loader-recovery", Hashes: []string{"hash0"}, Role: bootloader.RoleRecovery}, 1092 {Name: "loader-run", Hashes: []string{"hash0"}, Role: bootloader.RoleRunMode}, 1093 } 1094 1095 blNames := map[bootloader.Role]string{ 1096 bootloader.RoleRecovery: "recovery-bl", 1097 // missing bootloader name for role "run-mode" 1098 } 1099 // fails when probing the shim asset in the cache 1100 chains, err := boot.BootAssetsToLoadChains(assets, kbl, blNames) 1101 c.Assert(err, ErrorMatches, "file .*/recovery-bl/shim-hash0 not found in boot assets cache") 1102 c.Check(chains, IsNil) 1103 // make it work now 1104 c.Assert(os.MkdirAll(filepath.Dir(cPath("recovery-bl/shim-hash0")), 0755), IsNil) 1105 c.Assert(ioutil.WriteFile(cPath("recovery-bl/shim-hash0"), nil, 0644), IsNil) 1106 1107 // nested error bubbled up 1108 chains, err = boot.BootAssetsToLoadChains(assets, kbl, blNames) 1109 c.Assert(err, ErrorMatches, "file .*/recovery-bl/loader-recovery-hash0 not found in boot assets cache") 1110 c.Check(chains, IsNil) 1111 // again, make it work 1112 c.Assert(os.MkdirAll(filepath.Dir(cPath("recovery-bl/loader-recovery-hash0")), 0755), IsNil) 1113 c.Assert(ioutil.WriteFile(cPath("recovery-bl/loader-recovery-hash0"), nil, 0644), IsNil) 1114 1115 // fails on missing bootloader name for role "run-mode" 1116 chains, err = boot.BootAssetsToLoadChains(assets, kbl, blNames) 1117 c.Assert(err, ErrorMatches, `internal error: no bootloader name for boot asset role "run-mode"`) 1118 c.Check(chains, IsNil) 1119 } 1120 1121 func (s *bootchainSuite) TestBootAssetsToLoadChainSimpleChain(c *C) { 1122 kbl := bootloader.NewBootFile("pc-kernel", "kernel.efi", bootloader.RoleRunMode) 1123 1124 assets := []boot.BootAsset{ 1125 {Name: "shim", Hashes: []string{"hash0"}, Role: bootloader.RoleRecovery}, 1126 {Name: "loader-recovery", Hashes: []string{"hash0"}, Role: bootloader.RoleRecovery}, 1127 {Name: "loader-run", Hashes: []string{"hash0"}, Role: bootloader.RoleRunMode}, 1128 } 1129 1130 // mock relevant files in cache 1131 for _, name := range []string{ 1132 "recovery-bl/shim-hash0", 1133 "recovery-bl/loader-recovery-hash0", 1134 "run-bl/loader-run-hash0", 1135 } { 1136 p := filepath.Join(dirs.SnapBootAssetsDir, name) 1137 c.Assert(os.MkdirAll(filepath.Dir(p), 0755), IsNil) 1138 c.Assert(ioutil.WriteFile(p, nil, 0644), IsNil) 1139 } 1140 1141 blNames := map[bootloader.Role]string{ 1142 bootloader.RoleRecovery: "recovery-bl", 1143 bootloader.RoleRunMode: "run-bl", 1144 } 1145 1146 chains, err := boot.BootAssetsToLoadChains(assets, kbl, blNames) 1147 c.Assert(err, IsNil) 1148 1149 c.Logf("got:") 1150 for _, ch := range chains { 1151 printChain(c, ch, "-") 1152 } 1153 1154 expected := []*secboot.LoadChain{ 1155 secboot.NewLoadChain(nbf("", cPath("recovery-bl/shim-hash0"), bootloader.RoleRecovery), 1156 secboot.NewLoadChain(nbf("", cPath("recovery-bl/loader-recovery-hash0"), bootloader.RoleRecovery), 1157 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash0"), bootloader.RoleRunMode), 1158 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))))), 1159 } 1160 c.Check(chains, DeepEquals, expected) 1161 } 1162 1163 func (s *bootchainSuite) TestBootAssetsToLoadChainWithAlternativeChains(c *C) { 1164 kbl := bootloader.NewBootFile("pc-kernel", "kernel.efi", bootloader.RoleRunMode) 1165 1166 assets := []boot.BootAsset{ 1167 {Name: "shim", Hashes: []string{"hash0", "hash1"}, Role: bootloader.RoleRecovery}, 1168 {Name: "loader-recovery", Hashes: []string{"hash0", "hash1"}, Role: bootloader.RoleRecovery}, 1169 {Name: "loader-run", Hashes: []string{"hash0", "hash1"}, Role: bootloader.RoleRunMode}, 1170 } 1171 1172 // mock relevant files in cache 1173 for _, name := range []string{ 1174 "recovery-bl/shim-hash0", "recovery-bl/shim-hash1", 1175 "recovery-bl/loader-recovery-hash0", 1176 "recovery-bl/loader-recovery-hash1", 1177 "run-bl/loader-run-hash0", 1178 "run-bl/loader-run-hash1", 1179 } { 1180 p := filepath.Join(dirs.SnapBootAssetsDir, name) 1181 c.Assert(os.MkdirAll(filepath.Dir(p), 0755), IsNil) 1182 c.Assert(ioutil.WriteFile(p, nil, 0644), IsNil) 1183 } 1184 1185 blNames := map[bootloader.Role]string{ 1186 bootloader.RoleRecovery: "recovery-bl", 1187 bootloader.RoleRunMode: "run-bl", 1188 } 1189 chains, err := boot.BootAssetsToLoadChains(assets, kbl, blNames) 1190 c.Assert(err, IsNil) 1191 1192 c.Logf("got:") 1193 for _, ch := range chains { 1194 printChain(c, ch, "-") 1195 } 1196 1197 expected := []*secboot.LoadChain{ 1198 secboot.NewLoadChain(nbf("", cPath("recovery-bl/shim-hash0"), bootloader.RoleRecovery), 1199 secboot.NewLoadChain(nbf("", cPath("recovery-bl/loader-recovery-hash0"), bootloader.RoleRecovery), 1200 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash0"), bootloader.RoleRunMode), 1201 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))), 1202 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash1"), bootloader.RoleRunMode), 1203 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode)))), 1204 secboot.NewLoadChain(nbf("", cPath("recovery-bl/loader-recovery-hash1"), bootloader.RoleRecovery), 1205 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash0"), bootloader.RoleRunMode), 1206 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))), 1207 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash1"), bootloader.RoleRunMode), 1208 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))))), 1209 secboot.NewLoadChain(nbf("", cPath("recovery-bl/shim-hash1"), bootloader.RoleRecovery), 1210 secboot.NewLoadChain(nbf("", cPath("recovery-bl/loader-recovery-hash0"), bootloader.RoleRecovery), 1211 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash0"), bootloader.RoleRunMode), 1212 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))), 1213 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash1"), bootloader.RoleRunMode), 1214 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode)))), 1215 secboot.NewLoadChain(nbf("", cPath("recovery-bl/loader-recovery-hash1"), bootloader.RoleRecovery), 1216 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash0"), bootloader.RoleRunMode), 1217 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))), 1218 secboot.NewLoadChain(nbf("", cPath("run-bl/loader-run-hash1"), bootloader.RoleRunMode), 1219 secboot.NewLoadChain(nbf("pc-kernel", "kernel.efi", bootloader.RoleRunMode))))), 1220 } 1221 c.Check(chains, DeepEquals, expected) 1222 }