Implement mallocarray()

A function used only in the OpenBSD-Kernel as of now, but it surely
provides a helpful interface when you just don't want to make sure
the incoming pointer to erealloc() is really NULL so it behaves
like malloc, making it a bit more safer.

Talking about *allocarray(): It's definitely a major step in code-
hardening. Especially as a system administrator, you should be
able to trust your core tools without having to worry about segfaults
like this, which can easily lead to privilege escalation.

How do the GNU coreutils handle this?
$ strings -n 4611686018427387903
strings: invalid minimum string length -1
$ strings -n 4611686018427387904
strings: invalid minimum string length 0

They silently overflow...

In comparison, sbase:

$ strings -n 4611686018427387903
mallocarray: out of memory
$ strings -n 4611686018427387904
mallocarray: out of memory

The first out of memory is actually a true OOM returned by malloc,
whereas the second one is a detected overflow, which is not marked
in a special way.
Now tell me which diagnostic error-messages are easier to understand.
This commit is contained in:
FRIGN 2015-03-10 22:19:19 +01:00
parent 3b825735d8
commit 3c33abc520
13 changed files with 74 additions and 23 deletions

View File

@ -54,6 +54,7 @@ LIBUTILSRC =\
libutil/fnck.c\
libutil/getlines.c\
libutil/human.c\
libutil/mallocarray.c\
libutil/md5.c\
libutil/mode.c\
libutil/putword.c\

2
col.c
View File

@ -177,7 +177,7 @@ allocbuf(void)
{
char **bp;
buff = ereallocarray(buff, pagsize, sizeof(*buff));
buff = emallocarray(pagsize, sizeof(*buff));
for (bp = buff; bp < &buff[pagsize]; ++bp)
*bp = emalloc(NCOLS);
}

2
cut.c
View File

