-
Notifications
You must be signed in to change notification settings - Fork 2
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
Implement a caboose EPOC
tag used by RoT update_server for rollback protection
#33
base: main
Are you sure you want to change the base?
Conversation
hubtools/src/lib.rs
Outdated
// Hubris has an epoch in the app.toml but Bootleby does not. | ||
// CLI arg overrides app.toml, value will default to zero. | ||
let epoc: u32 = if let Some(param) = epoch { | ||
param.parse::<u32>().map_err(|_| Error::InvalidEpoch(param.to_string()))? | ||
} else if let Some(param) = manifest.as_table().ok_or(Error::BadTomlType)?.get("epoch") { | ||
let toml_int = param.as_integer().ok_or(Error::BadTomlType)?; | ||
u32::try_from(toml_int).map_err(|_| Error::InvalidEpoch(format!("epoch from toml = {}", toml_int)))? | ||
} else { | ||
// Default is zero if missing from app.toml | ||
0u32 | ||
}; | ||
// EPOC in the caboose is a u32, zero-padded 10-digit ascii number. | ||
// Missing EPOC or all-zeros is equivalent to EPOC zero. | ||
// Anything else represents some future scheme or a typo in toml file. | ||
let caboose_epoc = format!("{:010}", epoc).to_owned(); |
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.
The epoch was added in the app.toml as a random thought. Is there value in keeping it there vs getting surprised later?
I'm also not a huge fan of the parsing then re-formatting. I'd rather require the user to specify the epoch exactly and then reject it if it isn't in the expected form
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 have the line "epoch = 0" in app.toml files which Toml returns as an i64.
I could remove the leading ASCII zeros. I had thought originally to compare EPOC byte by byte, but I wound up converting to u32 to stay consistent with ImageHeader's representation.
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.
Re: "The epoch was added in app.toml as a random thought..."
The ImageHeader version
isn't expected to be used, but the epoch
field has a very nice property for rollback protection: it is available to update_server
before any flash is erased.
This allows us to reject updates early and keeps us from wearing out flash if some person or process keeps retrying because they don't understand that rollback protection is keeping the update from being applied.
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 think about our release flow. We manage version strings manually and epoch could be the same.
That is very helpful for SP hubris which is compiled differently for the different target boards. We might have some dangerous PSC SP release that we want to ban with rollback protection. We would increment epoch there but wouldn't have to for the other platforms. Using the app.toml to track epoch works there because of the different app.toml files per target.
We don't have an app.toml for bootleby. I would like to find a git-controlled place to put it though.
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 currently build a minimal fake app.toml under hubtools/bootleby.rs
. How about adding an --epoch
flag to package-elf
and adding the epoch
to the fake toml? We could commit the epoch to our release build scripts that way.
I'd actually like to see about committing the version string and tag to git to make releases even less prone (the only runtime check would be the expected hash of the output) so we could also do the epoch there.
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.
Managing the version string for releases needs more discussion.
We could put a json file in sprot-release that binds (repo, commit, version) or (repo, commit, version, epoch).
But that source of truth is redundant with artifacts that permslip stores. We could call it a release plan.
We could just store the version to be used.
We could aromatically query production permslip on the next available major or minor version.
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.
Added optional --epoch u32
to --package-elf
as you suggested.
38c7a22
to
0f8d3cf
Compare
@@ -93,6 +98,8 @@ pub enum Command { | |||
board: String, | |||
/// Git has for the hubris archive | |||
gitc: String, | |||
/// Epoch for rollback protection | |||
epoch: Option<u32>, |
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 this be optional here, or should it be a bare u32
(with responsibility for deciding on a default value given to the caller)?
hubedit/src/main.rs
Outdated
@@ -33,6 +33,9 @@ pub enum Command { | |||
#[clap(short, long)] | |||
version: String, | |||
|
|||
#[clap(short, long)] | |||
epoch: Option<String>, |
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.
Option<u32>
?
Should this be optional at all, or should it be mandatory (like version
)?
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'd like to change this to mandatory after changes to sprot-release
procedures implement reviewable release plans.
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.
...that will probably be worked into sprot-release
PR#11 or a follow-on.
Thinking about it last night, I feel like there's a missing design doc / RFD here that to explain implementation choices. RFD 349 mentions using epochs for rollback protection, but doesn't dive into the details. Not understanding the overall design means that it's hard to review the individual implementation PRs. Here's a set of questions that I've come up with, which would better be answered by a RFD describing the implementation plan:
|
I think this capturing that much of the release engineering for hubris/bootleby up until now has been a bit ad-hoc and grown as needed and as someone who has done this perhaps a bit too ad hoc I think it's worth treating this as a good checkpoint to write this down and make sure we're doing things the correct way. |
let header = header::ImageHeader { | ||
magic: 0x64_CE_D6_CA, | ||
total_image_len: len as u32, | ||
}; |
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 was an intentional choice when this was added to only add the magic and length fields to save space. It feels like a step in the wrong direction to add the full header back.
Bump hubtools version for EPOC tag in caboose Default epoch value is zero if not otherwise specified. Command line --epoch option. Work with the epoch value as a u32. Do not use ImageHeader epoch field.
Issue #31