summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkp <kp@FreeBSD.org>2018-01-20 23:46:03 +0000
committerkp <kp@FreeBSD.org>2018-01-20 23:46:03 +0000
commit62408e87e823d2ddedd2b5c3859fecfa3e0530aa (patch)
tree1abd6a23b349e8f7fb99a77b977de77cf7c209d4
parent0478c432b800de4237b5995a8e1a99ef45b48788 (diff)
downloadFreeBSD-src-62408e87e823d2ddedd2b5c3859fecfa3e0530aa.zip
FreeBSD-src-62408e87e823d2ddedd2b5c3859fecfa3e0530aa.tar.gz
MFC r327674, r327796
Introduce mallocarray() in the kernel Similar to calloc() the mallocarray() function checks for integer overflows before allocating memory. It does not zero memory, unless the M_ZERO flag is set. Additionally, move the overflow check logic out to WOULD_OVERFLOW() for consumers to have a common means of testing for overflowing allocations. WOULD_OVERFLOW() should be a secondary check -- on 64-bit platforms, just because an allocation won't overflow size_t does not mean it is a sane size to request. Callers should be imposing reasonable allocation limits far, far, below overflow. Obtained from: OpenBSD
-rw-r--r--share/man/man9/malloc.920
-rw-r--r--sys/kern/kern_malloc.c11
-rw-r--r--sys/sys/malloc.h18
3 files changed, 48 insertions, 1 deletions
diff --git a/share/man/man9/malloc.9 b/share/man/man9/malloc.9
index 81d40dc..bd26600 100644
--- a/share/man/man9/malloc.9
+++ b/share/man/man9/malloc.9
@@ -29,7 +29,7 @@
.\" $NetBSD: malloc.9,v 1.3 1996/11/11 00:05:11 lukem Exp $
.\" $FreeBSD$
.\"
-.Dd November 19, 2015
+.Dd January 10, 2018
.Dt MALLOC 9
.Os
.Sh NAME
@@ -45,6 +45,8 @@
.In sys/malloc.h
.Ft void *
.Fn malloc "unsigned long size" "struct malloc_type *type" "int flags"
+.Ft void *
+.Fn mallocarray "size_t nmemb" "size_t size" "struct malloc_type *type" "int flags"
.Ft void
.Fn free "void *addr" "struct malloc_type *type"
.Ft void *
@@ -64,6 +66,14 @@ object whose size is specified by
.Fa size .
.Pp
The
+.Fn mallocarray
+function allocates uninitialized memory in kernel address space for an
+array of
+.Fa nmemb
+entries whose size is specified by
+.Fa size .
+.Pp
+The
.Fn free
function releases memory at address
.Fa addr
@@ -144,6 +154,7 @@ If the request cannot be immediately fulfilled, the current process is put
to sleep to wait for resources to be released by other processes.
The
.Fn malloc ,
+.Fn mallocarray ,
.Fn realloc ,
and
.Fn reallocf
@@ -152,6 +163,13 @@ functions cannot return
if
.Dv M_WAITOK
is specified.
+if the multiplication of
+.Fa nmemb
+and
+.Fa size
+would cause an integer overflow, the
+.Fn mallocarray
+function induces a panic.
.It Dv M_USE_RESERVE
Indicates that the system can use its reserve of memory to satisfy the
request.
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index e6bc60c..410a971 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -2,6 +2,7 @@
* Copyright (c) 1987, 1991, 1993
* The Regents of the University of California.
* Copyright (c) 2005-2009 Robert N. M. Watson
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> (mallocarray)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -526,6 +527,16 @@ malloc(unsigned long size, struct malloc_type *mtp, int flags)
return ((void *) va);
}
+void *
+mallocarray(size_t nmemb, size_t size, struct malloc_type *type, int flags)
+{
+
+ if (WOULD_OVERFLOW(nmemb, size))
+ panic("mallocarray: %zu * %zu overflowed", nmemb, size);
+
+ return (malloc(size * nmemb, type, flags));
+}
+
/*
* free:
*
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index f94dd3b..70c33a8 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -39,6 +39,7 @@
#include <sys/queue.h>
#include <sys/_lock.h>
#include <sys/_mutex.h>
+#include <machine/_limits.h>
#define MINALLOCSIZE UMA_SMALLEST_UNIT
@@ -175,6 +176,9 @@ void *contigmalloc(unsigned long size, struct malloc_type *type, int flags,
void free(void *addr, struct malloc_type *type);
void *malloc(unsigned long size, struct malloc_type *type, int flags)
__malloc_like __result_use_check __alloc_size(1);
+void *mallocarray(size_t nmemb, size_t size, struct malloc_type *type,
+ int flags) __malloc_like __result_use_check
+ __alloc_size(1) __alloc_size(2);
void malloc_init(void *);
int malloc_last_fail(void);
void malloc_type_allocated(struct malloc_type *type, unsigned long size);
@@ -187,6 +191,20 @@ void *reallocf(void *addr, unsigned long size, struct malloc_type *type,
int flags) __result_use_check __alloc_size(2);
struct malloc_type *malloc_desc2type(const char *desc);
+
+/*
+ * 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) * 8 / 2))
+static inline bool
+WOULD_OVERFLOW(size_t nmemb, size_t size)
+{
+
+ return ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && __SIZE_T_MAX / nmemb < size);
+}
+#undef MUL_NO_OVERFLOW
#endif /* _KERNEL */
#endif /* !_SYS_MALLOC_H_ */
OpenPOWER on IntegriCloud