@ -56,7 +56,7 @@ parselist(char *str)
if (*s == ',')
n++;
}
r = ereallocarray(r, n, sizeof(*r));
r = emallocarray(n, sizeof(*r));
for (s = str; n; n--, s++) {
r->min = (*s == '-') ? 1 : strtoul(s, &s, 10);
r->max = (*s == '-') ? strtoul(s + 1, &s, 10) : r->min;

8
find.c
View File

@ -595,7 +595,7 @@ get_exec_arg(char *argv[], Extra *extra)
e->u.p.arglen = e->u.p.filelen = 0;
e->u.p.first = e->u.p.next = arg - argv - 1;
e->u.p.cap = (arg - argv) * 2;
e->argv = ereallocarray(e->argv, e->u.p.cap, sizeof(*e->argv));
e->argv = emallocarray(e->u.p.cap, sizeof(*e->argv));
for (arg = argv, new = e->argv; *arg; arg++, new++) {
*new = *arg;
@ -604,7 +604,7 @@ get_exec_arg(char *argv[], Extra *extra)
arg++; /* due to our extra NULL */
} else {
e->argv = argv;
e->u.s.braces = ereallocarray(e->u.s.braces, ++nbraces, sizeof(*e->u.s.braces)); /* ++ for NULL */
e->u.s.braces = emallocarray(++nbraces, sizeof(*e->u.s.braces)); /* ++ for NULL */
for (arg = argv, braces = e->u.s.braces; *arg; arg++)
if (!strcmp(*arg, "{}"))
@ -632,7 +632,7 @@ get_ok_arg(char *argv[], Extra *extra)
*arg = NULL;
o->argv = argv;
o->braces = ereallocarray(o->braces, ++nbraces, sizeof(*o->braces));
o->braces = emallocarray(++nbraces, sizeof(*o->braces));
for (arg = argv, braces = o->braces; *arg; arg++)
if (!strcmp(*arg, "{}"))
@ -824,7 +824,7 @@ parse(int argc, char **argv)
* https://en.wikipedia.org/wiki/Shunting-yard_algorithm
* read from infix, resulting rpn ends up in rpn, next position in rpn is out
* push operators onto stack, next position in stack is top */
rpn = ereallocarray(rpn, ntok + gflags.print, sizeof(*rpn));
rpn = emallocarray(ntok + gflags.print, sizeof(*rpn));
for (tok = infix, out = rpn, top = stack; tok->type != END; tok++) {
switch (tok->type) {
case PRIM: *out++ = *tok; break;

50
libutil/mallocarray.c Normal file
View File

@ -0,0 +1,50 @@
/*
* 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/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "../util.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 (1UL << (sizeof(size_t) * 4))
void *
mallocarray(size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
errno = ENOMEM;
return NULL;
}
return malloc(nmemb * size);
}
void *
emallocarray(size_t nmemb, size_t size)
{
void *p;
if (!(p = mallocarray(nmemb, size)))
eprintf("mallocarray: out of memory\n");
return p;
}

View File

@ -1,4 +1,3 @@
/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*

4
ls.c
View File

@ -269,7 +269,7 @@ usage(void)
int
main(int argc, char *argv[])
{
struct entry *ents = NULL;
struct entry *ents;
size_t i;
ARGBEGIN {
@ -341,7 +341,7 @@ main(int argc, char *argv[])
if (argc == 0)
*--argv = ".", argc++;
ents = ereallocarray(ents, argc, sizeof(*ents));
ents = emallocarray(argc, sizeof(*ents));
for (i = 0; i < argc; i++)
mkent(&ents[i], argv[i], 1, Hflag || Lflag);

View File

@ -85,8 +85,8 @@ usage(void)
int
main(int argc, char *argv[])
{
struct fdescr *dsc = NULL;
Rune *delim = NULL;
struct fdescr *dsc;
Rune *delim;
size_t i, len;
int seq = 0;
char *adelim = "\t";
@ -107,11 +107,11 @@ main(int argc, char *argv[])
/* populate delimiters */
unescape(adelim);
delim = ereallocarray(delim, utflen(adelim) + 1, sizeof(*delim));
delim = emallocarray(utflen(adelim) + 1, sizeof(*delim));
len = utftorunestr(adelim, delim);
/* populate file list */
dsc = ereallocarray(dsc, argc, sizeof(*dsc));
dsc = emallocarray(argc, sizeof(*dsc));
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "-") == 0)

View File

@ -111,7 +111,7 @@ main(int argc, char *argv[])
break;
case 'c':
unescape(arg);
rarg = ereallocarray(rarg, utflen(arg) + 1, sizeof(*rarg));
rarg = emallocarray(utflen(arg) + 1, sizeof(*rarg));
utftorunestr(arg, rarg);
efputrune(rarg, stdout, "<stdout>");
free(rarg);
@ -125,7 +125,7 @@ main(int argc, char *argv[])
if (arg[j] == '\'' || arg[j] == '\"') {
arg += j + 1;
unescape(arg);
rarg = ereallocarray(rarg, utflen(arg) + 1, sizeof(*rarg));
rarg = emallocarray(utflen(arg) + 1, sizeof(*rarg));
utftorunestr(arg, rarg);
num = rarg[0];
} else

5
sed.c
View File

@ -596,10 +596,9 @@ chompr(char *s, Rune rune)
Rune *
strtorunes(char *s, size_t nrunes)
{
Rune *rs = NULL, *rp;
Rune *rs, *rp;
rs = ereallocarray(rs, nrunes + 1, sizeof(*rs));
rp = rs;
rp = rs = emallocarray(nrunes + 1, sizeof(*rs));
while (nrunes--)
s += chartorune(rp++, s);

View File

@ -11,11 +11,11 @@ static char *format = "";
static void
strings(FILE *fp, const char *fname, size_t len)
{
Rune r, *rbuf = NULL;
Rune r, *rbuf;
size_t i, bread;
off_t off;
rbuf = ereallocarray(rbuf, len, sizeof(*rbuf));
rbuf = emallocarray(len, sizeof(*rbuf));
for (off = 0, i = 0; (bread = efgetrune(&r, fp, fname)); ) {
off += bread;

6
tr.c
View File

@ -71,16 +71,16 @@ rstrmatch(Rune *r, char *s, size_t n)
static size_t
makeset(char *str, struct range **set, int (**check)(Rune))
{
Rune *rstr = NULL;
Rune *rstr;
size_t len, i, j, m, n;
size_t q, setranges = 0;
int factor, base;
/* rstr defines at most len ranges */
unescape(str);
rstr = ereallocarray(rstr, utflen(str) + 1, sizeof(*rstr));
rstr = emallocarray(utflen(str) + 1, sizeof(*rstr));
len = utftorunestr(str, rstr);
*set = ereallocarray(*set, len, sizeof(**set));
*set = emallocarray(len, sizeof(**set));
for (i = 0; i < len; i++) {
if (rstr[i] == '[') {

2
util.h
View File

@ -25,6 +25,8 @@ void apathmax(char **, size_t *);
void *ecalloc(size_t, size_t);
void *emalloc(size_t);
void *mallocarray(size_t, size_t);
void *emallocarray(size_t, size_t);
void *erealloc(void *, size_t);
void *reallocarray(void *, size_t, size_t);
void *ereallocarray(void *, size_t, size_t);