Add allocarray(), an overflow-safe allocation function.
authormmcc <mmcc@openbsd.org>
Fri, 16 Oct 2015 03:17:56 +0000 (03:17 +0000)
committermmcc <mmcc@openbsd.org>
Fri, 16 Oct 2015 03:17:56 +0000 (03:17 +0000)
We avoided reallocation support because it demands more fancy footwork
to deal with the prepended link struct.

This has been on my mind for a while, and a 2010 security review of mksh
by the Android security team's Chris Palmer suggested it.

ok nicm@. Also discussed with millert@ and tedu@.

bin/ksh/alloc.c

index 7e41c2c..3a6b35a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: alloc.c,v 1.8 2008/07/21 17:30:08 millert Exp $       */
+/*     $OpenBSD: alloc.c,v 1.9 2015/10/16 03:17:56 mmcc Exp $  */
 /*
  * Copyright (c) 2002 Marc Espie.
  *
@@ -28,6 +28,7 @@
  * area-based allocation built on malloc/free
  */
 
+#include <stdint.h>
 #include "sh.h"
 
 struct link {
@@ -74,6 +75,30 @@ alloc(size_t size, Area *ap)
        return L2P(l);
 }
 
+/*
+ * Copied from calloc().
+ *
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW        (1UL << (sizeof(size_t) * 4))
+
+void *
+allocarray(size_t nmemb, size_t size, Area *ap)
+{
+       /* condition logic cloned from calloc() */
+       if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+           nmemb > 0 && SIZE_MAX / nmemb < size) {
+               internal_errorf(1, "unable to allocate memory");
+       }
+
+       /* additional check because alloc() allocates space for link */
+       if (nmemb * size > SIZE_MAX - sizeof(struct link))
+               internal_errorf(1, "unable to allocate memory");
+
+       return alloc(nmemb * size, ap);
+}
+
 void *
 aresize(void *ptr, size_t size, Area *ap)
 {