diff mbox series

[3/6] xmalloc: guard against integer overflow

Message ID 043fa4ef-b46d-6ddf-8348-33b3bce69b3f@suse.com (mailing list archive)
State New, archived
Headers show
Series misc hardening and some cleanup | expand

Commit Message

Jan Beulich Feb. 5, 2020, 1:15 p.m. UTC
There are hypercall handling paths (EFI ones are what this was found
with) needing to allocate buffers of a caller specified size. This is
generally fine, as our page allocator enforces an upper bound on all
allocations. However, certain extremely large sizes could, when adding
in allocator overhead, result in an apparently tiny allocation size,
which would typically result in either a successful allocation, but a
severe buffer overrun when using that memory block, or in a crash right
in the allocator code.

Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
diff mbox series

Patch

--- a/xen/common/xmalloc_tlsf.c
+++ b/xen/common/xmalloc_tlsf.c
@@ -378,7 +378,17 @@  void *xmem_pool_alloc(unsigned long size
     int fl, sl;
     unsigned long tmp_size;
 
-    size = (size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : ROUNDUP_SIZE(size);
+    if ( size < MIN_BLOCK_SIZE )
+        size = MIN_BLOCK_SIZE;
+    else
+    {
+        tmp_size = ROUNDUP_SIZE(size);
+        /* Guard against overflow. */
+        if ( tmp_size < size )
+            return NULL;
+        size = tmp_size;
+    }
+
     /* Rounding up the requested size and calculating fl and sl */
 
     spin_lock(&pool->lock);
@@ -594,6 +604,10 @@  void *_xmalloc(unsigned long size, unsig
         align = MEM_ALIGN;
     size += align - MEM_ALIGN;
 
+    /* Guard against overflow. */
+    if ( size < align - MEM_ALIGN )
+        return NULL;
+
     if ( !xenpool )
         tlsf_init();
 
@@ -646,6 +660,10 @@  void *_xrealloc(void *ptr, unsigned long
         unsigned long tmp_size = size + align - MEM_ALIGN;
         const struct bhdr *b;
 
+        /* Guard against overflow. */
+        if ( tmp_size < size )
+            return NULL;
+
         if ( tmp_size < PAGE_SIZE )
             tmp_size = (tmp_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE :
                 ROUNDUP_SIZE(tmp_size);