-
Notifications
You must be signed in to change notification settings - Fork 5
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
Implemented artifact integrity checks #89
base: main
Are you sure you want to change the base?
Conversation
There was an error running your pipeline, see logs for details. |
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.
Looks good to me otherwise. Thanks for splitting the work in such nice and small commits! ❤️ 🍻
@@ -990,24 +990,26 @@ mender_client_update_work_function(void) { | |||
/* Get artifact context if artifact download succeeded */ | |||
if ((NULL != mender_update_module) && (MENDER_OK == (ret = mender_artifact_get_ctx(&mender_artifact_ctx)))) { | |||
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT | |||
if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) { | |||
if (MENDER_OK == (ret = mender_artifact_check_integrity(mender_artifact_ctx))) { | |||
if (MENDER_OK == (ret = mender_check_artifact_requirements(mender_artifact_ctx, deployment))) { |
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 feel like those two should be in a single function, a new one I guess.
|
||
for (char *ch = strstr(filename, ".tar"); *ch != '\0'; ch++) { | ||
/* Don't worry! The call to strlen() on a static string should | ||
* be optimized out by the compiler */ |
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.
😁 👍
f9b7064
to
0c12ac1
Compare
Ticket: MEN-7483 Changelog: None Signed-off-by: Lars Erik Wik <[email protected]>
Ticket: None Changelog: None Signed-off-by: Lars Erik Wik <[email protected]>
Ticket: None Changelog: None Signed-off-by: Lars Erik Wik <[email protected]>
The client now performs integrity checks on the version file in the artifact by comparing its computed checksum to the one in the artifact manifest. Ticket: MEN-7483 Changelog: Commit Signed-off-by: Lars Erik Wik <[email protected]>
The client now performs integrity checks on the header.tar file in the artifact by comparing its computed checksum to the one in the artifact manifest. Ticket: MEN-7483 Changelog: Commit Signed-off-by: Lars Erik Wik <[email protected]>
Added logging of mismatching checksums during artifact integrity checks in debug mode. Ticket: None Changelog: None Signed-off-by: Lars Erik Wik <[email protected]>
The client now performs integrity checks on the data files in the artifact by comparing its computed checksum to the one in the artifact manifest. Ticket: MEN-7483 Changelog: Commit Signed-off-by: Lars Erik Wik <[email protected]>
Merging these commits will result in the following changelog entries: Changelogsmender-mcu (sha256)New changes in mender-mcu since main: Features
|
Thanks for the thorough review @vpodzime. I will follow up on ^^ in a separate commit 🍻 |
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.
Great work 🚀
See my comments below. Nothing really big but some discussions will be needed.
Before my final approval, I will now compile your work locally and try few things as I suspect another bug when parsing multiple files.
} | ||
|
||
mbedtls_sha256_init(ctx); | ||
mbedtls_sha256_starts(ctx, 0); /* Use SHA-256, not SHA-224 */ |
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.
Check return code
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 version of MbedTLS we compile with returns void
for all of these functions.
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 is not the case.
Zephyr v3.7.0
comes with mbedtls revision 2f24831ee13d399ce019c4632b0bcd440a713f7c
👉 you can see this both in the manifest file and from your local workspace with cd modules/crypto/mbedtls/ && git log
. Maybe you are using an untracked version of it? Or what am I missing?
assert(NULL != context); | ||
|
||
mbedtls_sha256_context *ctx = context; | ||
mbedtls_sha256_update(ctx, input, length); |
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.
Check return code here too
mbedtls_sha256_context *ctx = context; | ||
if (NULL != ctx) { | ||
if (NULL != output) { | ||
mbedtls_sha256_finish(ctx, output); |
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.
And here 🫠
if (NULL != ctx) { | ||
if (NULL != output) { |
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 these two should be assert
instead. Otherwise we are just returning MENDER_OK
while really doing nothing.
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.
See doc string in the declaration ;)
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.
Yes, but why would we allow this use case?
/* See if we already have an entry for this file */ | ||
mender_artifact_checksum_t *checksum; | ||
for (checksum = ctx->artifact_info.checksums; NULL != checksum; checksum = checksum->next) { | ||
if (StringEqual(checksum->filename, 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.
I am not sure about using the filename as unique ID.
A tar archive does not guarantee uniqueness of filenames, so in theory we could have more than entry with same filename but different checksum. Our mender-artifact
cli tool however will prevent this to happen, so we are only talking about a manually crafted Artifact or a 3rd party tool creating the Artifact.
Can you elaborate on the motivation? Can't we use good old indexes? It is a list after all.
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 goal is to compare the computed checksums to those in the manifest. The manifest contains pairs of checksums and a filenames. No reference to indexes. So I'm not sure how we could do this without changing the artifact format.
checksum->next = ctx->artifact_info.checksums; | ||
ctx->artifact_info.checksums = checksum; | ||
|
||
/* Start SHA-256 checksum computation (if not already started) */ |
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.
What do you mean with "if not already started"? At this point it is starting it unconditionally
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.
Good catch! It's some leftovers from an earlier iteration of trying to get this thing to work. I will remove the last part ;)
|
||
/* Start SHA-256 checksum computation (if not already started) */ | ||
if (MENDER_OK != mender_sha256_begin(&(checksum->context))) { | ||
mender_log_error("Failed to start checksum"); |
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.
... for entry %s, filename
|
||
/* Populate with manifest checksum */ | ||
for (int i = 0; i < MENDER_DIGEST_BUFFER_SIZE; i++) { | ||
if (1 != sscanf(checksum_str + (2 * i), "%02hhx", checksum->manifest + i)) { |
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.
Won't we hit the same problems with sscanf
on ESP32?
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.
Worked on my machine 😉 I used the ESP32-S3-DevKitC. Could be that it is only buggy for some format specifiers. Can you try on the ESP32-Ethernet-Kit?
if (!StringEqual(checksum->filename, "version") && !StringEqual(checksum->filename, "header.tar") | ||
&& !mender_utils_strbeginwith(checksum->filename, "data/")) { | ||
/* Whenever we introduce a new file to the artifact manifest, we | ||
* need to skip integrity checks for that file until it's | ||
* implemented. Otherwise, the client will get stuck trying to | ||
* install the artifact which may hold the new implementation. */ | ||
mender_log_warning("Skipping integrity check for artifact file '%s': Not implemented", checksum->filename); | ||
continue; | ||
} |
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 sounds insecure to me, why will it get "stuck"?
If we introduce new fields in the manifest, we will in order do
- Update Artifact format specification, likely publishing a new version
- Implement the changes in the client for the new spec.
- Assume the client is updated if you are sending a Artifact with the new spec
All in all I think we should gracefully fail the deployment. On a breaking change like this, the mender-artifact tool will provide a way to produce "legacy Artifacts" so that you can update your devices in the field to newer clients before sending new Artifacts.
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.
Let's discuss this 😄2😄 on Monday with a ☕
This was a bit harder than I first anticipated. Enjoy 🍿🍻
Also tested without full artifact parsing