src/arc4random_unix.h
src/arc4random_win.h
src/closefrom.c
+ src/freezero.c
src/getentropy_aix.c
src/getentropy_bsd.c
src/getentropy_hpux.c
src/getentropy_win.c
src/readpassphrase.c
src/reallocarray.c
+ src/recallocarray.c
src/strlcat.c
src/strlcpy.c
Copyright:
Todd C. Miller <Todd.Miller@courtesan.com>
Copyright © 2004 Ted Unangst
Copyright © 2008 Damien Miller <djm@openbsd.org>
- Copyright © 2008 Otto Moerbeek <otto@drijf.net>
+ Copyright © 2008, 2010-2011, 2016-2017 Otto Moerbeek <otto@drijf.net>
Copyright © 2013 Markus Friedl <markus@openbsd.org>
Copyright © 2014 Bob Beck <beck@obtuse.com>
Copyright © 2014 Brent Cook <bcook@openbsd.org>
(defined(__GLIBC__) && (!__GLIBC_PREREQ(2, 26) || !defined(_GNU_SOURCE)))
void *reallocarray(void *ptr, size_t nmemb, size_t size);
#endif
+void *recallocarray(void *ptr, size_t oldnmemb, size_t nmemb, size_t size);
+void freezero(void *ptr, size_t size);
long long strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
fgetln.3bsd \
fgetwln.3bsd \
flopen.3bsd \
+ freezero.3bsd \
fmtcheck.3bsd \
fparseln.3bsd \
fpurge.3bsd \
readpassphrase.3bsd \
reallocarray.3bsd \
reallocf.3bsd \
+ recallocarray.3bsd \
setmode.3bsd \
setproctitle.3bsd \
setproctitle_init.3bsd \
--- /dev/null
+.so man3/reallocarray.3bsd
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $OpenBSD: malloc.3,v 1.78 2014/05/01 18:41:59 jmc Exp $
+.\" $OpenBSD: malloc.3,v 1.126 2019/09/14 13:16:50 otto Exp $
.\"
-.Dd $Mdocdate: May 1 2014 $
+.Dd $Mdocdate: September 14 2019 $
.Dt REALLOCARRAY 3bsd
.Os
.Sh NAME
-.Nm reallocarray
+.Nm reallocarray ,
+.Nm recallocarray ,
+.Nm freezero
.Nd memory allocation and deallocation
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
for include usage.)
.Ft void *
.Fn reallocarray "void *ptr" "size_t nmemb" "size_t size"
+.Ft void *
+.Fn recallocarray "void *ptr" "size_t oldnmemb" "size_t nmemb" "size_t size"
+.Ft void
+.Fn freezero "void *ptr" "size_t size"
.Sh DESCRIPTION
.Pp
-When using
+Designed for safe allocation of arrays,
+the
+.Fn reallocarray
+function is similar to
+.Fn realloc
+except it operates on
+.Fa nmemb
+members of size
+.Fa size
+and checks for integer overflow in the calculation
+.Fa nmemb
+*
+.Fa size .
+.Pp
+Used for the allocation of memory holding sensitive data,
+the
+.Fn recallocarray
+function guarantees that memory becoming unallocated is explicitly
+.Em discarded ,
+meaning cached free objects are cleared with
+.Xr explicit_bzero 3 .
+.Pp
+The
+.Fn recallocarray
+function is similar to
+.Fn reallocarray
+except it ensures newly allocated memory is cleared similar to
+.Fn calloc .
+If
+.Fa ptr
+is
+.Dv NULL ,
+.Fa oldnmemb
+is ignored and the call is equivalent to
+.Fn calloc .
+If
+.Fa ptr
+is not
+.Dv NULL ,
+.Fa oldnmemb
+must be a value such that
+.Fa oldnmemb
+*
+.Fa size
+is the size of the earlier allocation that returned
+.Fa ptr ,
+otherwise the behavior is undefined.
+The
+.Fn freezero
+function is similar to the
+.Fn free
+function except it ensures memory is explicitly discarded.
+If
+.Fa ptr
+is
+.Dv NULL ,
+no action occurs.
+If
+.Fa ptr
+is not
+.Dv NULL ,
+the
+.Fa size
+argument must be equal to or smaller than the size of the earlier allocation
+that returned
+.Fa ptr .
+.Fn freezero
+guarantees the memory range starting at
+.Fa ptr
+with length
+.Fa size
+is discarded while deallocating the whole object originally allocated.
+.Sh RETURN VALUES
+The
+.Fn reallocarray
+and
+.Fn recallocarray
+functions return a pointer to the allocated space if successful; otherwise,
+a null pointer is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Pp
+If multiplying
+.Fa nmemb
+and
+.Fa size
+results in integer overflow,
+.Fn reallocarray
+and
+.Fn recallocarray
+return
+.Dv NULL
+and set
+.Va errno
+to
+.Er ENOMEM .
+.Pp
+If
+.Fa ptr
+is not
+.Dv NULL
+and multiplying
+.Fa oldnmemb
+and
+.Fa size
+results in integer overflow
+.Fn recallocarray
+returns
+.Dv NULL
+and sets
+.Va errno
+to
+.Er EINVAL .
+.Sh IDIOMS
+Consider
+.Fn calloc
+or the extensions
+.Fn reallocarray
+and
+.Fn recallocarray
+when there is multiplication in the
+.Fa size
+argument of
.Fn malloc
-be careful to avoid the following idiom:
+or
+.Fn realloc .
+For example, avoid this common idiom as it may lead to integer overflow:
.Bd -literal -offset indent
if ((p = malloc(num * size)) == NULL)
- err(1, "malloc");
+ err(1, NULL);
.Ed
.Pp
-The multiplication may lead to an integer overflow, which can
-be avoided using the extension
-.Fn reallocarray ,
-as follows:
+A drop-in replacement is
+.Fn reallocarray :
.Bd -literal -offset indent
if ((p = reallocarray(NULL, num, size)) == NULL)
- err(1, "malloc");
+ err(1, NULL);
.Ed
.Pp
-Alternatively
+Alternatively,
.Fn calloc
-is a more portable solution which comes with the cost of clearing memory.
+may be used at the cost of initialization overhead.
.Pp
-If
-.Fn malloc
-must be used, be sure to test for overflow:
+When using
+.Fn realloc ,
+be careful to avoid the following idiom:
+.Bd -literal -offset indent
+size += 50;
+if ((p = realloc(p, size)) == NULL)
+ return (NULL);
+.Ed
+.Pp
+Do not adjust the variable describing how much memory has been allocated
+until the allocation has been successful.
+This can cause aberrant program behavior if the incorrect size value is used.
+In most cases, the above sample will also result in a leak of memory.
+As stated earlier, a return value of
+.Dv NULL
+indicates that the old object still remains allocated.
+Better code looks like this:
.Bd -literal -offset indent
-if (size && num > SIZE_MAX / size) {
- errno = ENOMEM;
- err(1, "overflow");
+newsize = size + 50;
+if ((newp = realloc(p, newsize)) == NULL) {
+ free(p);
+ p = NULL;
+ size = 0;
+ return (NULL);
}
+p = newp;
+size = newsize;
+.Ed
+.Pp
+As with
+.Fn malloc ,
+it is important to ensure the new size value will not overflow;
+i.e. avoid allocations like the following:
+.Bd -literal -offset indent
+if ((newp = realloc(p, num * size)) == NULL) {
+ ...
+.Ed
+.Pp
+Instead, use
+.Fn reallocarray :
+.Bd -literal -offset indent
+if ((newp = reallocarray(p, num, size)) == NULL) {
+ ...
+.Ed
+.Pp
+Calling
+.Fn realloc
+with a
+.Dv NULL
+.Fa ptr
+is equivalent to calling
+.Fn malloc .
+Instead of this idiom:
+.Bd -literal -offset indent
+if (p == NULL)
+ newp = malloc(newsize);
+else
+ newp = realloc(p, newsize);
+.Ed
+.Pp
+Use the following:
+.Bd -literal -offset indent
+newp = realloc(p, newsize);
.Ed
.Pp
-The use of
-.Fn reallocarray
-or
-.Fn calloc
-is strongly encouraged when allocating multiple sized objects
-in order to avoid possible integer overflows.
-.Sh RETURN VALUES
The
-.Fn reallocarray
-function returns a pointer to the allocated space if successful; otherwise,
-a null pointer is returned and
-.Va errno
-is set to
-.Er ENOMEM .
+.Fn recallocarray
+function should be used for resizing objects containing sensitive data like
+keys.
+To avoid leaking information,
+it guarantees memory is cleared before placing it on the internal free list.
+Deallocation of such an object should be done by calling
+.Fn freezero .
+
.Sh SEE ALSO
.Xr malloc 3 ,
.Xr calloc 3 ,
.Xr alloca 3
.Sh HISTORY
+The
.Fn reallocarray
-appeared in
+function appeared in
.Ox 5.6 ,
-glibc 2.26.
+and glibc 2.26.
+The
+.Fn recallocarray
+function appeared in
+.Ox 6.1 .
+The
+.Fn freezero
+function appeared in
+.Ox 6.2 .
--- /dev/null
+.so man3/reallocarray.3bsd
expand_number.c \
explicit_bzero.c \
fgetln.c \
+ freezero.c \
fgetwln.c \
flopen.c \
fmtcheck.c \
readpassphrase.c \
reallocarray.c \
reallocf.c \
+ recallocarray.c \
setmode.c \
setproctitle.c \
strlcat.c \
--- /dev/null
+/* $OpenBSD: malloc.c,v 1.267 2020/11/23 15:42:11 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+void
+freezero(void *ptr, size_t sz)
+{
+ /* This is legal. */
+ if (ptr == NULL)
+ return;
+
+ explicit_bzero(ptr, sz);
+ free(ptr);
+}
LIBBSD_0.11.0 {
strnvisx;
+
+ recallocarray;
+ freezero;
} LIBBSD_0.10.0;
--- /dev/null
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * 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 ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ newnmemb > 0 && SIZE_MAX / newnmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ newsize = newnmemb * size;
+
+ if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
+ errno = EINVAL;
+ return NULL;
+ }
+ oldsize = oldnmemb * size;
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}