mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(bitscrambler): validate and safely load LUT data
Reject LUT loads that exceed the hardware address space and assemble each 32-bit LUT word via memcpy so unaligned and partial inputs do not read past the caller buffer. Add regression tests for oversized and partial unaligned LUT loads.
This commit is contained in:
@@ -89,6 +89,7 @@ esp_err_t bitscrambler_load_program(bitscrambler_handle_t handle, const void *pr
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid handle or lut pointer
|
||||
* - ESP_ERR_INVALID_SIZE: LUT data exceeds hardware capacity
|
||||
*/
|
||||
esp_err_t bitscrambler_load_lut(bitscrambler_handle_t handle, void *lut, size_t size_bytes);
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ static const char *TAG = "bitscrambler";
|
||||
|
||||
#define BITSCRAMBLER_BINARY_VER 1 //max version we're compatible with
|
||||
#define BITSCRAMBLER_HW_REV 0
|
||||
// LUT index register is 11 bits wide, so the LUT address space is 2048 bytes.
|
||||
#define BITSCRAMBLER_LUT_MAX_BYTES (1U << 11)
|
||||
|
||||
// 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
|
||||
@@ -241,12 +243,28 @@ esp_err_t bitscrambler_load_lut(bitscrambler_handle_t handle, void *lut, size_t
|
||||
if (!handle || !lut) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
uint32_t *lut_words = (uint32_t*)lut;
|
||||
if (size_bytes > BITSCRAMBLER_LUT_MAX_BYTES) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
const uint8_t *lut_bytes = (const uint8_t *)lut;
|
||||
bitscrambler_lut_width_t lut_width = bitscrambler_ll_get_lut_width(handle->hw, handle->cfg.dir);
|
||||
bitscrambler_ll_set_lut_width(handle->hw, handle->cfg.dir, BITSCRAMBLER_LUT_WIDTH_32BIT);
|
||||
size_t size_words = (size_bytes + 3) / 4;
|
||||
for (int w = 0; w < size_words; w++) {
|
||||
bitscrambler_ll_lutmem_write(handle->hw, handle->cfg.dir, w, lut_words[w]);
|
||||
// Assemble each LUT entry byte-wise before writing it to hardware:
|
||||
// 1) callers are allowed to pass unaligned buffers, so reading via a
|
||||
// uint32_t * could fault or perform an unaligned access on some targets;
|
||||
// 2) the final LUT word may be only partially supplied, and copying the
|
||||
// valid bytes into a zero-initialized word avoids reading past the end
|
||||
// of the caller's buffer and leaking adjacent memory into the LUT.
|
||||
uint32_t lut_word = 0;
|
||||
size_t offset = w * sizeof(lut_word);
|
||||
size_t bytes_to_copy = size_bytes - offset;
|
||||
if (bytes_to_copy > sizeof(lut_word)) {
|
||||
bytes_to_copy = sizeof(lut_word);
|
||||
}
|
||||
memcpy(&lut_word, lut_bytes + offset, bytes_to_copy);
|
||||
bitscrambler_ll_lutmem_write(handle->hw, handle->cfg.dir, w, lut_word);
|
||||
}
|
||||
bitscrambler_ll_set_lut_width(handle->hw, handle->cfg.dir, lut_width);
|
||||
return ESP_OK;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
@@ -171,6 +172,51 @@ TEST_CASE("BitScrambler with LUT32", "[bs]")
|
||||
free(data_out);
|
||||
}
|
||||
|
||||
TEST_CASE("BitScrambler loads partial LUT from unaligned buffer", "[bs]")
|
||||
{
|
||||
const size_t len = 32;
|
||||
const uint32_t expected_lut_words[] = {
|
||||
0xA0011111,
|
||||
0xA0022222,
|
||||
0xA0033333,
|
||||
0x00000044,
|
||||
};
|
||||
const uint32_t lut_source_words[] = {
|
||||
0xA0011111,
|
||||
0xA0022222,
|
||||
0xA0033333,
|
||||
0xA0044444,
|
||||
};
|
||||
uint8_t lut_bytes[sizeof(lut_source_words) + 4] = {0};
|
||||
uint8_t *unaligned_lut = lut_bytes + 1;
|
||||
const size_t lut_size = 13;
|
||||
uint8_t *data_in = heap_caps_aligned_calloc(8, 1, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
uint32_t *data_out = heap_caps_aligned_calloc(8, 1, len * 4, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
TEST_ASSERT_NOT_NULL(data_in);
|
||||
TEST_ASSERT_NOT_NULL(data_out);
|
||||
memcpy(unaligned_lut, lut_source_words, sizeof(lut_source_words));
|
||||
unaligned_lut[lut_size] = 0xAB;
|
||||
unaligned_lut[lut_size + 1] = 0xCD;
|
||||
unaligned_lut[lut_size + 2] = 0xEF;
|
||||
|
||||
bitscrambler_handle_t bs;
|
||||
TEST_ESP_OK(bitscrambler_loopback_create(&bs, SOC_BITSCRAMBLER_ATTACH_GPSPI2, len * 4));
|
||||
TEST_ESP_OK(bitscrambler_load_program(bs, bitscrambler_program_lut32));
|
||||
TEST_ESP_OK(bitscrambler_load_lut(bs, unaligned_lut, lut_size));
|
||||
|
||||
size_t res_len = 0;
|
||||
TEST_ESP_OK(bitscrambler_loopback_run(bs, data_in, len, data_out, len * 4, &res_len));
|
||||
bitscrambler_free(bs);
|
||||
|
||||
for (size_t i = 0; i < res_len / 4; i++) {
|
||||
TEST_ASSERT_EQUAL(expected_lut_words[i % 4], data_out[i]);
|
||||
}
|
||||
TEST_ASSERT_EQUAL(len * 4, res_len);
|
||||
|
||||
free(data_in);
|
||||
free(data_out);
|
||||
}
|
||||
|
||||
TEST_CASE("BitScrambler with loop instruction", "[bs]")
|
||||
{
|
||||
uint8_t data_in[] = {0x00, 0xFF, 0x55};
|
||||
|
||||
Reference in New Issue
Block a user