[rtems commit] Fix calloc() behaviour in case of overflow

Sebastian Huber sebh at rtems.org
Wed Apr 21 05:03:26 UTC 2021


Module:    rtems
Branch:    master
Commit:    51defd927427b5b74c3a0c0f0b5c161929547cfc
Changeset: http://git.rtems.org/rtems/commit/?id=51defd927427b5b74c3a0c0f0b5c161929547cfc

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Apr 20 19:30:35 2021 +0200

Fix calloc() behaviour in case of overflow

The multiplication to calculate the length of the memory area to
allocate may overflow.  Return NULL in case of an overflow.

Close #4389.

---

 cpukit/libcsupport/src/calloc.c       | 13 ++++++++++++-
 cpukit/libcsupport/src/rtemscalloc.c  |  9 ++++++++-
 testsuites/libtests/malloctest/init.c | 23 +++++++++++++----------
 3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/cpukit/libcsupport/src/calloc.c b/cpukit/libcsupport/src/calloc.c
index e015f30..693aa21 100644
--- a/cpukit/libcsupport/src/calloc.c
+++ b/cpukit/libcsupport/src/calloc.c
@@ -20,7 +20,10 @@
 
 #if defined(RTEMS_NEWLIB) && !defined(HAVE_CALLOC)
 #include <stdlib.h>
+
+#include <errno.h>
 #include <string.h>
+
 #include <rtems/score/basedefs.h>
 
 void *calloc(
@@ -31,7 +34,15 @@ void *calloc(
   void   *cptr;
   size_t  length;
 
-  length = nelem * elsize;
+  if ( nelem == 0 ) {
+    length = 0;
+  } else if ( elsize > SIZE_MAX / nelem ) {
+    errno = ENOMEM;
+    return NULL;
+  } else {
+    length = nelem * elsize;
+  }
+
   cptr = malloc( length );
   RTEMS_OBFUSCATE_VARIABLE( cptr );
   if ( RTEMS_PREDICT_FALSE( cptr == NULL ) ) {
diff --git a/cpukit/libcsupport/src/rtemscalloc.c b/cpukit/libcsupport/src/rtemscalloc.c
index 4e189e8..836f1da 100644
--- a/cpukit/libcsupport/src/rtemscalloc.c
+++ b/cpukit/libcsupport/src/rtemscalloc.c
@@ -46,7 +46,14 @@ void *rtems_calloc( size_t nelem, size_t elsize )
   size_t  length;
   void   *p;
 
-  length = nelem * elsize;
+  if ( nelem == 0 ) {
+    length = 0;
+  } else if ( elsize > SIZE_MAX / nelem ) {
+    return NULL;
+  } else {
+    length = nelem * elsize;
+  }
+
   p = rtems_malloc( length );
   RTEMS_OBFUSCATE_VARIABLE( p );
   if ( RTEMS_PREDICT_FALSE( p == NULL ) ) {
diff --git a/testsuites/libtests/malloctest/init.c b/testsuites/libtests/malloctest/init.c
index 1d91385..4d0f421 100644
--- a/testsuites/libtests/malloctest/init.c
+++ b/testsuites/libtests/malloctest/init.c
@@ -1190,6 +1190,14 @@ static void test_rtems_calloc(void)
   rtems_test_assert(p == NULL);
   rtems_test_assert(errno == 0);
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Walloc-size-larger-than=N"
+  errno = 0;
+  p = rtems_calloc(SIZE_MAX, SIZE_MAX);
+  rtems_test_assert(p == NULL);
+  rtems_test_assert(errno == 0);
+#pragma GCC diagnostic pop
+
   i = rtems_calloc(1, sizeof(*i));
   rtems_test_assert(i != NULL);
   rtems_test_assert(*i == 0);
@@ -1313,22 +1321,17 @@ rtems_task Init(
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Walloc-size-larger-than=N"
   p1 = calloc( 1, SIZE_MAX );
+  rtems_test_assert( p1 == NULL );
+
+  p1 = calloc( SIZE_MAX, SIZE_MAX );
+  rtems_test_assert( p1 == NULL );
 #pragma GCC diagnostic pop
-  if (p1) {
-    printf("ERROR on attempt to calloc SIZE_MAX block expected failure.");
-    free( p1 );
-  }
 
   /*
    * Verify error case where malloc of size 0.
    */
   p1 = malloc( 0 );
-  if (p1) {
-    printf("ERROR on attempt to malloc size 0 block expected failure.");
-    free( p1 );
-  }
-
-
+  rtems_test_assert( p1 == NULL );
 
   test_heap_initialize();
   test_heap_block_allocate();



More information about the vc mailing list