mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
Merge branch 'fix/kasan_heap_alignment' into 'master'
fix(heap): preserve aligned allocation with KASAN See merge request espressif/esp-idf!51186
This commit is contained in:
@@ -40,6 +40,10 @@
|
||||
* The ordering is intentional: user underflows must hit the left redzone
|
||||
* before they can reach the task-tracking block-owner word.
|
||||
*
|
||||
* For heap_caps_aligned_alloc(), the tlsf align offset must be
|
||||
* (block-owner size + KASAN_RZ) so the *user* pointer (after both shifts)
|
||||
* satisfies the requested alignment.
|
||||
*
|
||||
* Pointer arithmetic macros live in heap_kasan_layout.h.
|
||||
*/
|
||||
|
||||
@@ -183,6 +187,8 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_aligned_alloc_base(size_t alignment
|
||||
}
|
||||
|
||||
const size_t alloc_size = KASAN_ADD_RZ(size);
|
||||
/* Align the eventual user pointer (after block-owner + left redzone). */
|
||||
const size_t align_offset = MULTI_HEAP_BLOCK_OWNER_SIZE() + KASAN_RZ;
|
||||
|
||||
for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
|
||||
//Iterate over heaps and check capabilities at this priority
|
||||
@@ -205,7 +211,7 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_aligned_alloc_base(size_t alignment
|
||||
//we need to 'invert' it (lowest address in DRAM == highest address in IRAM and vice-versa) and
|
||||
//add a pointer to the DRAM equivalent before the address we're going to return.
|
||||
ret = aligned_or_unaligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(alloc_size) + 4,
|
||||
alignment, MULTI_HEAP_BLOCK_OWNER_SIZE()); // int overflow checked above
|
||||
alignment, align_offset); // int overflow checked above
|
||||
if (ret != NULL) {
|
||||
#if CONFIG_HEAP_TASK_TRACKING
|
||||
heap_caps_update_per_task_info_alloc(heap,
|
||||
@@ -224,7 +230,7 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_aligned_alloc_base(size_t alignment
|
||||
} else {
|
||||
//Just try to alloc, nothing special.
|
||||
ret = aligned_or_unaligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(alloc_size),
|
||||
alignment, MULTI_HEAP_BLOCK_OWNER_SIZE());
|
||||
alignment, align_offset);
|
||||
if (ret != NULL) {
|
||||
#if CONFIG_HEAP_TASK_TRACKING
|
||||
heap_caps_update_per_task_info_alloc(heap,
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_kasan.h"
|
||||
|
||||
@@ -139,6 +141,34 @@ TEST_CASE("no false positive", "[kasan]")
|
||||
ESP_LOGI(TAG, "no-bug test PASSED");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
TEST_CASE("aligned allocation preserves alignment", "[kasan][heap]")
|
||||
{
|
||||
static const size_t alignments[] = { 8, 16, 32, 64 };
|
||||
const uint32_t alloc_size = 37;
|
||||
|
||||
#if CONFIG_KASAN_NO_HALT
|
||||
kasan_reset_error_count();
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < sizeof(alignments) / sizeof(alignments[0]); i++) {
|
||||
const size_t alignment = alignments[i];
|
||||
uint8_t *buf = heap_caps_aligned_alloc(alignment, alloc_size, MALLOC_CAP_DEFAULT);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(buf);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, (uintptr_t)buf & (alignment - 1));
|
||||
/* Verify the full user region remains accessible after the KASAN redzone offset. */
|
||||
memset(buf, 0xA5, alloc_size);
|
||||
heap_caps_free(buf);
|
||||
}
|
||||
|
||||
#if CONFIG_KASAN_NO_HALT
|
||||
TEST_ASSERT_EQUAL_UINT32(0, kasan_get_error_count());
|
||||
#endif
|
||||
ESP_LOGI(TAG, "aligned allocation test PASSED");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* GCC -fsanitize=kernel-address instrumentation calls a sized family of
|
||||
|
||||
@@ -93,6 +93,16 @@ def test_kasan_halt_no_false_positive(dut: Dut) -> None:
|
||||
dut.expect('no-bug test PASSED', timeout=15)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['supported_targets', 'preview_targets'], indirect=['target'])
|
||||
@pytest.mark.parametrize('config', ['halt'], indirect=True)
|
||||
def test_kasan_halt_aligned_alloc(dut: Dut) -> None:
|
||||
"""KASAN redzones must not change aligned allocator guarantees."""
|
||||
dut.expect('KASAN test application starting', timeout=15)
|
||||
dut.write('"aligned allocation preserves alignment"')
|
||||
dut.expect('aligned allocation test PASSED', timeout=15)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['supported_targets', 'preview_targets'], indirect=['target'])
|
||||
@pytest.mark.parametrize('config', ['halt'], indirect=True)
|
||||
|
||||
Reference in New Issue
Block a user