Browse Source

[malloc] Avoid integer overflow for excessively large memory allocations

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
f3fbb5ff1c
1 changed files with 49 additions and 48 deletions
  1. 49
    48
      src/core/malloc.c

+ 49
- 48
src/core/malloc.c View File

@@ -275,7 +275,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
275 275
 	size_t align_mask;
276 276
 	size_t actual_size;
277 277
 	size_t pre_size;
278
-	ssize_t post_size;
278
+	size_t post_size;
279 279
 	struct memory_block *pre;
280 280
 	struct memory_block *post;
281 281
 	void *ptr;
@@ -291,7 +291,9 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
291 291
 	 */
292 292
 	actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
293 293
 			~( MIN_MEMBLOCK_SIZE - 1 ) );
294
+	assert ( actual_size >= size );
294 295
 	align_mask = ( ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 ) );
296
+	assert ( ( actual_size + align_mask ) > actual_size );
295 297
 
296 298
 	DBGC2 ( &heap, "Allocating %#zx (aligned %#zx+%zx)\n",
297 299
 		size, align, offset );
@@ -300,55 +302,54 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
300 302
 		list_for_each_entry ( block, &free_blocks, list ) {
301 303
 			pre_size = ( ( offset - virt_to_phys ( block ) )
302 304
 				     & align_mask );
305
+			if ( block->size < ( pre_size + actual_size ) )
306
+				continue;
303 307
 			post_size = ( block->size - pre_size - actual_size );
304
-			if ( post_size >= 0 ) {
305
-				/* Split block into pre-block, block, and
306
-				 * post-block.  After this split, the "pre"
307
-				 * block is the one currently linked into the
308
-				 * free list.
309
-				 */
310
-				pre   = block;
311
-				block = ( ( ( void * ) pre   ) + pre_size );
312
-				post  = ( ( ( void * ) block ) + actual_size );
313
-				DBGC2 ( &heap, "[%p,%p) -> [%p,%p) + [%p,%p)\n",
314
-					pre, ( ( ( void * ) pre ) + pre->size ),
315
-					pre, block, post,
316
-					( ( ( void * ) pre ) + pre->size ) );
317
-				/* If there is a "post" block, add it in to
318
-				 * the free list.  Leak it if it is too small
319
-				 * (which can happen only at the very end of
320
-				 * the heap).
321
-				 */
322
-				if ( (size_t) post_size >= MIN_MEMBLOCK_SIZE ) {
323
-					VALGRIND_MAKE_MEM_UNDEFINED
324
-						( post, sizeof ( *post ) );
325
-					post->size = post_size;
326
-					list_add ( &post->list, &pre->list );
327
-				}
328
-				/* Shrink "pre" block, leaving the main block
329
-				 * isolated and no longer part of the free
330
-				 * list.
331
-				 */
332
-				pre->size = pre_size;
333
-				/* If there is no "pre" block, remove it from
334
-				 * the list.  Also remove it (i.e. leak it) if
335
-				 * it is too small, which can happen only at
336
-				 * the very start of the heap.
337
-				 */
338
-				if ( pre_size < MIN_MEMBLOCK_SIZE ) {
339
-					list_del ( &pre->list );
340
-					VALGRIND_MAKE_MEM_NOACCESS
341
-						( pre, sizeof ( *pre ) );
342
-				}
343
-				/* Update total free memory */
344
-				freemem -= actual_size;
345
-				/* Return allocated block */
346
-				DBGC2 ( &heap, "Allocated [%p,%p)\n", block,
347
-					( ( ( void * ) block ) + size ) );
348
-				ptr = block;
349
-				VALGRIND_MAKE_MEM_UNDEFINED ( ptr, size );
350
-				goto done;
308
+			/* Split block into pre-block, block, and
309
+			 * post-block.  After this split, the "pre"
310
+			 * block is the one currently linked into the
311
+			 * free list.
312
+			 */
313
+			pre   = block;
314
+			block = ( ( ( void * ) pre   ) + pre_size );
315
+			post  = ( ( ( void * ) block ) + actual_size );
316
+			DBGC2 ( &heap, "[%p,%p) -> [%p,%p) + [%p,%p)\n", pre,
317
+				( ( ( void * ) pre ) + pre->size ), pre, block,
318
+				post, ( ( ( void * ) pre ) + pre->size ) );
319
+			/* If there is a "post" block, add it in to
320
+			 * the free list.  Leak it if it is too small
321
+			 * (which can happen only at the very end of
322
+			 * the heap).
323
+			 */
324
+			if ( post_size >= MIN_MEMBLOCK_SIZE ) {
325
+				VALGRIND_MAKE_MEM_UNDEFINED ( post,
326
+							      sizeof ( *post ));
327
+				post->size = post_size;
328
+				list_add ( &post->list, &pre->list );
351 329
 			}
330
+			/* Shrink "pre" block, leaving the main block
331
+			 * isolated and no longer part of the free
332
+			 * list.
333
+			 */
334
+			pre->size = pre_size;
335
+			/* If there is no "pre" block, remove it from
336
+			 * the list.  Also remove it (i.e. leak it) if
337
+			 * it is too small, which can happen only at
338
+			 * the very start of the heap.
339
+			 */
340
+			if ( pre_size < MIN_MEMBLOCK_SIZE ) {
341
+				list_del ( &pre->list );
342
+				VALGRIND_MAKE_MEM_NOACCESS ( pre,
343
+							     sizeof ( *pre ) );
344
+			}
345
+			/* Update total free memory */
346
+			freemem -= actual_size;
347
+			/* Return allocated block */
348
+			DBGC2 ( &heap, "Allocated [%p,%p)\n", block,
349
+				( ( ( void * ) block ) + size ) );
350
+			ptr = block;
351
+			VALGRIND_MAKE_MEM_UNDEFINED ( ptr, size );
352
+			goto done;
352 353
 		}
353 354
 
354 355
 		/* Try discarding some cached data to free up memory */

Loading…
Cancel
Save