When image is slot 1 had bad signature, the swap would fail and
try to write image_ok in slot 0 which if that was already a
permanent image would cause a overwrite in flash.
Fix warning/error when slot 0 validation is not enabled.
Signed-off-by: Fabio Utzig <utzig@apache.org>
After a swap operation is finished trailer control flags are written
according to the type of swap that was performed. The function names
that execute those operations were renamed to explicity reflect what
they do, and all "less deterministic" behaviors, of the type
"if flash is not set, set it", were removed.
Signed-off-by: Fabio Utzig <utzig@apache.org>
This adds handling of the copy_done bit while evaluation a swap state.
Since copy_done is only ever written when a swap finishes, it can be
safely assumed that if copy_done is not set no swap was ever performed
and the image was written directly to flash, and thus no revert is run.
Signed-off-by: Fabio Utzig <utzig@apache.org>
This reworks much of the code, as well as tables, handling swap
state to make them simpler. Only states that require an actual
swap to be performed, perm/test/revert are checked for and acted
upon. Other possible states try to default to no operation
performed.
One extra state, BOOT_SWAP_TYPE_PANIC, was added to differentiate
between "soft" errors and unrecoverable ones (as flash read/write
errors).
Non well defined state changes after swap failures, as described
in MCUB-59 were also clean up.
This should also fix situations as described in MCUB-63, where
images generated using imgtool (magic + image_ok set) are written
to slot 0 and cause an incorrect "revert".
Signed-off-by: Fabio Utzig <utzig@apache.org>
The MCUBOOT_VALIDATE_SLOT0 feature only verifies the signature when
there is no swapping happening. The assumption was that if there is a
swap being done, the code will verify the signature of slot 1 before
doing the slot.
However, either due to bugs, or intentional trickery, it may be possible
to confuse the code into continuing a swap operation. If the data is
modified before this, the bootloader can be tricked into booting the
resulting image in slot 0 without having verified the signature.
Fix this by always verifying slot 0's signature before booting it.
JIRA: MCUB-64
Signed-off-by: David Brown <david.brown@linaro.org>
This implements changes according to MCUB-14, easing the process
of making external apps parse and read/write the trailer.
Signed-off-by: Fabio Utzig <utzig@apache.org>
For mynewt flash map only accepts values for slot 0 and 1. This
code was trying to read the image header on the scratch area using
the same interface and was segfaulting when slot0 and slot1 had
similarly sized images.
Signed-off-by: Fabio Utzig <utzig@apache.org>
This error was catched by Coverity and it happens when a fail occurs
opening a flash map handle, which is not checked by the close
routine.
Right now this only affects Zephyr, but extra checking was added
assuming that in a future Mynewt implementation close could actually
be changed to do something.
Signed-off-by: Fabio Utzig <utzig@apache.org>
Use flash_device_base() in the boot code to compute a real address,
given the offset returned by boot_go().
Provide an implementation on mynewt that preserves existing
behavior. If mynewt needs to support devices with nonzero flash base
addresses, this can be migrated to the core OS.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Similarly, it's confusing whether br_flash_id is a flash device ID or
a flash area ID. Make this unambiguous.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
The boot response returns a flash offset, not a flash address. This is
causing confusion and leading to crashes on some platforms which don't
have flash at address 0.
Rename the field to make it more clear what its purpose is; future
patches can start fixing up usages.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Add a typedef which lets us use flash_sector or flash_area to contain
the sectors within the boot_data global. When
MCUBOOT_USE_FLASH_AREA_GET_SECTORS is defined, this is struct
flash_sector.
Also add struct boot_loader_state accessors to handle this case, and
make the appropriate changes to where the sectors are allocated to use
the new typedef.
Finally, ensure MCUBOOT_USE_FLASH_AREA_GET_SECTORS is defined in the
Zephyr Makefile, since flash_area_get_sectors() is already provided
there.
This lets mcuboot users convert to the new flash API gradually.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Move helpers which are needed for using flash_area_to_sectors() to the
end of file. This is just to keep things clean when we add support for
flash_area_get_sectors().
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Keep both image areas and the scratch area open while we are
bootloading. This fixes up a hack and will make it easier to use
flash_area_get_sectors() later.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Add abstractions for calculating the starting offset of a sector from
the beginning of its image, and the starting offset of an image slot
from the beginning of its flash device.
Using this tweaks a check in boot_swap_sectors(), but doesn't change
its outcome.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Add an abstraction for initializing bootloader state for a particular
flash area.
For now, we preserve some existing hacky behavior related to the
scratch area. This will get cleaned up more later in the series.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Taking the opportunity to move some signed integers over to unsigned
size_t as we go. (Depending on compiler settings, signed / unsigned
comparisons can generate warnings, so it's nice to use the signedness
we mean when possible).
Having boot_img_set_num_sectors() is just an intermediate step; this
gets cleaned up as we go forward.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
This begins some preparatory work to using flash_area_get_sectors() in
loader.c. Subsequent commits will add and use additional accessors for
the contents of this struct.
Making the struct contents opaque will allow it to contain struct
flash_area or struct flash_sector values in its sectors field. This
will allow use of either flash_area_get_sectors() or the
now-deprecated flash_area_to_sectors().
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Allow the size of bignums in mbed TLS to be configured larger than
needed for RSA2048. This will waste memory holding the large numbers,
but will still work.
The PKCS#1 standards, which define RSA signatures, are currently at
version 2.2. Starting in v2.1, the standard defines a new signature
method RSA-PSS, which has a stronger security proof than the signature
method used in earlier versions. The standard recommends that RSA-PSS
be used in new designs, instead of the older algorithm.
This patch implements RSA-PSS verification for a specific set of
parameters:
- RSA-2048
- SHA256 for both the message digest and the internal hash
- 32-byte salt
- 2047 bit message
Although RSA-PSS supports other parameters, due to size constraints,
this verificatino code only supports these specific parameters, and
signatures with other parameters will be considered invalid.
To encourage the use of the more secure algorithm, the default build
configuration is RSA-PSS. BOOTUTIL_RSA_PKCS1_15 needs to be defined in
order to support the older signature algorithm.
Remove most of mynewt specific stuff to a separate port package. This
should make mcuboot less "mynewt'y" and slightly easier to port to.
- Mynewt specific stuff moved to boot/mynewt.
- Sample app moved from apps/boot to boot/mynewt.
- Use MYNEWT_VAL macro only on mynewt port.
- BOOTUTIL_* and MYNEWT_VAL() usage moved to MCUBOOT_ defines.
Before this patch, the swapping would process all sectors in a slot
not matter what the size of the binary firmware was. This changes the
swap process to swap only sectors that are in use by firmware.
Also, if the last slot sector, which stores the trailer, is actually not
in use by the binary firmware, now trailer is never written to scratch.
`use_scratch` temp variable was added to boot_status struct to control
this (this var is never written to disk).
Random other small refactorings were applied.
Before this change, trailer was handled as part of the binary image,
which during a swap was just copied around together with the image.
This had issues if some fault happened while the trailer copy was
underway.
This patch changes how trailer is handled by making by non-copying.
The trailer is now updated step-by-step based on the current status.
Magic, copy_done and image_ok are also handled by writing them
individually, not by copying.
The trailer on scratch area was reduced to include at most swap state for
one sector, since it is only used temporarily while erasing the last
sector of the slot that stores the final trailer.
Many other small fixes were applied.
In order to allow messages to be printed, set the compiled level to
INFO. This allows messages at this level to be printed without having
to recompile.
Change the C logging code, when in the simulator, to query what the rust
logging level is set to. This allows the level of logging from the C
code to be set through the environment. For example
RUST_LOG=bootsim=info cargo run --release runall
will enable logging at the "info" level for all of the C code as well as
the simulator code. The C code's logging can be selected specifically
by using bootsim::api instead of just bootsim in the above.
Add a configuration option "BOOTUTIL_OVERWRITE_ONLY" that avoids using
the image swap code. Instead, when an upgrade is detected in slot 1, it
is copied directly onto slot 0. As long as the image in slot 1 is
valid, this should work robustly (it will redo it if power is lost
during the upgrade).
This doesn't protect against the case of deploying an image that fails
to boot on some devices. But, the behavior is similar to the swap
upgrade approach when the slot 1 image is marked initially as "image
ok", but without the complexity (or need of a swap partition) of the
swap code.
Add a simple function to query the bootloader for capabilities.
Ultimately, this API should be available to the running app, but the
simulator can use this to determine what to test.
Instead of a separate invocation of printf to print the trailing
newline, use some modern cpp trickery to expand the format string
explicitly. The ## will remove the preceding comma of the argument list
if empty.
Add logging support for when running in the simulator. Log messages are
still based on compile-time determinations, and log using printf.
Based on a patch from Marti Bolivar <marti.bolivar@linaro.org>.
When building with ECDSA P-256 as the signature algorithm, we are still
bringing in SHA256 and some ASN.1 code from mbed TLS. Fix part of this
by wrapping the hash functions with general routines (inline functions)
allowing to select between mbed TLS and Tinycrypt for the
implementation.
Update the Zephyr config files so that the Tinycrypt version is used
when building the ECDSA P-256 signing variant.
There are some problems with how mbed TLS is configured in Zephyr.
First, include the makefile stub in the Makefile that uses these
defines. This makes sure the right definitions get made so that our
custom config gets used for all compiled files, rather than a mixed set.
Also, fix up the wrappers on the custom configs so that each is
different, making it easier to detect if multiple configs are being
included.
Lastly, only include the right header in the image validation. The mbed
TLS includes don't seem to want to allow both RSA and ECDSA to be used
(due to the key size), and including the wrong header results in a
compilation error.
Previously, the return of boot_swap_sectors() was discarded. If a flash
operation failed, this information was lost.
Now, boot_swap_sectors() returns void. Rather than returning a result,
success is asserted for all flash operations during function execution
(boot_copy_sector() and boot_erase_sector()).
commit d930ec69c8
Author: David Brown <david.brown@linaro.org>
Date: Wed Dec 14 07:59:48 2016 -0700
Validate slot zero before booting
adds a feature to validate slot 0 before booting it. However, there
is an error in the logic, and if the magic number is written to an
invalid value, but not all 0xFF, it will consider any image to be
valid.
Fix this logic so that slot zero is always validated.
Use the bootutil_log.h APIs to log the boot source chosen by the
loader, as well as the image trailer state that led it to its
conclusion.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
This patch adds platform-independent logging to bootutil.
When bootutil is compiled as part of an application, the
application environment can provide logging hooks using this
file. Initially, hooks for Zephyr are provided. When built for
simulation or unit testing, the logging macros produce no
code (the ignore.h used by mynewt is used to avoid unused
variable warnings in this case).
Before including this file, users may define BOOT_LOG_LEVEL. If
they do, it must be one of BOOT_LOG_LEVEL_OFF,
BOOT_LOG_LEVEL_ERROR, ..., BOOT_LOG_LEVEL_DEBUG. This determines
the log level for the current translation unit. If they do not, a
default log level is determined in a target-specific way.
After including bootutil_log.h, the macros BOOT_LOG_ERR(),
BOOT_LOG_WRN(), etc. may be used to log messages. These take
printf-like arguments.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
Make it clear in the top-level Makefile how to configure mcuboot for
Zephyr for a particular signing algorithm. Currently supported, are the
RSA signatures, and ECDSA with the P-256 curve. These configuration
lines will select the code built in the bootloader, as well as which
public key gets included with the image.
This also adds a demo public key for the P-256 signatures.
Instead of just checking the upgrade image signature, check the
signature on each boot. This helps to prevent rogue images being flash
by a means other than the upgrade process.
This feature is controlled by whether BOOTUTIL_VALIDATE_SLOT0 is
defined.
The ECDSA signature is written as two DER-encoded INTEGERS. Although
the values are always 256 bits, the encoding ends up being variable
length, because the encoding is signed, and therefore needs an extra
zero byte to keep the number positive. This means that the length can
vary by up to two bytes.
The 'newt' tool handles this for signature by allowing space for the
largest encoding, and padding with one or two zeros. However, the
bootutil image check code insists that the length is exact, resulting in
a decoding error on about 3/4 signatures.
Fix this by only verifying that we have at least enough payload to hold
the signature. There are later checks that will fail if the integers
themselves are too large.
Some flash devices not only require writes to occur on an `align` byte
boundary, but also require that the writes be done in chunks of this
size as well. Enhance the sections that write status bytes to write
more than a single status byte.
This reverts commit 920fc16b89.
The boot loader records its current state in the form of a pair of image
trailers, each located at the end of the corresponding image slot. If
an image is so big that it extends into the trailer space of a slot, the
boot loader would read the end of the image and interpet it as the start
of a trailer. The fix was to determine the size of each image upfront
by reading their headers, and only attempt to read an image's trailer if
the image is small enough that it doesn't extend into the trailer space.
If an image is too big to allow for a trailer, the boot loader fails
over to its "rescue mode": just boot into whatever is in slot 0.
The problem arises when the boot loader reads the image headers. There
are certain points during a swap when an image header is not in the
expected location. That is, if the device reboots at the wrong time
during an image swap, the boot loader will fail to read the image
headers when it comes up.
The image sectors are swapped in reverse order. When a swap is
performed, the final sectors of each slot are swapped first, and the
first sectors (containing the image headers) get swapped last. During
the final swap operation, there are two points at which the image
headers are not in the expected place:
1. slot 1 erased; header 1 in scratch area.
2. slot 0 erased; header 0 in scratch area.
In each case, the image header is not actually missing. Rather, the
boot loader is just looking in the wrong place. It should be looking in
the scratch area, not the start of the image slot.
The fix is to revert the original commit. Now, the boot loader won't
fail when an image header read fails. It is the user's responsibility
to ensure an image isn't too big.
The previous commit for this ticket left the code in a working state.
However, it was not possible for image management to distinguish between
the test and permanent states.
Now, these two states are indicated by the addition of a new swap type:
BOOT_SWAP_TYPE_PERMANENT.
Currently, to permanently run the alternate image, the boot loader
requires the following sequence:
1. image test <slot-01-hash>
2. reboot
3. image confirm
The new feature is to remove the need for the third step. The user
should be able to permanently switch images with this sequence:
1. image confirm <slot-01-hash>
2. reboot