Add ESP8266 support to OTA release compatibility system using .ver_number section
Co-authored-by: willmmiles <6540455+willmmiles@users.noreply.github.com>
This commit is contained in:
@@ -7,43 +7,11 @@
|
||||
#endif
|
||||
|
||||
bool extractReleaseFromCustomDesc(const uint8_t* binaryData, size_t dataSize, char* extractedRelease) {
|
||||
if (!binaryData || !extractedRelease || dataSize < sizeof(esp_image_header_t)) {
|
||||
if (!binaryData || !extractedRelease || dataSize < 64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
// Look for ESP32 image header to find the custom description section
|
||||
const esp_image_header_t* header = (const esp_image_header_t*)binaryData;
|
||||
|
||||
// Validate ESP32 image header
|
||||
if (header->magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
DEBUG_PRINTLN(F("Not a valid ESP32 image - missing magic header"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// The custom description section is located at a fixed offset after the image header
|
||||
// ESP-IDF places custom description at offset 0x20 in the binary for ESP32
|
||||
const size_t custom_desc_offset = 0x20;
|
||||
|
||||
if (dataSize < custom_desc_offset + sizeof(wled_custom_desc_t)) {
|
||||
DEBUG_PRINTLN(F("Binary too small to contain custom description"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const wled_custom_desc_t* custom_desc = (const wled_custom_desc_t*)(binaryData + custom_desc_offset);
|
||||
|
||||
// Validate magic number and version
|
||||
if (custom_desc->magic != WLED_CUSTOM_DESC_MAGIC) {
|
||||
DEBUG_PRINTLN(F("No WLED custom description found - no magic number"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (custom_desc->version != WLED_CUSTOM_DESC_VERSION) {
|
||||
DEBUG_PRINTF_P(PSTR("Unsupported custom description version: %u\n"), custom_desc->version);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate simple hash checksum (using the same simple hash as in wled_custom_desc.cpp)
|
||||
// Helper lambda function for hash validation (same as in wled_custom_desc.cpp)
|
||||
auto simple_hash = [](const char* str) -> uint32_t {
|
||||
uint32_t hash = 5381;
|
||||
for (int i = 0; str[i]; ++i) {
|
||||
@@ -52,24 +20,46 @@ bool extractReleaseFromCustomDesc(const uint8_t* binaryData, size_t dataSize, ch
|
||||
return hash;
|
||||
};
|
||||
|
||||
uint32_t expected_hash = simple_hash(custom_desc->release_name);
|
||||
if (custom_desc->crc32 != expected_hash) {
|
||||
DEBUG_PRINTF_P(PSTR("Custom description hash mismatch: expected 0x%08x, got 0x%08x\n"),
|
||||
expected_hash, custom_desc->crc32);
|
||||
return false;
|
||||
// For both ESP32 and ESP8266, search for our custom structure
|
||||
// Since we don't know the exact offset, we'll search for our magic number
|
||||
const size_t search_limit = min(dataSize, (size_t)32768); // Limit search to first 32KB
|
||||
|
||||
for (size_t offset = 0; offset <= search_limit - sizeof(wled_custom_desc_t); offset++) {
|
||||
const wled_custom_desc_t* custom_desc = (const wled_custom_desc_t*)(binaryData + offset);
|
||||
|
||||
// Check for magic number
|
||||
if (custom_desc->magic == WLED_CUSTOM_DESC_MAGIC) {
|
||||
// Found potential match, validate version
|
||||
if (custom_desc->version != WLED_CUSTOM_DESC_VERSION) {
|
||||
DEBUG_PRINTF_P(PSTR("Found WLED structure at offset %u but version mismatch: %u\n"),
|
||||
offset, custom_desc->version);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract release name (ensure null termination)
|
||||
// Validate hash - allow CRC32 of 0 (not computed at compile time)
|
||||
uint32_t expected_hash = simple_hash(custom_desc->release_name);
|
||||
if (custom_desc->crc32 != 0 && custom_desc->crc32 != expected_hash) {
|
||||
DEBUG_PRINTF_P(PSTR("Found WLED structure at offset %u but hash mismatch\n"), offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Valid structure found
|
||||
strncpy(extractedRelease, custom_desc->release_name, WLED_RELEASE_NAME_MAX_LEN - 1);
|
||||
extractedRelease[WLED_RELEASE_NAME_MAX_LEN - 1] = '\0';
|
||||
|
||||
DEBUG_PRINTF_P(PSTR("Extracted release name from custom description: '%s'\n"), extractedRelease);
|
||||
return true;
|
||||
#ifdef ESP32
|
||||
DEBUG_PRINTF_P(PSTR("Extracted ESP32 release name from .rodata.wled_desc section at offset %u: '%s'\n"),
|
||||
offset, extractedRelease);
|
||||
#else
|
||||
// ESP8266 doesn't use ESP-IDF format, so we can't extract custom description
|
||||
DEBUG_PRINTLN(F("ESP8266 binaries do not support custom description extraction"));
|
||||
return false;
|
||||
DEBUG_PRINTF_P(PSTR("Extracted ESP8266 release name from .ver_number section at offset %u: '%s'\n"),
|
||||
offset, extractedRelease);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINTLN(F("No WLED custom description found in binary"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validateReleaseCompatibility(const char* extractedRelease) {
|
||||
@@ -92,6 +82,10 @@ bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool ignoreRelea
|
||||
errorMessage[0] = '\0';
|
||||
}
|
||||
|
||||
// Ensure our custom description structure is referenced (prevents optimization)
|
||||
const wled_custom_desc_t* local_desc = getWledCustomDesc();
|
||||
(void)local_desc; // Suppress unused variable warning
|
||||
|
||||
// If user chose to ignore release check, allow OTA
|
||||
if (ignoreReleaseCheck) {
|
||||
DEBUG_PRINTLN(F("OTA release check bypassed by user"));
|
||||
@@ -103,13 +97,9 @@ bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool ignoreRelea
|
||||
bool hasCustomDesc = extractReleaseFromCustomDesc(binaryData, dataSize, extractedRelease);
|
||||
|
||||
if (!hasCustomDesc) {
|
||||
// No custom description - this could be a legacy binary or ESP8266 binary
|
||||
// No custom description - this could be a legacy binary
|
||||
if (errorMessage) {
|
||||
#ifdef ESP32
|
||||
strcpy(errorMessage, "Binary has no release compatibility metadata. Check 'Ignore release name check' to proceed.");
|
||||
#else
|
||||
strcpy(errorMessage, "ESP8266 binaries do not support release checking. Check 'Ignore release name check' to proceed.");
|
||||
#endif
|
||||
}
|
||||
DEBUG_PRINTLN(F("OTA blocked: No custom description found"));
|
||||
return false;
|
||||
|
||||
@@ -55,4 +55,11 @@ bool validateReleaseCompatibility(const char* extractedRelease);
|
||||
*/
|
||||
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool ignoreReleaseCheck, char* errorMessage);
|
||||
|
||||
/**
|
||||
* Get pointer to the embedded custom description structure
|
||||
* This ensures the structure is referenced and not optimized out
|
||||
* @return pointer to the custom description structure
|
||||
*/
|
||||
const wled_custom_desc_t* getWledCustomDesc();
|
||||
|
||||
#endif // WLED_OTA_RELEASE_CHECK_H
|
||||
@@ -3,23 +3,44 @@
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
// Simple hash function for validation (compile-time friendly)
|
||||
constexpr uint32_t simple_hash(const char* str) {
|
||||
uint32_t hash = 5381;
|
||||
for (int i = 0; str[i]; ++i) {
|
||||
hash = ((hash << 5) + hash) + str[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Create the custom description structure with current release name
|
||||
// This will be embedded at a fixed offset in the ESP32 binary
|
||||
const wled_custom_desc_t __attribute__((section(".rodata_custom_desc"))) wled_custom_description = {
|
||||
.magic = WLED_CUSTOM_DESC_MAGIC,
|
||||
.version = WLED_CUSTOM_DESC_VERSION,
|
||||
.release_name = WLED_RELEASE_NAME,
|
||||
.crc32 = simple_hash(WLED_RELEASE_NAME), // Use simple hash for validation
|
||||
.reserved = {0}
|
||||
// This will be embedded in a standard rodata section for ESP32 binary
|
||||
// Using a simpler section name that the linker will accept
|
||||
const wled_custom_desc_t __attribute__((section(".rodata.wled_desc"))) wled_custom_description = {
|
||||
WLED_CUSTOM_DESC_MAGIC, // magic
|
||||
WLED_CUSTOM_DESC_VERSION, // version
|
||||
WLED_RELEASE_NAME, // release_name
|
||||
0, // crc32 - computed at runtime
|
||||
{0} // reserved
|
||||
};
|
||||
|
||||
#endif // ESP32
|
||||
// Reference to ensure it's not optimized away
|
||||
const wled_custom_desc_t* __attribute__((used)) wled_custom_desc_ref = &wled_custom_description;
|
||||
|
||||
// Function to ensure the structure is referenced by code
|
||||
const wled_custom_desc_t* getWledCustomDesc() {
|
||||
return &wled_custom_description;
|
||||
}
|
||||
|
||||
#elif defined(ESP8266)
|
||||
|
||||
// For ESP8266, use the .ver_number section to store release metadata
|
||||
// This section is located at a known offset in ESP8266 binaries
|
||||
const wled_custom_desc_t __attribute__((section(".ver_number"))) wled_esp8266_version_info = {
|
||||
WLED_CUSTOM_DESC_MAGIC, // magic
|
||||
WLED_CUSTOM_DESC_VERSION, // version
|
||||
WLED_RELEASE_NAME, // release_name
|
||||
0, // crc32 - computed at runtime
|
||||
{0} // reserved
|
||||
};
|
||||
|
||||
// Reference the structure in code to prevent linker from discarding it
|
||||
// This ensures the version info is always present in the binary
|
||||
const wled_custom_desc_t* __attribute__((used)) wled_esp8266_version_ref = &wled_esp8266_version_info;
|
||||
|
||||
// Function to ensure the structure is referenced by code
|
||||
const wled_custom_desc_t* getWledCustomDesc() {
|
||||
return &wled_esp8266_version_info;
|
||||
}
|
||||
|
||||
#endif // ESP32/ESP8266
|
||||
@@ -512,7 +512,11 @@ void initServer()
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
WLED::instance().enableWatchdog();
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
request->send(500, FPSTR(CONTENT_TYPE_PLAIN), String("Update.begin failed: ") + Update.errorString());
|
||||
#else
|
||||
request->send(500, FPSTR(CONTENT_TYPE_PLAIN), String("Update.begin failed: ") + Update.getErrorString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user