diff options
| author | christos <christos@NetBSD.org> | 2015-02-05 16:04:35 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2015-02-05 16:04:35 +0000 |
| commit | 0b3f5adb89b2d9b3337bbb3a7d33731e7ec14ffe (patch) | |
| tree | fa634c69a6037e2e11297bc6e962e7766b3a2970 /lib/libc/stdlib | |
| parent | f04055b7416901d536f54c00dc90050a664e5495 (diff) | |
Add and use reallocarray() to prevent a multiplication overflow in allocation.
Reported by Guido Vranken, thanks!
Diffstat (limited to 'lib/libc/stdlib')
| -rw-r--r-- | lib/libc/stdlib/Makefile.inc | 5 | ||||
| -rw-r--r-- | lib/libc/stdlib/malloc.3 | 77 | ||||
| -rw-r--r-- | lib/libc/stdlib/reallocarray.c | 41 |
3 files changed, 114 insertions, 9 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index f918e425b3e..fea0c954498 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.86 2015/01/18 17:59:36 christos Exp $ +# $NetBSD: Makefile.inc,v 1.87 2015/02/05 16:04:35 christos Exp $ # from: @(#)Makefile.inc 8.3 (Berkeley) 2/4/95 # stdlib sources @@ -12,7 +12,7 @@ SRCS+= _env.c _rand48.c \ lcong48.c lrand48.c lsearch.c merge.c mi_vector_hash.c mrand48.c \ nrand48.c putenv.c qabs.c qdiv.c qsort.c posix_openpt.c pty.c \ quick_exit.c radixsort.c rand.c rand_r.c random.c remque.c \ - seed48.c setenv.c srand48.c strsuftoll.c \ + reallocarray.c seed48.c setenv.c srand48.c strsuftoll.c \ strtoi.c strtou.c strtonum.c \ strtoimax.c strtol.c strtoll.c strtoq.c strtoul.c strtoull.c \ strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c \ @@ -74,6 +74,7 @@ MLINKS+=hcreate.3 hdestroy1.3 hcreate.3 hdestroy1_r.3 MLINKS+=insque.3 remque.3 MLINKS+=lsearch.3 lfind.3 MLINKS+=malloc.3 calloc.3 malloc.3 realloc.3 malloc.3 free.3 +MLINKS+=malloc.3 reallocarray.3 MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3 MLINKS+=ptsname.3 ptsname_r.3 MLINKS+=rand.3 rand_r.3 diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3 index 1b892c81f2b..9bf851b0805 100644 --- a/lib/libc/stdlib/malloc.3 +++ b/lib/libc/stdlib/malloc.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: malloc.3,v 1.38 2010/05/03 08:23:20 jruoho Exp $ +.\" $NetBSD: malloc.3,v 1.39 2015/02/05 16:04:35 christos Exp $ .\" .\" Copyright (c) 1980, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -34,11 +34,11 @@ .\" @(#)malloc.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD: src/lib/libc/stdlib/malloc.3,v 1.73 2007/06/15 22:32:33 jasone Exp $ .\" -.Dd May 3, 2010 +.Dd February 5, 2015 .Dt MALLOC 3 .Os .Sh NAME -.Nm malloc , calloc , realloc , free +.Nm malloc , calloc , realloc , reallocarray, free .Nd general purpose memory allocation functions .Sh LIBRARY .Lb libc @@ -50,6 +50,8 @@ .Fn calloc "size_t number" "size_t size" .Ft void * .Fn realloc "void *ptr" "size_t size" +.Ft void * +.Fn reallocarray "void *ptr" "size_t number" "size_t size" .Ft void .Fn free "void *ptr" .Sh DESCRIPTION @@ -74,7 +76,7 @@ The result is identical to calling with an argument of .Dq "number * size" , with the exception that the allocated memory is explicitly initialized -to zero bytes. +to zero bytes, and overflow is being checked. .Pp The .Fn realloc @@ -90,8 +92,22 @@ the value of the newly allocated portion of the memory is undefined. Upon success, the memory referenced by .Fa ptr is freed and a pointer to the newly allocated memory is returned. +.Pp +The +.Fn reallocarray +function is similar to +.Fn realloc +except it operates on +.Fa number +members of size +.Fa size +and checks for integer overflow in the calculation of\ +.Dq "number * size" . +.Pp Note that .Fn realloc +and +.Fn reallocarray may move the memory allocation, resulting in a different return value than .Fa ptr . If @@ -129,7 +145,9 @@ is set to .Pp The .Fn realloc -function returns a pointer, possibly identical to +and +.Fn reallocarray +functions return a pointer, possibly identical to .Fa ptr , to the allocated memory if successful; otherwise a @@ -141,7 +159,9 @@ is set to if the error was the result of an allocation failure. The .Fn realloc -function always leaves the original buffer intact +and +.Fn reallocarray +functions always leave the original buffer intact when an error occurs. .Pp The @@ -158,7 +178,7 @@ if ((p = malloc(number * size)) == NULL) .Pp The multiplication may lead to an integer overflow. To avoid this, -.Fn calloc +.Fn reallocarray is recommended. .Pp If @@ -171,6 +191,42 @@ if (size && number > SIZE_MAX / size) { } .Ed .Pp +The above test is not sufficient in all cases. +For example, multiplying ints requires a different set of checks: +.Bd -literal -offset indent +int num, size; +\&.\&.\&. + +/* Avoid invalid requests */ +if (size < 0 || num < 0) + errc(1, EOVERFLOW, "overflow"); + +/* Check for signed int overflow */ +if (size && num > INT_MAX / size) + errc(1, EOVERFLOW, "overflow"); + +if ((p = malloc(size * num)) == NULL) + err(1, "malloc"); +.Ed +.Pp +Assuming the implementation checks for integer overflow as +.Nx +does, it is much easier to use +.Fn calloc +or +.Fn reallocarray . +.Pp +The above examples could be simplified to: +.Bd -literal -offset indent +if ((p = reallocarray(NULL, num, size)) == NULL) + err(1, "reallocarray"); +.Ed +.Bd -literal -offset indent +or at the cost of initialization: +if ((p = calloc(num, size)) == NULL) + err(1, "calloc"); +.Ed +.Pp When using .Fn realloc , one must be careful to avoid the following idiom: @@ -227,3 +283,10 @@ and .Fn free functions conform to .St -isoC . +.Pp +The +.Fn reallocarray +function first appeared on +.Ox 5.6 +and +.Nx 8 . diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c new file mode 100644 index 00000000000..eaf9e8b34e4 --- /dev/null +++ b/lib/libc/stdlib/reallocarray.c @@ -0,0 +1,41 @@ +/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ +/* + * Copyright (c) 2008 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 <sys/cdefs.h> +__RCSID("$NetBSD: reallocarray.c,v 1.1 2015/02/05 16:04:35 christos Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.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) * (CHAR_BIT / 2))) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + size > 0 && nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} |
