coredump: core dump data check can now be parametrized

Core dump integrity check can now be parametrized through menuconfig.
It can be performed on boot or ignored. When core dump is activated
in the menuconfig, the user can still check the core dump at any time
with the function `esp_core_dump_image_check()`.

Fix a bug where `esp_core_dump_image_get()` was not accessible
when core dump was disabled.

Closes https://github.com/espressif/esp-idf/issues/6620
This commit is contained in:
Omar Chebib 2021-03-03 19:39:04 +08:00
parent 9d649505bc
commit 837629814f
3 changed files with 126 additions and 52 deletions

View File

@ -48,6 +48,14 @@ menu "Core dump"
depends on ESP_COREDUMP_DATA_FORMAT_ELF && IDF_TARGET_ESP32
endchoice
config ESP_COREDUMP_CHECK_BOOT
bool "Check core dump data integrity on boot"
default y
depends on ESP_COREDUMP_ENABLE_TO_FLASH
help
When enabled, if any data are found on the flash core dump partition,
they will be checked by calculating their checksum.
config ESP_COREDUMP_ENABLE
bool
default F

View File

@ -104,6 +104,19 @@ void esp_core_dump_to_uart(panic_info_t *info);
/*********************************** USER MODE API ************************************/
/**************************************************************************************/
/**
* @brief Check integrity of coredump data in flash.
* This function reads the coredump data while calculating their checksum. If it
* doesn't match the checksum written on flash, it means data are corrupted,
* an error will be returned. Else, ESP_OK is returned.
*
* @return `ESP_OK` if core dump is present and valid, `ESP_ERR_NOT_FOUND` if no core dump
* is stored in the partition, `ESP_ERR_INVALID_SIZE` or `ESP_ERR_INVALID_CRC`
* if the core dump is corrupted, other errors when unable to access flash, in that
* case please refer to \see esp_err_t
*/
esp_err_t esp_core_dump_image_check(void);
/**
* @brief Retrieves address and size of coredump data in flash.
* This function is always available, even when core dump is disabled in menuconfig.

View File

@ -59,6 +59,9 @@ static core_dump_flash_config_t s_core_flash_config;
#define ESP_COREDUMP_FLASH_ERASE(_off_, _len_) esp_flash_erase_region(esp_flash_default_chip, _off_, _len_)
#endif
esp_err_t esp_core_dump_image_check(void);
static esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size);
static esp_err_t esp_core_dump_flash_custom_write(uint32_t address, const void *buffer, uint32_t length)
{
esp_err_t err = ESP_OK;
@ -72,8 +75,6 @@ static esp_err_t esp_core_dump_flash_custom_write(uint32_t address, const void *
return err;
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void)
{
return esp_rom_crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition));
@ -304,6 +305,7 @@ static esp_err_t esp_core_dump_flash_write_end(core_dump_write_data_t* priv)
}
wr_data->off += cs_len;
ESP_COREDUMP_LOGI("Write end offset 0x%x, check sum length %d", wr_data->off, cs_len);
return err;
}
@ -343,19 +345,26 @@ void esp_core_dump_to_flash(panic_info_t *info)
void esp_core_dump_init(void)
{
size_t core_data_sz = 0;
size_t core_data_addr = 0;
esp_core_dump_flash_init();
if (esp_core_dump_image_get(&core_data_addr, &core_data_sz) == ESP_OK && core_data_sz > 0) {
ESP_COREDUMP_LOGI("Found core dump %d bytes in flash @ 0x%x", core_data_sz, core_data_addr);
#if CONFIG_ESP_COREDUMP_CHECK_BOOT
const esp_partition_t *partition = 0;
uint32_t size = 0;
if (esp_core_dump_image_check() == ESP_OK
&& esp_core_dump_partition_and_size_get(&partition, &size) == ESP_OK) {
ESP_COREDUMP_LOGI("Found core dump %d bytes in flash @ 0x%x", size, partition->address);
}
#endif
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
esp_err_t esp_core_dump_image_check(void)
{
esp_err_t err = ESP_OK;
const esp_partition_t *core_part = NULL;
core_dump_write_data_t wr_data = { 0 };
uint32_t size = 0;
uint32_t total_size = 0;
uint32_t offset = 0;
const uint32_t checksum_size = esp_core_dump_checksum_size();
core_dump_checksum_bytes checksum_calc = NULL;
@ -366,51 +375,15 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
/* Assert that we won't have any problems with our checksum size. */
ESP_COREDUMP_DEBUG_ASSERT(checksum_size <= COREDUMP_CHECKSUM_MAX_LEN);
/* Check the validity of the parameters. */
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Find the partition that could potentially contain a (previous) core dump. */
const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (!core_part) {
ESP_LOGE(TAG, "No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_LOGE(TAG, "Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
/* The partition has been found, get its first uint32_t value, which
* describes the core dump file size. */
err = esp_partition_read(core_part, 0, &size, sizeof(uint32_t));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read core dump data size (%d)!", err);
return err;
}
/* Verify that the size read from the flash is not corrupted. */
if (size == BLANK_COREDUMP_SIZE) {
ESP_LOGD(TAG, "Coredump not found, blank core dump partition!");
err = ESP_ERR_NOT_FOUND;
} else if ((size < sizeof(uint32_t)) || (size > core_part->size)) {
ESP_LOGE(TAG, "Incorrect size of core dump image: %d", size);
err = ESP_ERR_INVALID_SIZE;
}
/* Retrieve the partition and size. */
err = esp_core_dump_partition_and_size_get(&core_part, &total_size);
if (err != ESP_OK) {
return err;
}
/* Save the size read. */
*out_size = size;
/* The final checksum, from the image, doesn't take part into the checksum
* calculation, so subtract it from the bytes we are going to read. */
size -= checksum_size ;
size = total_size - checksum_size ;
/* Initiate the checksum calculation for the coredump in the flash. */
esp_core_dump_checksum_init(&wr_data.checksum_ctx);
@ -423,7 +396,7 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
/* Read the content of the flash. */
err = esp_partition_read(core_part, offset, wr_data.cached_data, toread);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read data from core dump (%d)!", err);
ESP_COREDUMP_LOGE("Failed to read data from core dump (%d)!", err);
return err;
}
@ -440,23 +413,22 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
/* Read the checksum from the flash and compare to the one just
* calculated. */
err = esp_partition_read(core_part, *out_size - checksum_size, checksum_read, checksum_size);
err = esp_partition_read(core_part, total_size - checksum_size, checksum_read, checksum_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read checksum from core dump (%d)!", err);
ESP_COREDUMP_LOGE("Failed to read checksum from core dump (%d)!", err);
return err;
}
/* Compare the checksum read from the flash and the one just calculated. */
if (memcmp(checksum_calc, checksum_read, checksum_size) != 0) {
ESP_LOGE(TAG, "Core dump data check failed:");
ESP_COREDUMP_LOGE("Core dump data check failed:");
esp_core_dump_print_checksum("Calculated checksum", checksum_calc);
esp_core_dump_print_checksum("Image checksum", checksum_read);
return ESP_ERR_INVALID_CRC;
} else {
ESP_LOGI(TAG, "Core dump data checksum is correct");
ESP_COREDUMP_LOGI("Core dump data checksum is correct");
}
*out_addr = core_part->address;
return ESP_OK;
}
@ -493,3 +465,84 @@ esp_err_t esp_core_dump_image_erase(void)
return err;
}
static esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size)
{
uint32_t core_size = 0;
const esp_partition_t *core_part = NULL;
/* Check the arguments, at least one should be provided. */
if (partition == NULL && size == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Find the partition that could potentially contain a (previous) core dump. */
core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (core_part == NULL) {
ESP_COREDUMP_LOGE("No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_COREDUMP_LOGE("Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
/* The partition has been found, get its first uint32_t value, which
* describes the core dump file size. */
esp_err_t err = esp_partition_read(core_part, 0, &core_size, sizeof(uint32_t));
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to read core dump data size (%d)!", err);
return err;
}
/* Verify that the size read from the flash is not corrupted. */
if (core_size == 0xFFFFFFFF) {
ESP_COREDUMP_LOGD("Blank core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
if ((core_size < sizeof(uint32_t)) || (core_size > core_part->size)) {
ESP_COREDUMP_LOGE("Incorrect size of core dump image: %d", core_size);
return ESP_ERR_INVALID_SIZE;
}
/* Return the values if needed. */
if (partition != NULL) {
*partition = core_part;
}
if (size != NULL) {
*size = core_size;
}
return ESP_OK;
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
{
esp_err_t err = ESP_OK;
uint32_t size = 0;
const esp_partition_t *core_part = NULL;
/* Check the validity of the parameters. */
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Retrieve the partition and size. */
err = esp_core_dump_partition_and_size_get(&core_part, &size);
if (err != ESP_OK) {
return err;
}
/* Save the address. */
*out_addr = core_part->address;
/* Save the size read. */
*out_size = size;
return ESP_OK;
}