Skip to content

Commit 811302e

Browse files
peter-mitsiskartben
authored andcommitted
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 <[email protected]>
1 parent 45f3b71 commit 811302e

File tree

2 files changed

+21
-21
lines changed

2 files changed

+21
-21
lines changed

lib/heap/heap.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,13 @@ void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)
265265
struct z_heap *h = heap->heap;
266266
void *mem;
267267

268-
if ((bytes == 0U) || size_too_big(h, bytes)) {
268+
if (bytes == 0U) {
269269
return NULL;
270270
}
271271

272-
chunksz_t chunk_sz = bytes_to_chunksz(h, bytes);
272+
chunksz_t chunk_sz = bytes_to_chunksz(h, bytes, 0);
273273
chunkid_t c = alloc_chunk(h, chunk_sz);
274+
274275
if (c == 0U) {
275276
return NULL;
276277
}
@@ -330,7 +331,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
330331
}
331332
__ASSERT((align & (align - 1)) == 0, "align must be a power of 2");
332333

333-
if ((bytes == 0) || size_too_big(h, bytes)) {
334+
if (bytes == 0) {
334335
return NULL;
335336
}
336337

@@ -339,7 +340,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
339340
* We over-allocate to account for alignment and then free
340341
* the extra allocations afterwards.
341342
*/
342-
chunksz_t padded_sz = bytes_to_chunksz(h, bytes + align - gap);
343+
chunksz_t padded_sz = bytes_to_chunksz(h, bytes, align - gap);
343344
chunkid_t c0 = alloc_chunk(h, padded_sz);
344345

345346
if (c0 == 0) {
@@ -387,13 +388,10 @@ static bool inplace_realloc(struct sys_heap *heap, void *ptr, size_t bytes)
387388
{
388389
struct z_heap *h = heap->heap;
389390

390-
if (size_too_big(h, bytes)) {
391-
return false;
392-
}
393-
394391
chunkid_t c = mem_to_chunkid(h, ptr);
395392
size_t align_gap = (uint8_t *)ptr - (uint8_t *)chunk_mem(h, c);
396-
chunksz_t chunks_need = bytes_to_chunksz(h, bytes + align_gap);
393+
394+
chunksz_t chunks_need = bytes_to_chunksz(h, bytes, align_gap);
397395

398396
if (chunk_size(h, c) == chunks_need) {
399397
/* We're good already */

lib/heap/heap.h

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,25 @@ static inline chunksz_t chunksz(size_t bytes)
232232
return (bytes + CHUNK_UNIT - 1U) / CHUNK_UNIT;
233233
}
234234

235-
static inline chunksz_t bytes_to_chunksz(struct z_heap *h, size_t bytes)
235+
/**
236+
* Convert the number of requested bytes to chunks and clamp it to facilitate
237+
* error handling. As some of the heap is used for metadata, there will never
238+
* be enough space for 'end_chunk' chunks. Also note that since 'size_t' may
239+
* be 64-bits wide, clamping guards against overflow when converting to the
240+
* 32-bit wide 'chunksz_t'.
241+
*/
242+
static ALWAYS_INLINE chunksz_t bytes_to_chunksz(struct z_heap *h, size_t bytes, size_t extra)
236243
{
237-
return chunksz(chunk_header_bytes(h) + bytes);
244+
size_t chunks = (bytes / CHUNK_UNIT) + (extra / CHUNK_UNIT);
245+
size_t oddments = ((bytes % CHUNK_UNIT) + (extra % CHUNK_UNIT) +
246+
chunk_header_bytes(h) + CHUNK_UNIT - 1U) / CHUNK_UNIT;
247+
248+
return (chunksz_t)MIN(chunks + oddments, h->end_chunk);
238249
}
239250

240251
static inline chunksz_t min_chunk_size(struct z_heap *h)
241252
{
242-
return bytes_to_chunksz(h, 1);
253+
return chunksz(chunk_header_bytes(h) + 1);
243254
}
244255

245256
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)
253264
return 31 - __builtin_clz(usable_sz);
254265
}
255266

256-
static inline bool size_too_big(struct z_heap *h, size_t bytes)
257-
{
258-
/*
259-
* Quick check to bail out early if size is too big.
260-
* Also guards against potential arithmetic overflows elsewhere.
261-
*/
262-
return (bytes / CHUNK_UNIT) >= h->end_chunk;
263-
}
264-
265267
static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes,
266268
size_t *free_bytes)
267269
{

0 commit comments

Comments
 (0)