Merge branch 'feature/embed_elf_sha256' into 'master'
build system: include SHA256 hash of ELF file into app_desc structure See merge request idf/esp-idf!4093
This commit is contained in:
commit
590825824d
8 changed files with 156 additions and 4 deletions
|
@ -13,7 +13,9 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_attr.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// Application version info
|
||||
|
@ -60,3 +62,24 @@ const esp_app_desc_t *esp_ota_get_app_description(void)
|
|||
{
|
||||
return &esp_app_desc;
|
||||
}
|
||||
|
||||
/* The following two functions may be called from the panic handler
|
||||
* or core dump, hence IRAM_ATTR.
|
||||
*/
|
||||
|
||||
static inline char IRAM_ATTR to_hex_digit(unsigned val)
|
||||
{
|
||||
return (val < 10) ? ('0' + val) : ('a' + val - 10);
|
||||
}
|
||||
|
||||
int IRAM_ATTR esp_ota_get_app_elf_sha256(char* dst, size_t size)
|
||||
{
|
||||
size_t n = MIN((size - 1) / 2, sizeof(esp_app_desc.app_elf_sha256));
|
||||
const uint8_t* src = esp_app_desc.app_elf_sha256;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
dst[2*i] = to_hex_digit(src[i] >> 4);
|
||||
dst[2*i + 1] = to_hex_digit(src[i] & 0xf);
|
||||
}
|
||||
dst[2*n] = 0;
|
||||
return 2*n + 1;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,16 @@ typedef uint32_t esp_ota_handle_t;
|
|||
*/
|
||||
const esp_app_desc_t *esp_ota_get_app_description(void);
|
||||
|
||||
/**
|
||||
* @brief Fill the provided buffer with SHA256 of the ELF file, formatted as hexadecimal, null-terminated.
|
||||
* If the buffer size is not sufficient to fit the entire SHA256 in hex plus a null terminator,
|
||||
* the largest possible number of bytes will be written followed by a null.
|
||||
* @param dst Destination buffer
|
||||
* @param size Size of the buffer
|
||||
* @return Number of bytes written to dst (including null terminator)
|
||||
*/
|
||||
int esp_ota_get_app_elf_sha256(char* dst, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Commence an OTA update writing to the specified partition.
|
||||
|
||||
|
|
50
components/app_update/test/test_app_desc.c
Normal file
50
components/app_update/test/test_app_desc.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include <string.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "unity.h"
|
||||
|
||||
TEST_CASE("esp_ota_get_app_elf_sha256 test", "[esp_app_desc]")
|
||||
{
|
||||
const int sha256_hex_len = 64;
|
||||
char dst[sha256_hex_len + 2];
|
||||
const char fill = 0xcc;
|
||||
int res;
|
||||
size_t len;
|
||||
|
||||
char ref_sha256[sha256_hex_len + 1];
|
||||
const esp_app_desc_t* desc = esp_ota_get_app_description();
|
||||
for (int i = 0; i < sizeof(ref_sha256) / 2; ++i) {
|
||||
snprintf(ref_sha256 + 2*i, 3, "%02x", desc->app_elf_sha256[i]);
|
||||
}
|
||||
ref_sha256[sha256_hex_len] = 0;
|
||||
|
||||
printf("Ref: %s\n", ref_sha256);
|
||||
|
||||
memset(dst, fill, sizeof(dst));
|
||||
len = sizeof(dst);
|
||||
res = esp_ota_get_app_elf_sha256(dst, len);
|
||||
printf("%d: %s (%d)\n", len, dst, res);
|
||||
TEST_ASSERT_EQUAL(sha256_hex_len + 1, res);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(dst, ref_sha256, res - 1));
|
||||
TEST_ASSERT_EQUAL_HEX(0, dst[sha256_hex_len]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[sha256_hex_len + 1]);
|
||||
|
||||
memset(dst, fill, sizeof(dst));
|
||||
len = 9;
|
||||
res = esp_ota_get_app_elf_sha256(dst, len);
|
||||
printf("%d: %s (%d)\n", len, dst, res);
|
||||
TEST_ASSERT_EQUAL(9, res);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(dst, ref_sha256, res - 1));
|
||||
TEST_ASSERT_EQUAL_HEX(0, dst[8]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[9]);
|
||||
|
||||
memset(dst, fill, sizeof(dst));
|
||||
len = 8;
|
||||
res = esp_ota_get_app_elf_sha256(dst, len);
|
||||
printf("%d: %s (%d)\n", len, dst, res);
|
||||
// should output even number of characters plus '\0'
|
||||
TEST_ASSERT_EQUAL(7, res);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(dst, ref_sha256, res - 1));
|
||||
TEST_ASSERT_EQUAL_HEX(0, dst[6]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[7]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[8]);
|
||||
}
|
|
@ -189,9 +189,11 @@ void IRAM_ATTR call_start_cpu0()
|
|||
ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version);
|
||||
#endif
|
||||
#ifdef CONFIG_APP_COMPILE_TIME_DATE
|
||||
ESP_EARLY_LOGI(TAG, "Compile time: %s", app_desc->time);
|
||||
ESP_EARLY_LOGI(TAG, "Compile date: %s", app_desc->date);
|
||||
ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time);
|
||||
#endif
|
||||
char buf[17];
|
||||
esp_ota_get_app_elf_sha256(buf, sizeof(buf));
|
||||
ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf);
|
||||
ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "esp_app_trace.h"
|
||||
#include "esp_system_internal.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
#include "SEGGER_RTT.h"
|
||||
#endif
|
||||
|
@ -473,7 +474,7 @@ static void doBacktrace(XtExcFrame *frame)
|
|||
break;
|
||||
}
|
||||
}
|
||||
panicPutStr("\r\n\r\n");
|
||||
panicPutStr("\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -541,9 +542,16 @@ static void commonErrorHandler_dump(XtExcFrame *frame, int core_id)
|
|||
|
||||
}
|
||||
|
||||
panicPutStr("\r\nELF file SHA256: ");
|
||||
char sha256_buf[65];
|
||||
esp_ota_get_app_elf_sha256(sha256_buf, sizeof(sha256_buf));
|
||||
panicPutStr(sha256_buf);
|
||||
panicPutStr("\r\n");
|
||||
|
||||
/* With windowed ABI backtracing is easy, let's do it. */
|
||||
doBacktrace(frame);
|
||||
|
||||
panicPutStr("\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -39,6 +39,8 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
ESPTOOL_ELF2IMAGE_OPTIONS += --elf-sha256-offset 0xb0
|
||||
|
||||
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS)
|
||||
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(APP_OFFSET) $(APP_BIN)
|
||||
|
|
|
@ -52,6 +52,8 @@ if(CONFIG_SECURE_BOOT_ENABLED AND
|
|||
${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} --secure-pad)
|
||||
endif()
|
||||
|
||||
set(ESPTOOLPY_ELF2IMAGE_OPTIONS --elf-sha256-offset 0xb0)
|
||||
|
||||
if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT)
|
||||
# Set ESPFLASHSIZE to 'detect' *after* elf2image options are generated,
|
||||
# as elf2image can't have 'detect' as an option...
|
||||
|
@ -75,7 +77,7 @@ endif()
|
|||
# Add 'app.bin' target - generates with elf2image
|
||||
#
|
||||
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}"
|
||||
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}
|
||||
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
|
||||
-o "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}" "${IDF_PROJECT_EXECUTABLE}"
|
||||
DEPENDS ${IDF_PROJECT_EXECUTABLE}
|
||||
VERBATIM
|
||||
|
|
55
examples/get-started/blink/example_test.py
Normal file
55
examples/get-started/blink/example_test.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import hashlib
|
||||
|
||||
try:
|
||||
import IDF
|
||||
except ImportError:
|
||||
# This environment variable is expected on the host machine
|
||||
test_fw_path = os.getenv("TEST_FW_PATH")
|
||||
if test_fw_path and test_fw_path not in sys.path:
|
||||
sys.path.insert(0, test_fw_path)
|
||||
|
||||
import IDF
|
||||
|
||||
import Utility
|
||||
|
||||
|
||||
def verify_elf_sha256_embedding(dut):
|
||||
elf_file = os.path.join(dut.app.binary_path, "blink.elf")
|
||||
sha256 = hashlib.sha256()
|
||||
with open(elf_file, "rb") as f:
|
||||
sha256.update(f.read())
|
||||
sha256_expected = sha256.hexdigest()
|
||||
|
||||
dut.reset()
|
||||
sha256_reported = dut.expect(re.compile(r'ELF file SHA256:\s+([a-f0-9]+)'), timeout=5)[0]
|
||||
|
||||
Utility.console_log('ELF file SHA256: %s' % sha256_expected)
|
||||
Utility.console_log('ELF file SHA256 (reported by the app): %s' % sha256_reported)
|
||||
# the app reports only the first several hex characters of the SHA256, check that they match
|
||||
if not sha256_expected.startswith(sha256_reported):
|
||||
raise ValueError('ELF file SHA256 mismatch')
|
||||
|
||||
|
||||
@IDF.idf_example_test(env_tag="Example_WIFI")
|
||||
def test_examples_blink(env, extra_data):
|
||||
dut = env.get_dut("blink", "examples/get-started/blink")
|
||||
binary_file = os.path.join(dut.app.binary_path, "blink.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
IDF.log_performance("blink_bin_size", "{}KB".format(bin_size // 1024))
|
||||
IDF.check_performance("blink_bin_size", bin_size // 1024)
|
||||
|
||||
dut.start_app()
|
||||
|
||||
verify_elf_sha256_embedding(dut)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_blink()
|
Loading…
Reference in a new issue