mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-04 20:05:25 +02:00
bootloader: Add support of anti-rollback
Added: * set a secure version in app/bootloader. * description anti-rollback to ota part * emulate the secure_version write and read operations * efuse_em partition. * a description about a rollback for native_ota_example. Closes: TW26335
This commit is contained in:
@@ -121,6 +121,74 @@ A brief description of where the states are set:
|
||||
* ``ESP_OTA_IMG_ABORTED`` state is set if there was no confirmation of the application operability and occurs reboots (if :ref:`CONFIG_APP_ROLLBACK_ENABLE` option is enabled).
|
||||
* ``ESP_OTA_IMG_PENDING_VERIFY`` state is set in a bootloader if :ref:`CONFIG_APP_ROLLBACK_ENABLE` option is enabled and selected app has ``ESP_OTA_IMG_NEW`` state.
|
||||
|
||||
.. _anti-rollback:
|
||||
|
||||
Anti-rollback
|
||||
-------------
|
||||
|
||||
Anti-rollback prevents rollback to application with security version lower than one programmed in eFuse of chip.
|
||||
|
||||
This function works if set :ref:`CONFIG_APP_ANTI_ROLLBACK` option. In the bootloader, when selecting a bootable application, an additional security version check is added which is on the chip and in the application image. The version in the bootable firmware must be greater than or equal to the version in the chip.
|
||||
|
||||
|
||||
:ref:`CONFIG_APP_ANTI_ROLLBACK` and :ref:`CONFIG_APP_ROLLBACK_ENABLE` options are used together. In this case, rollback is possible only on the security version which is equal or higher than the version in the chip.
|
||||
|
||||
|
||||
A typical anti-rollback scheme is
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- New firmware released with the elimination of vulnerabilities with the previous version of security.
|
||||
- After the developer makes sure that this firmware is working. He can increase the security version and release a new firmware.
|
||||
- Download new application.
|
||||
- To make it bootable, run the function :cpp:func:`esp_ota_set_boot_partition`. If the security version of the new application is smaller than the version in the chip, the new application will be erased. Update to new firmware is not possible.
|
||||
- Reboot.
|
||||
- In the bootloader, an application with a security version greater than or equal to the version in the chip will be selected. If otadata is in the initial state, and one firmware was loaded via a serial channel, whose secure version is higher than the chip, then the secure version of efuse will be immediately updated in the bootloader.
|
||||
- New application booted. Then the application should perform diagnostics of the operation and if it is completed successfully, you should call :cpp:func:`esp_ota_mark_app_valid_cancel_rollback` function to mark the running application with the ``ESP_OTA_IMG_VALID`` state and update the secure version on chip. Note that if was called :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` function a rollback may not happend due to the device may not have any bootable apps then it will return ``ESP_ERR_OTA_ROLLBACK_FAILED`` error and stay in the ``ESP_OTA_IMG_PENDING_VERIFY`` state.
|
||||
- The next update of app is possible if a running app is in the ``ESP_OTA_IMG_VALID`` state.
|
||||
|
||||
Recommendation:
|
||||
|
||||
If you want to avoid the download/erase overhead in case of the app from the server has security version lower then running app you have to get ``new_app_info.secure_version`` from the first package of an image and compare it with the secure version of efuse. Use ``esp_efuse_check_secure_version(new_app_info.secure_version)`` function if it is true then continue downloading otherwise abort.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
....
|
||||
bool image_header_was_checked = false;
|
||||
while (1) {
|
||||
int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);
|
||||
...
|
||||
if (data_read > 0) {
|
||||
if (image_header_was_checked == false) {
|
||||
esp_app_desc_t new_app_info;
|
||||
if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
|
||||
// check current version with downloading
|
||||
if (esp_efuse_check_secure_version(new_app_info.secure_version) == false) {
|
||||
ESP_LOGE(TAG, "This a new app can not be downloaded due to a secure version is lower than stored in efuse.");
|
||||
http_cleanup(client);
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
image_header_was_checked = true;
|
||||
|
||||
esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
|
||||
}
|
||||
}
|
||||
esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
|
||||
}
|
||||
}
|
||||
...
|
||||
|
||||
Restrictions:
|
||||
|
||||
- The number of bits in the ``secure_version`` field is limited to 32 bits. This means that only 32 times you can do an anti-rollback. You can reduce the length of this efuse field use :ref:`CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD` option.
|
||||
- Anti-rollback only works if the encoding scheme for efuse is set to ``NONE``.
|
||||
- The partition table should not have a factory partition, only two of the app.
|
||||
|
||||
``security_version``:
|
||||
|
||||
- In application image it is stored in ``esp_app_desc`` structure. The number is set :ref:`CONFIG_APP_SECURE_VERSION`.
|
||||
- In ESP32 it is stored in efuse ``EFUSE_BLK3_RDATA4_REG``. (when a eFuse bit is programmed to 1, it can never be reverted to 0). The number of bits set in this register is the ``security_version`` from app.
|
||||
|
||||
.. _secure-ota-updates:
|
||||
|
||||
Secure OTA Updates Without Secure boot
|
||||
|
||||
Reference in New Issue
Block a user