Browse Source

[malloc] Guard against unsigned integer overflow

Commit f3fbb5f ("[malloc] Avoid integer overflow for excessively large
memory allocations") fixed signed integer overflow issues caused by
the use of ssize_t, but did not guard against unsigned integer
overflow.

Add explicit checks for unsigned integer overflow where needed.  As a
side bonus, erroneous calls to malloc_dma() with an (illegal) size of
zero will now fail cleanly.

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

+ 13
- 2
src/core/malloc.c View File

291
 	 */
291
 	 */
292
 	actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
292
 	actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
293
 			~( MIN_MEMBLOCK_SIZE - 1 ) );
293
 			~( MIN_MEMBLOCK_SIZE - 1 ) );
294
+	if ( ! actual_size ) {
295
+		/* The requested size is not permitted to be zero.  A
296
+		 * zero result at this point indicates that either the
297
+		 * original requested size was zero, or that unsigned
298
+		 * integer overflow has occurred.
299
+		 */
300
+		ptr = NULL;
301
+		goto done;
302
+	}
294
 	assert ( actual_size >= size );
303
 	assert ( actual_size >= size );
295
 	align_mask = ( ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 ) );
304
 	align_mask = ( ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 ) );
296
-	assert ( ( actual_size + align_mask ) > actual_size );
297
 
305
 
298
 	DBGC2 ( &heap, "Allocating %#zx (aligned %#zx+%zx)\n",
306
 	DBGC2 ( &heap, "Allocating %#zx (aligned %#zx+%zx)\n",
299
 		size, align, offset );
307
 		size, align, offset );
302
 		list_for_each_entry ( block, &free_blocks, list ) {
310
 		list_for_each_entry ( block, &free_blocks, list ) {
303
 			pre_size = ( ( offset - virt_to_phys ( block ) )
311
 			pre_size = ( ( offset - virt_to_phys ( block ) )
304
 				     & align_mask );
312
 				     & align_mask );
305
-			if ( block->size < ( pre_size + actual_size ) )
313
+			if ( ( block->size < pre_size ) ||
314
+			     ( ( block->size - pre_size ) < actual_size ) )
306
 				continue;
315
 				continue;
307
 			post_size = ( block->size - pre_size - actual_size );
316
 			post_size = ( block->size - pre_size - actual_size );
308
 			/* Split block into pre-block, block, and
317
 			/* Split block into pre-block, block, and
506
 	if ( new_size ) {
515
 	if ( new_size ) {
507
 		new_total_size = ( new_size +
516
 		new_total_size = ( new_size +
508
 				   offsetof ( struct autosized_block, data ) );
517
 				   offsetof ( struct autosized_block, data ) );
518
+		if ( new_total_size < new_size )
519
+			return NULL;
509
 		new_block = alloc_memblock ( new_total_size, 1, 0 );
520
 		new_block = alloc_memblock ( new_total_size, 1, 0 );
510
 		if ( ! new_block )
521
 		if ( ! new_block )
511
 			return NULL;
522
 			return NULL;

Loading…
Cancel
Save