mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(bitscrambler): reject malformed program headers
Validate BitScrambler program headers against the supported format and hardware limits before using header-derived instruction and LUT sizes. Also add regression coverage for malformed headers and document that the program blob must come from a trusted assembler output.
This commit is contained in:
@@ -73,6 +73,11 @@ void bitscrambler_free(bitscrambler_handle_t handle);
|
|||||||
/**
|
/**
|
||||||
* @brief Load a BitScrambler binary program into BitScrambler memory
|
* @brief Load a BitScrambler binary program into BitScrambler memory
|
||||||
*
|
*
|
||||||
|
* @note The program blob is expected to come from a trusted BitScrambler assembler
|
||||||
|
* output. This API validates the header fields against hardware limits, but it
|
||||||
|
* does not take an explicit blob length and therefore cannot verify that an
|
||||||
|
* arbitrary caller-supplied buffer is complete.
|
||||||
|
*
|
||||||
* @param handle BitScrambler handle
|
* @param handle BitScrambler handle
|
||||||
* @param program Binary program to load
|
* @param program Binary program to load
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ static const char *TAG = "bitscrambler";
|
|||||||
|
|
||||||
#define BITSCRAMBLER_BINARY_VER 1 //max version we're compatible with
|
#define BITSCRAMBLER_BINARY_VER 1 //max version we're compatible with
|
||||||
#define BITSCRAMBLER_HW_REV 0
|
#define BITSCRAMBLER_HW_REV 0
|
||||||
// LUT index register is 11 bits wide, so the LUT address space is 2048 bytes.
|
#define BITSCRAMBLER_MAX_LUT_WORDS (BITSCRAMBLER_LL_LUT_MAX_BYTES / sizeof(uint32_t))
|
||||||
#define BITSCRAMBLER_LUT_MAX_BYTES (1U << 11)
|
|
||||||
|
|
||||||
// After a reset, it can take a few cycles for the BitScrambler to actually be
|
// After a reset, it can take a few cycles for the BitScrambler to actually be
|
||||||
// reset. We check this many times for this; if it takes longer the hardware
|
// reset. We check this many times for this; if it takes longer the hardware
|
||||||
@@ -58,6 +57,9 @@ typedef struct {
|
|||||||
} bitscrambler_program_hdr_t;
|
} bitscrambler_program_hdr_t;
|
||||||
|
|
||||||
#define INST_LEN_WORDS BITSCRAMBLER_LL_INST_LEN_WORDS
|
#define INST_LEN_WORDS BITSCRAMBLER_LL_INST_LEN_WORDS
|
||||||
|
#define BITSCRAMBLER_V1_HDR_LEN_WORDS (sizeof(bitscrambler_program_hdr_t) / sizeof(uint32_t))
|
||||||
|
|
||||||
|
_Static_assert(sizeof(bitscrambler_program_hdr_t) % sizeof(uint32_t) == 0, "bitscrambler program header must be word aligned");
|
||||||
|
|
||||||
// For now, hardware only has one TX and on RX unit. Need to make this more flexible if we get
|
// For now, hardware only has one TX and on RX unit. Need to make this more flexible if we get
|
||||||
// non-specific and/or more channels.
|
// non-specific and/or more channels.
|
||||||
@@ -193,7 +195,7 @@ esp_err_t bitscrambler_load_program(bitscrambler_handle_t bs, const void *progra
|
|||||||
|
|
||||||
//Parse the program header. There are two versions, V0 is generated by the C assembler while
|
//Parse the program header. There are two versions, V0 is generated by the C assembler while
|
||||||
//v1 is generated by the Python assembler.
|
//v1 is generated by the Python assembler.
|
||||||
int inst_len_bytes = INST_LEN_WORDS * sizeof(uint32_t); //note this is different for v1 and v0
|
size_t inst_len_bytes = INST_LEN_WORDS * sizeof(uint32_t); //note this is different for v1 and v0
|
||||||
memcpy(&hdr, program_bin, sizeof(bitscrambler_program_hdr_t));
|
memcpy(&hdr, program_bin, sizeof(bitscrambler_program_hdr_t));
|
||||||
if (hdr.version != BITSCRAMBLER_BINARY_VER) {
|
if (hdr.version != BITSCRAMBLER_BINARY_VER) {
|
||||||
ESP_LOGE(TAG, "Bitscrambler binary version %d not supported!", hdr.version);
|
ESP_LOGE(TAG, "Bitscrambler binary version %d not supported!", hdr.version);
|
||||||
@@ -203,12 +205,29 @@ esp_err_t bitscrambler_load_program(bitscrambler_handle_t bs, const void *progra
|
|||||||
ESP_LOGE(TAG, "Bitscrambler hardware rev %d not supported!", hdr.hw_rev);
|
ESP_LOGE(TAG, "Bitscrambler hardware rev %d not supported!", hdr.hw_rev);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
if (hdr.hdr_len != BITSCRAMBLER_V1_HDR_LEN_WORDS) {
|
||||||
|
ESP_LOGE(TAG, "Bitscrambler header length %d not supported!", hdr.hdr_len);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
if (hdr.inst_ct > BITSCRAMBLER_LL_MAX_INST) {
|
||||||
|
ESP_LOGE(TAG, "Bitscrambler instruction count %d exceeds hardware limit!", hdr.inst_ct);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
if (hdr.lut_word_ct > BITSCRAMBLER_MAX_LUT_WORDS) {
|
||||||
|
ESP_LOGE(TAG, "Bitscrambler LUT size %d words exceeds hardware limit!", hdr.lut_word_ct);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
if (hdr.lut_width > BITSCRAMBLER_LUT_WIDTH_32BIT) {
|
||||||
|
ESP_LOGE(TAG, "Bitscrambler LUT width %d not supported!", hdr.lut_width);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
bitscrambler_ll_set_state(bs->hw, bs->cfg.dir, BITSCRAMBLER_SET_STATE_HALT);
|
bitscrambler_ll_set_state(bs->hw, bs->cfg.dir, BITSCRAMBLER_SET_STATE_HALT);
|
||||||
|
|
||||||
//Load the program
|
//Load the program
|
||||||
const uint8_t *p = (const uint8_t*)program_bin;
|
const uint8_t *p = (const uint8_t*)program_bin;
|
||||||
p += hdr.hdr_len * sizeof(uint32_t); //skip header
|
size_t header_size_bytes = hdr.hdr_len * sizeof(uint32_t);
|
||||||
|
p += header_size_bytes; //skip header
|
||||||
uint32_t instr[INST_LEN_WORDS];
|
uint32_t instr[INST_LEN_WORDS];
|
||||||
for (int inst = 0; inst < hdr.inst_ct; inst++) {
|
for (int inst = 0; inst < hdr.inst_ct; inst++) {
|
||||||
//v0 doesn't have the words 32-bit aligned, so memcpy to work around that
|
//v0 doesn't have the words 32-bit aligned, so memcpy to work around that
|
||||||
@@ -222,9 +241,10 @@ esp_err_t bitscrambler_load_program(bitscrambler_handle_t bs, const void *progra
|
|||||||
ESP_LOGD(TAG, "Loaded %d instructions", hdr.inst_ct);
|
ESP_LOGD(TAG, "Loaded %d instructions", hdr.inst_ct);
|
||||||
//Load the LUT.
|
//Load the LUT.
|
||||||
bitscrambler_ll_set_lut_width(bs->hw, bs->cfg.dir, BITSCRAMBLER_LUT_WIDTH_32BIT);
|
bitscrambler_ll_set_lut_width(bs->hw, bs->cfg.dir, BITSCRAMBLER_LUT_WIDTH_32BIT);
|
||||||
uint32_t *lut = (uint32_t*)p;
|
|
||||||
for (int w = 0; w < hdr.lut_word_ct; w++) {
|
for (int w = 0; w < hdr.lut_word_ct; w++) {
|
||||||
bitscrambler_ll_lutmem_write(bs->hw, bs->cfg.dir, w, lut[w]);
|
uint32_t lut_word;
|
||||||
|
memcpy(&lut_word, p + (w * sizeof(lut_word)), sizeof(lut_word));
|
||||||
|
bitscrambler_ll_lutmem_write(bs->hw, bs->cfg.dir, w, lut_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set options from header
|
//Set options from header
|
||||||
@@ -249,7 +269,7 @@ esp_err_t bitscrambler_load_lut(bitscrambler_handle_t handle, void *lut, size_t
|
|||||||
if (!handle || !lut) {
|
if (!handle || !lut) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if (size_bytes > BITSCRAMBLER_LUT_MAX_BYTES) {
|
if (size_bytes > BITSCRAMBLER_LL_LUT_MAX_BYTES) {
|
||||||
return ESP_ERR_INVALID_SIZE;
|
return ESP_ERR_INVALID_SIZE;
|
||||||
}
|
}
|
||||||
const uint8_t *lut_bytes = (const uint8_t *)lut;
|
const uint8_t *lut_bytes = (const uint8_t *)lut;
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ extern "C" {
|
|||||||
#define BITSCRAMBLER_LL_GET_HW(num) (((num) == 0) ? (&BITSCRAMBLER) : NULL)
|
#define BITSCRAMBLER_LL_GET_HW(num) (((num) == 0) ? (&BITSCRAMBLER) : NULL)
|
||||||
|
|
||||||
#define BITSCRAMBLER_LL_INST_LEN_WORDS 9 //length of one instruction in 32-bit words as defined by HW
|
#define BITSCRAMBLER_LL_INST_LEN_WORDS 9 //length of one instruction in 32-bit words as defined by HW
|
||||||
|
// LUT index register is 11 bits wide, so the LUT address space is 2048 bytes.
|
||||||
|
#define BITSCRAMBLER_LL_LUT_MAX_BYTES (1U << 11)
|
||||||
|
#define BITSCRAMBLER_LL_MAX_INST 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Select peripheral BitScrambler is attached to
|
* @brief Select peripheral BitScrambler is attached to
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ extern "C" {
|
|||||||
#define BITSCRAMBLER_LL_GET_HW(num) (((num) == 0) ? (&BITSCRAMBLER) : NULL)
|
#define BITSCRAMBLER_LL_GET_HW(num) (((num) == 0) ? (&BITSCRAMBLER) : NULL)
|
||||||
|
|
||||||
#define BITSCRAMBLER_LL_INST_LEN_WORDS 9 //length of one instruction in 32-bit words as defined by HW
|
#define BITSCRAMBLER_LL_INST_LEN_WORDS 9 //length of one instruction in 32-bit words as defined by HW
|
||||||
|
// LUT index register is 11 bits wide, so the LUT address space is 2048 bytes.
|
||||||
|
#define BITSCRAMBLER_LL_LUT_MAX_BYTES (1U << 11)
|
||||||
|
#define BITSCRAMBLER_LL_MAX_INST 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Select peripheral BitScrambler is attached to
|
* @brief Select peripheral BitScrambler is attached to
|
||||||
|
|||||||
Reference in New Issue
Block a user