kernel: sys_heap: Fix chunk size request validation
Updates the heap code to ensure that when converting the requested number of bytes to chunks, we do not return a value that exceeds the number of chunks in the heap. Fixes #90306 Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
This commit is contained in:
parent
45f3b71b39
commit
811302e6d2
2 changed files with 21 additions and 21 deletions
|
@ -265,12 +265,13 @@ void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)
|
||||||
struct z_heap *h = heap->heap;
|
struct z_heap *h = heap->heap;
|
||||||
void *mem;
|
void *mem;
|
||||||
|
|
||||||
if ((bytes == 0U) || size_too_big(h, bytes)) {
|
if (bytes == 0U) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunksz_t chunk_sz = bytes_to_chunksz(h, bytes);
|
chunksz_t chunk_sz = bytes_to_chunksz(h, bytes, 0);
|
||||||
chunkid_t c = alloc_chunk(h, chunk_sz);
|
chunkid_t c = alloc_chunk(h, chunk_sz);
|
||||||
|
|
||||||
if (c == 0U) {
|
if (c == 0U) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -330,7 +331,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
|
||||||
}
|
}
|
||||||
__ASSERT((align & (align - 1)) == 0, "align must be a power of 2");
|
__ASSERT((align & (align - 1)) == 0, "align must be a power of 2");
|
||||||
|
|
||||||
if ((bytes == 0) || size_too_big(h, bytes)) {
|
if (bytes == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +340,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
|
||||||
* We over-allocate to account for alignment and then free
|
* We over-allocate to account for alignment and then free
|
||||||
* the extra allocations afterwards.
|
* the extra allocations afterwards.
|
||||||
*/
|
*/
|
||||||
chunksz_t padded_sz = bytes_to_chunksz(h, bytes + align - gap);
|
chunksz_t padded_sz = bytes_to_chunksz(h, bytes, align - gap);
|
||||||
chunkid_t c0 = alloc_chunk(h, padded_sz);
|
chunkid_t c0 = alloc_chunk(h, padded_sz);
|
||||||
|
|
||||||
if (c0 == 0) {
|
if (c0 == 0) {
|
||||||
|
@ -387,13 +388,10 @@ static bool inplace_realloc(struct sys_heap *heap, void *ptr, size_t bytes)
|
||||||
{
|
{
|
||||||
struct z_heap *h = heap->heap;
|
struct z_heap *h = heap->heap;
|
||||||
|
|
||||||
if (size_too_big(h, bytes)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunkid_t c = mem_to_chunkid(h, ptr);
|
chunkid_t c = mem_to_chunkid(h, ptr);
|
||||||
size_t align_gap = (uint8_t *)ptr - (uint8_t *)chunk_mem(h, c);
|
size_t align_gap = (uint8_t *)ptr - (uint8_t *)chunk_mem(h, c);
|
||||||
chunksz_t chunks_need = bytes_to_chunksz(h, bytes + align_gap);
|
|
||||||
|
chunksz_t chunks_need = bytes_to_chunksz(h, bytes, align_gap);
|
||||||
|
|
||||||
if (chunk_size(h, c) == chunks_need) {
|
if (chunk_size(h, c) == chunks_need) {
|
||||||
/* We're good already */
|
/* We're good already */
|
||||||
|
|
|
@ -232,14 +232,25 @@ static inline chunksz_t chunksz(size_t bytes)
|
||||||
return (bytes + CHUNK_UNIT - 1U) / CHUNK_UNIT;
|
return (bytes + CHUNK_UNIT - 1U) / CHUNK_UNIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline chunksz_t bytes_to_chunksz(struct z_heap *h, size_t bytes)
|
/**
|
||||||
|
* Convert the number of requested bytes to chunks and clamp it to facilitate
|
||||||
|
* error handling. As some of the heap is used for metadata, there will never
|
||||||
|
* be enough space for 'end_chunk' chunks. Also note that since 'size_t' may
|
||||||
|
* be 64-bits wide, clamping guards against overflow when converting to the
|
||||||
|
* 32-bit wide 'chunksz_t'.
|
||||||
|
*/
|
||||||
|
static ALWAYS_INLINE chunksz_t bytes_to_chunksz(struct z_heap *h, size_t bytes, size_t extra)
|
||||||
{
|
{
|
||||||
return chunksz(chunk_header_bytes(h) + bytes);
|
size_t chunks = (bytes / CHUNK_UNIT) + (extra / CHUNK_UNIT);
|
||||||
|
size_t oddments = ((bytes % CHUNK_UNIT) + (extra % CHUNK_UNIT) +
|
||||||
|
chunk_header_bytes(h) + CHUNK_UNIT - 1U) / CHUNK_UNIT;
|
||||||
|
|
||||||
|
return (chunksz_t)MIN(chunks + oddments, h->end_chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline chunksz_t min_chunk_size(struct z_heap *h)
|
static inline chunksz_t min_chunk_size(struct z_heap *h)
|
||||||
{
|
{
|
||||||
return bytes_to_chunksz(h, 1);
|
return chunksz(chunk_header_bytes(h) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t chunksz_to_bytes(struct z_heap *h, chunksz_t chunksz_in)
|
static inline size_t chunksz_to_bytes(struct z_heap *h, chunksz_t chunksz_in)
|
||||||
|
@ -253,15 +264,6 @@ static inline int bucket_idx(struct z_heap *h, chunksz_t sz)
|
||||||
return 31 - __builtin_clz(usable_sz);
|
return 31 - __builtin_clz(usable_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool size_too_big(struct z_heap *h, size_t bytes)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Quick check to bail out early if size is too big.
|
|
||||||
* Also guards against potential arithmetic overflows elsewhere.
|
|
||||||
*/
|
|
||||||
return (bytes / CHUNK_UNIT) >= h->end_chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes,
|
static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes,
|
||||||
size_t *free_bytes)
|
size_t *free_bytes)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue