New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
boot: reseal when changing kernel #9331
boot: reseal when changing kernel #9331
Conversation
401d31f
to
a31f6dd
Compare
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
adjust tests ATM we should never have sealed keys and not a TrustedAssetsBootloader
a31f6dd
to
60ee9aa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a bunch of comments, I have addressed some in here already, and some I'm addressing in #9340
@@ -93,6 +96,9 @@ type bootStateUpdate20 struct { | |||
|
|||
// tasks to run after the modeenv has been written | |||
postModeenvTasks []bootCommitTask | |||
|
|||
// device | |||
dev Device |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should store just the model atm (when we will have to support remodeling it will get more complex but let's do things one at a time), something like resealModel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is done in #9340
@@ -103,6 +109,10 @@ func (u20 *bootStateUpdate20) postModeenv(task bootCommitTask) { | |||
u20.postModeenvTasks = append(u20.postModeenvTasks, task) | |||
} | |||
|
|||
func (u20 *bootStateUpdate20) setDevice(dev Device) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this then could have a meaningful name like resealForModel(model)
// in between, we are still able to boot properly | ||
if u20.dev != nil { | ||
model := u20.dev.Model() | ||
if model.Grade() != asserts.ModelGradeUnset { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should always be true in our case
boot/bootstate20.go
Outdated
model := u20.dev.Model() | ||
if model.Grade() != asserts.ModelGradeUnset { | ||
// reseal if needed | ||
if err := resealKeyToModeenv(model, u20.writeModeenv); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we'll have to think whether to use the fact we have written the modeenv in the if block before as hint to expect or not a reseal, maybe it's useful with unasserted kernel, anyway this can be a follow up
boot/bootstate20.go
Outdated
if model.Grade() != asserts.ModelGradeUnset { | ||
// reseal if needed | ||
if err := resealKeyToModeenv(model, u20.writeModeenv); err != nil { | ||
return fmt.Errorf("cannot reseal encryption key: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be just return err to avoid repetitive errors
boot/boottest/device.go
Outdated
return d.model | ||
} | ||
|
||
func (d *mockDevice) SetModel(model *asserts.Model) { d.model = model } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we discussed this, but in hindsight it's confusing because then Kernel and Base return values get out of sync vs Model. I proposed #9339 instead
boot/seal.go
Outdated
recoveryBootChains, err := recoveryBootChainsForSystems(modeenv.CurrentRecoverySystems, rbl, model, modeenv) | ||
tbl, ok := rbl.(bootloader.TrustedAssetsBootloader) | ||
if !ok { | ||
// nothing to do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made this an internal error now that we know whether we have sealed keys at all or not
boot/seal.go
Outdated
@@ -59,8 +59,13 @@ func sealKeyToModeenv(key secboot.EncryptionKey, model *asserts.Model, modeenv * | |||
if err != nil { | |||
return fmt.Errorf("cannot find the recovery bootloader: %v", err) | |||
} | |||
tbl, ok := rbl.(bootloader.TrustedAssetsBootloader) | |||
if !ok { | |||
// nothing to do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be an internal error I think...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done now
@@ -640,7 +664,9 @@ func genericInitramfsSelectSnap(bs bootState20, modeenv *Modeenv, expectedTrySta | |||
|
|||
// bootState20BootAssets implements the successfulBootState interface for trusted | |||
// boot assets UC20. | |||
type bootState20BootAssets struct{} | |||
type bootState20BootAssets struct { | |||
dev Device |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same about this being something like resealModel
tab.BootChainList = []bootloader.BootFile{ | ||
bootloader.NewBootFile("", "asset", bootloader.RoleRunMode), | ||
// TODO:UC20: fix mocked trusted assets bootloader to actually | ||
// geenerate kernel boot files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this TODO is interesting, we'll have to think how to avoid having the mock code guess
I noew addressed most of my own comments with the changes proposed via #9340 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't get a chance to look at the tests, but the rest of the main code looks good to me
boot/seal.go
Outdated
logger.Debugf("reseal not necessary") | ||
return nil | ||
} | ||
pbcJSON, _ := json.Marshal(pbc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment as on other PR, but why no error checking here?
…eal-with-kernel Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
This test adds checks that resealing happens after the kernel gets updated.
. "$TESTSLIB/nested.sh" | ||
|
||
# Wait for snapd to be seeded | ||
nested_exec sudo snap wait system seed.loaded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
later we can drop this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm assuming we will land #9340 after
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One question about the unit tests in boot, otherwise lgtm
"snap_kernel": s.kern2.Filename(), | ||
"snap_try_kernel": boot.DefaultStatus, | ||
} | ||
c.Assert(tab.BootVars, DeepEquals, expected) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fine for now, but in general I'd like to move away from accessing BootVars directly like this and instead use the GetBootVars method from the Bootloader interface as it makes it easier to make changes to the MockBootloader interface and such
m2, err := boot.ReadModeenv("") | ||
c.Assert(err, IsNil) | ||
c.Assert(m2.CurrentKernels, DeepEquals, []string{s.kern1.Filename(), s.kern2.Filename()}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should check the kernel_status bl var as well here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the run is green, I'll push that in a followup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should get covered in #9340 I suppose
tab.BootChainList = []bootloader.BootFile{ | ||
bootloader.NewBootFile("", "shim", bootloader.RoleRecovery), | ||
bootloader.NewBootFile("", "asset", bootloader.RoleRecovery), | ||
runKernelBf, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is the same as other tests, but it now occurs to me whether this is the right chain for run mode?
I thought with run mode our chain was something like:
recovery shim -> recovery grub -> run grub -> run kernel
or are these tests just being simplistic because it's easier than building the full chain? or perhaps I have again misunderstood how the chain is used when resealing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as discussed on IRC with @pedronis, this is simplistic but it's fine for now, we have more realistic tests in seal_test.go so this is fine for now
Spread run finished, the following failed on core20 nested:
tests/nested/core20/basic which expected test-snapd-sh to be there but looking at the log, snap install command hit a timeout:
And the minimal got the a point where 3 out of 4 tests have already executed successfuly and it got killed (?):
|
kernel-reseal itself passed, merging |
stacked on #9337 now