[RFC] Support for choosing image to boot in runtime
MCUboot assumes that the images being booted live on a flash (or will be loaded to it, in case of serial support) or something that pretends to be a flash. It will usually check version of available images on flash partition slots, and choose the newer one to perform an update, with support to fallback to a previous working image in case the new one fails.
Another use cause for MCUboot, however, is to be able to load an image from an arbitrary source, in fact, not caring about the update facilities. In that case, the application will usually check some hardware straps to decide from which source to get the image to boot.
This RFC PR adds support for such scenarios: it uses single loader to load an image from a set of "sources". The single loader loops through available sources and the first one to succeed signature/validation boots. To access the images, weak functions flash_map_id_get_next() and flash_map_id_get_current() are used. Default implementation keeps current behaviour for single loader, i.e. just loads from FLASH_AREA_IMAGE_PRIMARY(0).
It is expected applications will reimplement these functions, allowing them to define a priority of different sources. As these different storage media may be ready only, MCUboot won't attempt to update them to record last source to succeed or so, it's application responsibility to define the correct priority of sources on every boot.
This PR also moves RAM loading code to its own file, so it's available for single loaders, as well as provide one example of such approach, using two slots on a FRDM-K64F.
While some of the source devices can not be flash devices at all (for instance, image is made available via I2C or eSPI bus), feedback on #2031 supports simply implementing the Flash API for them at Zephyr level, hence this new RFC PR.
Please review - comments and suggestions on how to better achieve this are highly appreciated =D
This is a follow on for #2031.
Any comments? @d3zd3z?
Having a quick read of this description (have not looked at code), I do not think this belongs in MCUboot, it does not deal with firmware updates and deals with selecting which image to boot from a bunch of devices, which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device by manipulating the end product e.g. removing one pin from an external flash device.
I suggest that you create your own bootloader using the MCUboot files by bringing MCUboot in as a module - TF-M does this so can be used as an inspiration for how to do this, or just fork MCUboot into your own bootloader and make changes in that, but I do not envisage this being in MCUboot itself as it really is a separate system you want that does not tie in with MCUboot's fundamentals
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
OK. So an user can choose full security or the ability to unbrick the device or reset it to factory settings.
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
OK. So an user can choose full security or the ability to unbrick the device or reset it to factory settings.
That's what swap using move or directXIP with revert is designed for, you update the application from the application, and check it works before confirming it should stay, the bootloader is a dumb bootloader and just deals with verifying the image, you reduce the attack vector by removing features that are not essential to that and use hardware to enforce those settings, which is what TF-M does with it's MCUboot (called bl2 there) build
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
OK. So an user can choose full security or the ability to unbrick the device or reset it to factory settings.
That's what swap using move or directXIP with revert is designed for, you update the application from the application, and check it works before confirming it should stay, the bootloader is a dumb bootloader and just deals with verifying the image, you reduce the attack vector by removing features that are not essential to that and use hardware to enforce those settings, which is what TF-M does with it's MCUboot (called bl2 there) build
Can we merge TFM bl2 features back to MCUBoot? Of cause, make them configurable,
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
OK. So an user can choose full security or the ability to unbrick the device or reset it to factory settings.
That's what swap using move or directXIP with revert is designed for, you update the application from the application, and check it works before confirming it should stay, the bootloader is a dumb bootloader and just deals with verifying the image, you reduce the attack vector by removing features that are not essential to that and use hardware to enforce those settings, which is what TF-M does with it's MCUboot (called bl2 there) build
Can we merge TFM bl2 features back to MCUBoot? Of cause, make them configurable,
Not sure what you mean, TF-M's bl2 is MCUboot
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
OK. So an user can choose full security or the ability to unbrick the device or reset it to factory settings.
That's what swap using move or directXIP with revert is designed for, you update the application from the application, and check it works before confirming it should stay, the bootloader is a dumb bootloader and just deals with verifying the image, you reduce the attack vector by removing features that are not essential to that and use hardware to enforce those settings, which is what TF-M does with it's MCUboot (called bl2 there) build
Can we merge TFM bl2 features back to MCUBoot? Of cause, make them configurable,
Not sure what you mean, TF-M's bl2 is MCUboot
Not fully, it has own variant: https://github.com/zephyrproject-rtos/trusted-firmware-m/tree/main/bl2
which then adds security issues because downgrades are implicitly allowed and an attacker can therefore boot from a possibly vulnerable device
But MCUBoot has a recovery, with the same security issue ;)
It does, and in no end device to be considered secure should it ever be used
OK. So an user can choose full security or the ability to unbrick the device or reset it to factory settings.
That's what swap using move or directXIP with revert is designed for, you update the application from the application, and check it works before confirming it should stay, the bootloader is a dumb bootloader and just deals with verifying the image, you reduce the attack vector by removing features that are not essential to that and use hardware to enforce those settings, which is what TF-M does with it's MCUboot (called bl2 there) build
Can we merge TFM bl2 features back to MCUBoot? Of cause, make them configurable,
Not sure what you mean, TF-M's bl2 is MCUboot
Not fully, it has own variant: https://github.com/zephyrproject-rtos/trusted-firmware-m/tree/main/bl2
Those are the interface files, which is no different then the boot/zephyr folder in MCUboot, it's the shim layer
I do not think this belongs in MCUboot, it does not deal with firmware updates
mcuboot is a bootloader, no? why using mcuboot does mean you have to do updates? Bootloader can be used for doing many other things, beside updates.
So, to clarify a bit about the purpose of mcuboot. MCUboot really does two things: 1. it validates that the code running in flash has been properly signed, and 2. it performs the last step of an update, the atomic swap of the two images.
The problem is that we need some initial bootloader that is immutable. Because of this, we want it to have as little functionality as possible. It is not, and should never be responsible for getting images from some other location.
So, the question comes down to: what is this change trying to recover from.
MCUboot won't swap or load images that haven't been properly signed. At least some level of testing should be preventing most of the cases of needing any kind of recovery. The revert operation should cover the cases when an image is deployed but is discoverd that it doesn't work on some hardware.
Any case of say power failure during the swap operation causing the device to not properly finish when power is restored should be considered bugs that need to be fixed.
Is there some other scenario where recovery is needed?
Aside from this, additional functionality would be the realm of a second stage bootloader, where this second bootloader would be the image upgraded by mcuboot.
That said, I don't actually find the arguments about security of this to be a concern. Allowing multiple sources of boot images isn't going to be less secure. We already make the assumption that the upgrade slot can be written with arbitrary data, and that is the case with these other slots. The images still have to be signed in order to be run.
One possibly security concern is if we are XIP-ing the code, could the flash be changed after the signature verification. This actually applies even with loading to RAM. Fixing that would require changing the way ram loading works, where it would have to very the signature of the image after it has been loaded into RAM. That might be worth fixing anyway. Ram loading in MCUboot doesn't get a lot of love, as there still are a lot of devices that XIP out of flash.
I've enabled the CI run, which so far is showing a failure in mynewt.
I do not think this belongs in MCUboot, it does not deal with firmware updates
mcuboot is a bootloader, no? why using mcuboot does mean you have to do updates? Bootloader can be used for doing many other things, beside updates.
Using mcuboot without firmware updates is pointless and makes no sense, you would just skip mcuboot entirely and load your application direct to the start of flash.
The problem is that we need some initial bootloader that is immutable. Because of this, we want it to have as little functionality as possible. It is not, and should never be responsible for getting images from some other location.
If it is configurable. It can have any amount of functionality.
[...] I've enabled the CI run, which so far is showing a failure in mynewt.
Thanks for that! I've fixed those!
v2:
- Fix RAM load code separation issues on Zephyr, mynewt and simulator.
- Rebased.
So, to clarify a bit about the purpose of mcuboot. MCUboot really does two things: 1. it validates that the code running in flash has been properly signed, and 2. it performs the last step of an update, the atomic swap of the two images. [...]
That is already not the case when some one uses "single application slot"/"single loader", right? In this case, each MCUboot port (at least Zephyr and mynewt, AFAICT) simply verifies the image and then loads/run it, no swap. This PR simply adds some hooks to Zephyr single loader that make it easier for a MCUboot based bootloader to choose, based on some runtime verification, from which source (a flash partition, as any kind of underlying storage will just pretend it's flash) to load the image to run.
That said, I don't actually find the arguments about security of this to be a concern. Allowing multiple sources of boot images isn't going to be less secure. We already make the assumption that the upgrade slot can be written with arbitrary data, and that is the case with these other slots. The images still have to be signed in order to be run.
One possibly security concern is if we are XIP-ing the code, could the flash be changed after the signature verification. This actually applies even with loading to RAM. Fixing that would require changing the way ram loading works, where it would have to very the signature of the image after it has been loaded into RAM. That might be worth fixing anyway. Ram loading in MCUboot doesn't get a lot of love, as there still are a lot of devices that XIP out of flash. [...]
About the RAM loading, verification is actually done on RAM after loading is done, so this case is already covered. Indeed, the other, and actually bigger, change in this PR is to split the RAM loading code, so that it can be used by single loader (RAM loading code is currently behind the non single loader code path). There's even a part of me that wants to avoid the - possibly - long discussion here, and have another PR just with the RAM loading code split.
Any thoughts, @d3zd3z and @nordicjm?
@nordicjm
Using mcuboot without firmware updates is pointless and makes no sense, you would just skip mcuboot entirely and load your application direct to the start of flash.
This is your view of the world and what bootloader should do. mcuboot is defined as a bootloader with update capabilities, does not mean you have to update anything to use mcuboot. There are different usecases that go beyond your own, so please be inclusive here. If mcuboot is only about updates, then it should not be called a bootloader in the context of zephyr, maybe mcu-updater? in that case we will figure a way to introduce a proper bootloader into zephyr that does more than just updates.
@nordicjm
Using mcuboot without firmware updates is pointless and makes no sense, you would just skip mcuboot entirely and load your application direct to the start of flash.
This is your view of the world and what bootloader should do. mcuboot is defined as a bootloader with update capabilities, does not mean you have to update anything to use mcuboot. There are different usecases that go beyond your own, so please be inclusive here. If mcuboot is only about updates, then it should not be called a bootloader in the context of zephyr, maybe mcu-updater? in that case we will figure a way to introduce a proper bootloader into zephyr that does more than just updates.
I have been using MCUboot as a user since 2018, I have been a MCUboot developer since 2021, so yes I have a very good idea of what this project is, how it works, what the goal of it is and what features it needs to support. Many people use MCUboot and do their own thing with it, the concept introduced here is in my opinion not a good fit for the project, that's not to say it can't be done, it just means you should have it as a fork or patch in your project, as you say when people post modules to zephyr "as an external module", and people do that with MCUboot. We do that in nordic for the nRF connect SDK, people have their own forks where they do things like have the second image as a file on a filesystem (which, again, is not a good fit for a feature to include in MCUboot but there is no reason someone can't take MCUboot, apply the changes they want for it and use that, then pull in fixes from MCUboot to their fork)
what the goal of it is and what features it needs to support. Many people use MCUboot and do their own thing with it, the concept introduced here is in my opinion not a good fit for the project, that's not to say it can't be done, it just means you should have it as a fork or patch in your project, as you say when people post modules to zephyr "as an external module", and people do that with MCUboot. We do that in nordic for the nRF connect SDK, people have their own forks where they do things like have the second image as a file on a filesystem (which, again, is not a good fit for a feature to include in MCUboot but there is no reason someone can't take MCUboot, apply the changes they want for it and use that, then pull in fixes from MCUboot to their fork)
It is pity that others have to spend resources to create and maintain their own forks of MCUBoot, such as the nRD SDK. Where can we find the mentioned goals of the MCUBoot project?
is it really that uncommon to say, have a jumper that lets you load an image from sd, onboard flash, qspi flash, or some other source? It's a fairly common boot rom feature for example on NXP parts, this would enable mimicking that behavior in mcuboot which would be nice and obviously useful for a case we have at Intel
is it really that uncommon to say, have a jumper that lets you load an image from sd, onboard flash, qspi flash, or some other source? It's a fairly common boot rom feature for example on NXP parts, this would enable mimicking that behavior in mcuboot which would be nice and obviously useful for a case we have at Intel
You have that, build in firmware loader mode and use a GPIO for selecting if you boot the primary or secondary image. Multiple boot sources are not and should not be supported (in tree)
Multiple boot sources are not and should not be supported (in tree)
If multiple-boot is configurable, it should be posible. For example, the NXP ROM Secure Bootloaders have this possibility (if it's enabled).
Multiple boot sources are not and should not be supported (in tree)
If multiple-boot is configurable, it should be posible. For example, the NXP ROM Secure Bootloaders have this possibility (if it's enabled).
We're talking about MCUboot, not <insert_name_of_completely_unrelated_project_here>, MCUboot is designed around 1 (single slot mode) or 2 (dual slot mode) slots
So, I don't have a particular problem with the concept of this change, especially if the feature is optional. As long as we document things meaningful, I don't think the security rollback concerns are an issue. We need to document that it is possible, and that if rollback protection is needed, hardware rollback protection will be needed.
But, the change is also fairly large, so I will need to review it.
I do not think this belongs in MCUboot, it does not deal with firmware updates
mcuboot is a bootloader, no? why using mcuboot does mean you have to do updates? Bootloader can be used for doing many other things, beside updates.
Using mcuboot without firmware updates is pointless and makes no sense, you would just skip mcuboot entirely and load your application direct to the start of flash.
Actually I encountered serious request for MCUboot which is only able to verify and run the given content, It was why single loader was added (yes - it was meant to be used without any MCUboot's recovery, FWU was planed to be done by direct memory programing). That's mean that it was requirement for enable only secure-boot by the MCUboot.
Actually I encountered serious request for MCUboot which is only able to verify and run the given content, It was why single loader was added (yes - it was meant to be used without any MCUboot's recovery, FWU was planed to be done by direct memory programing). That's mean that it was requirement for enable only secure-boot by the MCUboot.
This is a quite reasonable request.
The main security issue I see with this prompting for image to run has to do with rollback protection. At least some security requirements require fairly strict adherence to non-rollback, which for mcuboot means HW rollback counters. In that case, selecting an older image to run would not actually allow it to run.
That said, we don't require rollback protection to be enabled (in contrast to SUIT, which I'm not sure if it requires it, does require the counter to be in every image), and this makes sense with out that.
Rebased to use the #2062 now merged into the tree
Please take a look again if you can @nordicjm @nvlsianpu @d3zd3z
Thank you!
Actually I encountered serious request for MCUboot which is only able to verify and run the given content, It was why single loader was added (yes - it was meant to be used without any MCUboot's recovery, FWU was planed to be done by direct memory programing). That's mean that it was requirement for enable only secure-boot by the MCUboot.
This is a quite reasonable request.
The main security issue I see with this prompting for image to run has to do with rollback protection. At least some security requirements require fairly strict adherence to non-rollback, which for mcuboot means HW rollback counters. In that case, selecting an older image to run would not actually allow it to run.
That said, we don't require rollback protection to be enabled (in contrast to SUIT, which I'm not sure if it requires it, does require the counter to be in every image), and this makes sense with out that.
As I understand it, the sample here is only meant to show one possible usage. Some bootloaders, like the ROM bootloader builtin to imxrt for example, allow selecting the image source using gpio pins.
This isn't about running images with rollbacks and such. This is about having multiple sources of images and being able to select which one to boot from.
This does not belong in MCUboot to me, this should be implemented as a custom hook in an application or module, I cannot approve it.