• Address concerns of Chris Palmer from the Android security team

– possible integer overflows in memory allocation, mostly
    ‣ multiplication: all are checked now
    ‣ addition: reviewed them, most were “proven” or guessed to be
      “almost” impossible to run over (e.g. when we have a string
      whose length is taken it is assumed that the length will be
      more than only a few bytes below SIZE_MAX, since code and
      stack have to fit); some are checked now (e.g. when one of
      the summands is an off_t); most of the unchecked ones are
      annotated now
    ⇒ cost (MirBSD/i386 static): +76 .text
    ⇒ cost (Debian sid/i386): +779 .text  -4 .data
  – on Linux targets, setuid() setresuid() setresgid() can fail
    with EAGAIN; check for that and, if so, warn once and retry
    infinitely (other targets to be added later once we know that
    they are “insane”)
    ⇒ cost (Debian sid/i386): +192 .text (includes .rodata)
• setmode.c: Do overflow checking for realloc() too; switch back
  from calloc() to a checked malloc() for simplification while there
• define -DIN_MKSH and let setmode.c look a tad nicer while here
This commit is contained in:
tg 2010-09-14 21:26:19 +00:00
parent 08862021ee
commit 667d792d6a
18 changed files with 204 additions and 96 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.460 2010/09/14 21:15:09 tg Exp $'
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.461 2010/09/14 21:26:04 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
# Thorsten Glaser <tg@mirbsd.org>
@ -441,7 +441,7 @@ IRIX*)
: ${HAVE_SETLOCALE_CTYPE=0}
;;
Linux)
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN"
: ${HAVE_REVOKE=0}
;;
MidnightBSD)
@ -1427,11 +1427,11 @@ addsrcs '!' HAVE_SETMODE setmode.c
addsrcs '!' HAVE_STRLCPY strlcpy.c
addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && CPPFLAGS="$CPPFLAGS -DMKSH_PRINTF_BUILTIN"
test 0 = "$HAVE_SETMODE" && CPPFLAGS="$CPPFLAGS -DHAVE_CONFIG_H -DCONFIG_H_FILENAME=\\\"sh.h\\\""
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
$e $bi$me: Finished configuration testing, now producing output.$ao
CPPFLAGS="$CPPFLAGS -DIN_MKSH"
files=
objs=
sp=

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/Makefile,v 1.81 2010/08/24 15:19:53 tg Exp $
# $MirOS: src/bin/mksh/Makefile,v 1.82 2010/09/14 21:26:05 tg Exp $
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
# Thorsten Glaser <tg@mirbsd.org>
@ -43,7 +43,7 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 \
-DHAVE_SETMODE=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 \
-DHAVE_STRCASESTR=1 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 \
-DHAVE_REVOKE_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \
-DHAVE_PERSISTENT_HISTORY=1
-DHAVE_PERSISTENT_HISTORY=1 -DIN_MKSH
COPTS+= -std=gnu99 -Wall
.endif

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.391 2010/09/05 19:51:29 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.392 2010/09/14 21:26:07 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R39 2010/09/05
@(#)MIRBSD KSH R39 2010/09/14
description:
Check version of shell.
stdin:

24
edit.c
View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.200 2010/09/05 19:51:31 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.201 2010/09/14 21:26:09 tg Exp $");
/*
* in later versions we might use libtermcap for this, but since external
@ -424,7 +424,7 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
int i, path_order = 0;
info = (struct path_order_info *)
alloc(nwords * sizeof(struct path_order_info), ATEMP);
alloc2(nwords, sizeof(struct path_order_info), ATEMP);
for (i = 0; i < nwords; i++) {
info[i].word = words[i];
info[i].base = x_basename(words[i], NULL);
@ -678,13 +678,15 @@ glob_table(const char *pat, XPtrV *wp, struct table *tp)
static void
glob_path(int flags, const char *pat, XPtrV *wp, const char *lpath)
{
const char *sp, *p;
const char *sp = lpath, *p;
char *xp, **words;
int staterr, pathlen, patlen, oldsize, newsize, i, j;
size_t pathlen, patlen, oldsize, newsize, i, j;
int staterr;
XString xs;
patlen = strlen(pat) + 1;
sp = lpath;
patlen = strlen(pat);
checkoktoadd(patlen, 129 + X_EXTRA);
++patlen;
Xinit(xs, xp, patlen + 128, ATEMP);
while (sp) {
xp = Xstring(xs, xp);
@ -2466,7 +2468,7 @@ x_init_emacs(void)
ainit(AEDIT);
x_nextcmd = -1;
x_tab = alloc(X_NTABS * sizeof(*x_tab), AEDIT);
x_tab = alloc2(X_NTABS, sizeof(*x_tab), AEDIT);
for (j = 0; j < X_TABSZ; j++)
x_tab[0][j] = XFUNC_insert;
for (i = 1; i < X_NTABS; i++)
@ -2477,7 +2479,7 @@ x_init_emacs(void)
= x_defbindings[i].xdb_func;
#ifndef MKSH_SMALL
x_atab = alloc(X_NTABS * sizeof(*x_atab), AEDIT);
x_atab = alloc2(X_NTABS, sizeof(*x_atab), AEDIT);
for (i = 1; i < X_NTABS; i++)
for (j = 0; j < X_TABSZ; j++)
x_atab[i][j] = NULL;
@ -3912,7 +3914,7 @@ vi_cmd(int argcnt, const char *cmd)
{
static char alias[] = "_\0";
struct tbl *ap;
int olen, nlen;
size_t olen, nlen;
char *p, *nbuf;
/* lookup letter in alias list... */
@ -3929,6 +3931,10 @@ vi_cmd(int argcnt, const char *cmd)
nlen = strlen(ap->val.s) + 1;
olen = !macro.p ? 2 :
macro.len - (macro.p - macro.buf);
/*
* at this point, it's fairly reasonable that
* nlen + olen + 2 doesn't overflow
*/
nbuf = alloc(nlen + 1 + olen, APERM);
memcpy(nbuf, ap->val.s, nlen);
nbuf[nlen++] = cmd[1];

6
eval.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.92 2010/08/28 20:22:16 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.93 2010/09/14 21:26:10 tg Exp $");
/*
* string expansion
@ -1562,6 +1562,10 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
char *news;
int l1, l2, l3;
/*
* addition safe since these operate on
* one string (separate substrings)
*/
l1 = brace_start - start;
l2 = (p - 1) - field_start;
l3 = end - brace_end;

4
exec.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.81 2010/09/05 19:51:32 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.82 2010/09/14 21:26:11 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL "/bin/sh"
@ -101,7 +101,7 @@ execute(struct op *volatile t,
flags &= ~XTIME;
if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
e->savefd = alloc(NUFILE * sizeof(short), ATEMP);
e->savefd = alloc2(NUFILE, sizeof(short), ATEMP);
/* initialise to not redirected */
memset(e->savefd, 0, NUFILE * sizeof(short));
}

22
funcs.c
View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.161 2010/09/05 19:51:33 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.162 2010/09/14 21:26:12 tg Exp $");
#if HAVE_KILLPG
/*
@ -208,6 +208,7 @@ do_realpath(const char *upath)
afree(tp, ATEMP);
}
/* ipath and upath are in memory at the same time -> unchecked */
Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP);
while (*ip) {
@ -277,8 +278,15 @@ do_realpath(const char *upath)
}
/* get symlink(7) target */
if (pathcnd)
if (pathcnd) {
#ifdef NO_PATH_MAX
if (notoktoadd(pathlen, 1)) {
errno = ENAMETOOLONG;
goto notfound;
}
#endif
ldest = aresize(ldest, pathlen + 1, ATEMP);
}
llen = readlink(Xstring(xs, xp), ldest, pathlen);
if (llen < 0)
/* oops... */
@ -397,7 +405,7 @@ c_cd(const char **wp)
}
} else if (!wp[2]) {
/* Two arguments - substitute arg1 in PWD for arg2 */
int ilen, olen, nlen, elen;
size_t ilen, olen, nlen, elen;
char *cp;
if (!current_wd[0]) {
@ -413,6 +421,12 @@ c_cd(const char **wp)
bi_errorf("bad substitution");
return (1);
}
/*-
* ilen = part of current_wd before wp[0]
* elen = part of current_wd after wp[0]
* because current_wd and wp[1] need to be in memory at the
* same time beforehand the addition can stay unchecked
*/
ilen = cp - current_wd;
olen = strlen(wp[0]);
nlen = strlen(wp[1]);
@ -2381,7 +2395,7 @@ c_set(const char **wp)
while (*++wp != NULL)
strdupx(*wp, *wp, &l->area);
l->argc = wp - owp - 1;
l->argv = alloc((l->argc + 2) * sizeof(char *), &l->area);
l->argv = alloc2(l->argc + 2, sizeof(char *), &l->area);
for (wp = l->argv; (*wp++ = *owp++) != NULL; )
;
}

View File

@ -26,7 +26,7 @@
#include <sys/file.h>
#endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.101 2010/08/28 20:22:18 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.102 2010/09/14 21:26:13 tg Exp $");
/*-
* MirOS: This is the default mapping type, and need not be specified.
@ -92,6 +92,8 @@ c_fc(const char **wp)
sflag = true;
else {
size_t len = strlen(p);
/* almost certainly not overflowing */
editor = alloc(len + 4, ATEMP);
memcpy(editor, p, len);
memcpy(editor + len, " $_", 4);
@ -269,7 +271,17 @@ c_fc(const char **wp)
return (1);
}
n = stat(tf->name, &statb) < 0 ? 128 : statb.st_size + 1;
if (stat(tf->name, &statb) < 0)
n = 128;
else {
if (notoktoadd(statb.st_size, 1 + X_EXTRA)) {
bi_errorf(T_intovfl,
(unsigned long)statb.st_size, '+',
1UL + X_EXTRA);
goto errout;
}
n = statb.st_size + 1;
}
Xinit(xs, xp, n, hist_source->areap);
while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
xp += n;
@ -279,6 +291,7 @@ c_fc(const char **wp)
if (n < 0) {
bi_errorf("can't %s temporary file %s: %s",
"read", tf->name, strerror(shf_errno(shf)));
errout:
shf_close(shf);
return (1);
}
@ -532,7 +545,7 @@ sethistsize(int n)
cursize = n;
}
history = aresize(history, n * sizeof(char *), APERM);
history = aresize2(history, n, sizeof(char *), APERM);
histsize = n;
histptr = history + cursize;
@ -583,7 +596,7 @@ init_histvec(void)
{
if (history == (char **)NULL) {
histsize = HISTORYSIZE;
history = alloc(histsize * sizeof(char *), APERM);
history = alloc2(histsize, sizeof(char *), APERM);
histptr = history - 1;
}
}

View File

@ -20,7 +20,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.12 2010/08/28 20:22:19 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.13 2010/09/14 21:26:14 tg Exp $");
/* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
#if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
@ -67,6 +67,15 @@ findptr(ALLOC_ITEM **lpp, char *ptr, Area *ap)
return (ap);
}
void *
aresize2(void *ptr, size_t fac1, size_t fac2, Area *ap)
{
if (fac1 && fac2 && (SIZE_MAX / fac1 < fac2))
internal_errorf(T_intovfl, (unsigned long)fac1, '*',
(unsigned long)fac2);
return (aresize(ptr, fac1 * fac2, ap));
}
void *
aresize(void *ptr, size_t numb, Area *ap)
{
@ -80,7 +89,7 @@ aresize(void *ptr, size_t numb, Area *ap)
pp->next = lp->next;
}
if ((numb >= SIZE_MAX - ALLOC_SIZE) ||
if (notoktoadd(numb, ALLOC_SIZE) ||
(lp = remalloc(lp, numb + ALLOC_SIZE)) == NULL
#ifndef MKSH_SMALL
|| ALLOC_ISUNALIGNED(lp)

12
lex.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.120 2010/08/28 20:22:20 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.121 2010/09/14 21:26:14 tg Exp $");
/*
* states while lexing word
@ -1446,7 +1446,7 @@ getsc_line(Source *s)
int linelen;
linelen = Xlength(s->xs, xp);
XcheckN(s->xs, xp, fc_e_n + /* NUL */ 1);
XcheckN(s->xs, xp, Tn_fc_e_ + /* NUL */ 1);
/* reload after potential realloc */
cp = Xstring(s->xs, xp);
/* change initial '!' into space */
@ -1454,10 +1454,10 @@ getsc_line(Source *s)
/* NUL terminate the current string */
*xp = '\0';
/* move the actual string forward */
memmove(cp + fc_e_n, cp, linelen + /* NUL */ 1);
xp += fc_e_n;
memmove(cp + Tn_fc_e_, cp, linelen + /* NUL */ 1);
xp += Tn_fc_e_;
/* prepend it with "fc -e -" */
memcpy(cp, fc_e_, fc_e_n);
memcpy(cp, T_fc_e_, Tn_fc_e_);
}
#endif
s->start = s->str = cp;
@ -1749,7 +1749,7 @@ getsc_bn(void)
static Lex_state *
push_state_(State_info *si, Lex_state *old_end)
{
Lex_state *news = alloc(STATE_BSIZE * sizeof(Lex_state), ATEMP);
Lex_state *news = alloc2(STATE_BSIZE, sizeof(Lex_state), ATEMP);
news[0].ls_info.base = old_end;
si->base = &news[0];

21
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h>
#endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.171 2010/09/14 21:00:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.172 2010/09/14 21:26:14 tg Exp $");
extern char **environ;
@ -84,7 +84,7 @@ static const char *initcoms[] = {
"history=fc -l",
"nameref=typeset -n",
"nohup=nohup ",
r_fc_e_,
T_r_fc_e_,
"source=PATH=$PATH:. command .",
"login=exec login",
NULL,
@ -119,7 +119,7 @@ mksh_init(int argc, const char *argv[])
struct tbl *vp;
struct stat s_stdin;
#if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
size_t k;
ssize_t k;
char *cp;
#endif
@ -181,7 +181,7 @@ mksh_init(int argc, const char *argv[])
def_path = _PATH_DEFPATH;
#else
#ifdef _CS_PATH
if ((k = confstr(_CS_PATH, NULL, 0)) != (size_t)-1 && k > 0 &&
if ((k = confstr(_CS_PATH, NULL, 0)) > 0 &&
confstr(_CS_PATH, cp = alloc(k + 1, APERM), k + 1) == k + 1)
def_path = cp;
else
@ -1266,6 +1266,7 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
pathname = tempnam(dir, "mksh.");
len = ((pathname == NULL) ? 0 : strlen(pathname)) + 1;
#endif
/* reasonably sure that this will not overflow */
tp = alloc(sizeof(struct temp) + len, ap);
tp->name = (char *)&tp[1];
#if !HAVE_MKSTEMP
@ -1313,7 +1314,7 @@ texpand(struct table *tp, size_t nsize)
struct tbl *tblp, **pp;
struct tbl **ntblp, **otblp = tp->tbls;
ntblp = alloc(nsize * sizeof(struct tbl *), tp->areap);
ntblp = alloc2(nsize, sizeof(struct tbl *), tp->areap);
for (i = 0; i < nsize; i++)
ntblp[i] = NULL;
tp->size = nsize;
@ -1392,7 +1393,7 @@ struct tbl *
ktenter(struct table *tp, const char *n, uint32_t h)
{
struct tbl **pp, *p;
int len;
size_t len;
if (tp->size == 0)
texpand(tp, INIT_TBLS);
@ -1407,8 +1408,9 @@ ktenter(struct table *tp, const char *n, uint32_t h)
}
/* create new tbl entry */
len = strlen(n) + 1;
p = alloc(offsetof(struct tbl, name[0]) + len, tp->areap);
len = strlen(n);
checkoktoadd(len, offsetof(struct tbl, name[0]) + 1);
p = alloc(offsetof(struct tbl, name[0]) + ++len, tp->areap);
p->flag = 0;
p->type = 0;
p->areap = tp->areap;
@ -1456,7 +1458,8 @@ ktsort(struct table *tp)
size_t i;
struct tbl **p, **sp, **dp;
p = alloc((tp->size + 1) * sizeof(struct tbl *), ATEMP);
/* tp->size + 1 will not overflow */
p = alloc2(tp->size + 1, sizeof(struct tbl *), ATEMP);
sp = tp->tbls; /* source */
dp = p; /* dest */
i = (size_t)tp->size;

38
misc.c
View File

@ -29,7 +29,7 @@
#include <grp.h>
#endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.146 2010/09/14 21:15:10 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.147 2010/09/14 21:26:15 tg Exp $");
unsigned char chtypes[UCHAR_MAX + 1]; /* type bits for unsigned char */
@ -45,6 +45,25 @@ static const unsigned char *cclass(const unsigned char *, int);
static void chvt(const char *);
#endif
#ifdef SETUID_CAN_FAIL_WITH_EAGAIN
/* we don't need to check for other codes, EPERM won't happen */
#define DO_SETUID(func, argvec) do { \
bool messaged = false; \
\
while (/* CONSTCOND */ 1) \
if (!(func argvec) || errno != EAGAIN) \
break; \
else if (!messaged) { \
warningf(true, "%s failed with EAGAIN," \
" probably due to a too low process" \
" limit; retrying infinitely", #func); \
messaged = true; \
} \
} while (/* CONSTCOND */ 0)
#else
#define DO_SETUID(func, argvec) func argvec
#endif
/*
* Fast character classes
*/
@ -82,12 +101,15 @@ initctypes(void)
/* called from XcheckN() to grow buffer */
char *
Xcheck_grow_(XString *xsp, const char *xp, unsigned int more)
Xcheck_grow_(XString *xsp, const char *xp, size_t more)
{
const char *old_beg = xsp->beg;
xsp->len += more > xsp->len ? more : xsp->len;
xsp->beg = aresize(xsp->beg, xsp->len + 8, xsp->areap);
if (more < xsp->len)
more = xsp->len;
/* (xsp->len + X_EXTRA) never overflows */
checkoktoadd(more, xsp->len + X_EXTRA);
xsp->beg = aresize(xsp->beg, (xsp->len += more) + X_EXTRA, xsp->areap);
xsp->end = xsp->beg + xsp->len;
return (xsp->beg + (xp - old_beg));
}
@ -222,14 +244,16 @@ change_flag(enum sh_flag f, int what, unsigned int newval)
#if HAVE_SETRESUGID
gid_t kshegid = getgid();
setresgid(kshegid, kshegid, kshegid);
DO_SETUID(setresgid, (kshegid, kshegid, kshegid));
#if HAVE_SETGROUPS
/* setgroups doesn't EAGAIN on Linux */
setgroups(1, &kshegid);
#endif
setresuid(ksheuid, ksheuid, ksheuid);
DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid));
#else
/* seteuid, setegid, setgid don't EAGAIN on Linux */
seteuid(ksheuid = kshuid = getuid());
setuid(ksheuid);
DO_SETUID(setuid, (ksheuid));
setegid(kshegid = kshgid = getgid());
setgid(kshegid);
#endif

View File

@ -33,14 +33,10 @@
* SUCH DAMAGE.
*/
#if defined(HAVE_CONFIG_H) && (HAVE_CONFIG_H != 0)
/* usually when packaged with third-party software */
#ifdef CONFIG_H_FILENAME
#include CONFIG_H_FILENAME
#ifdef IN_MKSH
#include "sh.h"
#undef SETMODE_DEBUG
#else
#include "config.h"
#endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
@ -55,20 +51,36 @@
#include <stdio.h>
#endif
__SCCSID("@(#)setmode.c 8.2 (Berkeley) 3/25/94");
__RCSID("$MirOS: src/bin/mksh/setmode.c,v 1.14 2009/06/10 18:12:48 tg Rel $");
__RCSID("$miros: src/lib/libc/gen/setmode.c,v 1.12 2009/06/10 18:12:42 tg Exp $");
#endif
__SCCSID("@(#)setmode.c 8.2 (Berkeley) 3/25/94");
__RCSID("$MirOS: src/bin/mksh/setmode.c,v 1.15 2010/09/14 21:26:16 tg Exp $");
__RCSID("$miros: src/lib/libc/gen/setmode.c,v 1.14 2010/09/14 21:26:04 tg Exp $");
#ifdef IN_MKSH
/* for mksh */
#ifdef ksh_isdigit
#undef isdigit
#define isdigit ksh_isdigit
#endif
#else
#ifndef S_ISTXT
#define S_ISTXT 0001000
#endif
#ifndef SIZE_MAX
#ifdef SIZE_T_MAX
#define SIZE_MAX SIZE_T_MAX
#else
#define SIZE_MAX ((size_t)-1)
#endif
#endif
#endif
#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
@ -165,12 +177,15 @@ getmode(const void *bbox, mode_t omode)
}
}
#define notoktomul(a, b) ((a) && (b) && (SIZE_MAX / (a) < (b)))
#define ADDCMD(a, b, c, d) \
if (set >= endset) { \
BITCMD *newset; \
setlen += SET_LEN_INCR; \
newset = realloc(saveset, sizeof(BITCMD) * setlen); \
if (newset == NULL) { \
if (notoktomul(setlen, sizeof(BITCMD)) || \
(newset = realloc(saveset, setlen * \
sizeof(BITCMD))) == NULL) { \
free(saveset); \
return (NULL); \
} \
@ -210,7 +225,8 @@ setmode(const char *p)
setlen = SET_LEN + 2;
if ((set = calloc(sizeof(BITCMD), setlen)) == NULL)
if (notoktomul(setlen, sizeof(BITCMD)) ||
(set = malloc(setlen * sizeof(BITCMD))) == NULL)
return (NULL);
saveset = set;
endset = set + (setlen - 2);

36
sh.h
View File

@ -154,9 +154,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.413 2010/09/14 21:15:11 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.414 2010/09/14 21:26:16 tg Exp $");
#endif
#define MKSH_VERSION "R39 2010/09/05"
#define MKSH_VERSION "R39 2010/09/14"
#ifndef MKSH_INCLUDES_ONLY
@ -630,10 +630,11 @@ extern const struct shoption options[];
/* null value for variable; comparision pointer for unset */
EXTERN char null[] I__("");
/* helpers for string pooling */
#define T_synerr "syntax error"
EXTERN const char r_fc_e_[] I__("r=fc -e -");
#define fc_e_ (r_fc_e_ + 2) /* "fc -e -" */
#define fc_e_n 7 /* strlen(fc_e_) */
EXTERN const char T_intovfl[] I__("integer overflow %lu %c %lu prevented");
EXTERN const char T_synerr[] I__("syntax error");
EXTERN const char T_r_fc_e_[] I__("r=fc -e -");
#define T_fc_e_ (T_r_fc_e_ + 2) /* "fc -e -" */
#define Tn_fc_e_ 7 /* strlen(T_fc_e_) */
EXTERN const char T_local_typeset[] I__("local=typeset");
#define T__typeset (T_local_typeset + 5) /* "=typeset" */
#define T_typeset (T_local_typeset + 6) /* "typeset" */
@ -1223,7 +1224,7 @@ typedef char *XStringP;
#define XcheckN(xs, xp, n) do { \
int more = ((xp) + (n)) - (xs).end; \
if (more > 0) \
(xp) = Xcheck_grow_(&(xs), (xp), more); \
(xp) = Xcheck_grow_(&(xs), (xp), (size_t)more); \
} while (/* CONSTCOND */ 0)
/* check for overflow, expand string */
@ -1244,7 +1245,7 @@ typedef char *XStringP;
#define Xsavepos(xs, xp) ((xp) - (xs).beg)
#define Xrestpos(xs, xp, n) ((xs).beg + (n))
char *Xcheck_grow_(XString *, const char *, unsigned int);
char *Xcheck_grow_(XString *, const char *, size_t);
/*
* expandable vector of generic pointers
@ -1257,7 +1258,7 @@ typedef struct XPtrV {
#define XPinit(x, n) do { \
void **vp__; \
vp__ = alloc((n) * sizeof(void *), ATEMP); \
vp__ = alloc2((n), sizeof(void *), ATEMP); \
(x).cur = (x).beg = vp__; \
(x).end = vp__ + (n); \
} while (/* CONSTCOND */ 0)
@ -1265,8 +1266,8 @@ typedef struct XPtrV {
#define XPput(x, p) do { \
if ((x).cur >= (x).end) { \
size_t n = XPsize(x); \
(x).beg = aresize((x).beg, \
n * 2 * sizeof(void *), ATEMP); \
(x).beg = aresize2((x).beg, \
n, 2 * sizeof(void *), ATEMP); \
(x).cur = (x).beg + n; \
(x).end = (x).cur + n; \
} \
@ -1275,7 +1276,7 @@ typedef struct XPtrV {
#define XPptrv(x) ((x).beg)
#define XPsize(x) ((x).cur - (x).beg)
#define XPclose(x) aresize((x).beg, XPsize(x) * sizeof(void *), ATEMP)
#define XPclose(x) aresize2((x).beg, XPsize(x), sizeof(void *), ATEMP)
#define XPfree(x) afree((x).beg, ATEMP)
#define IDENT 64
@ -1392,12 +1393,21 @@ EXTERN int histsize; /* history size */
/* user and system time of last j_waitjed job */
EXTERN struct timeval j_usrtime, j_systime;
#define notoktoadd(val, cnst) ((val) > (SIZE_MAX - (cnst)))
#define checkoktoadd(val, cnst) do { \
if (notoktoadd((val), (cnst))) \
internal_errorf(T_intovfl, (unsigned long)(val), \
'+', (unsigned long)(cnst)); \
} while (/* CONSTCOND */ 0)
/* lalloc.c */
void ainit(Area *);
void afreeall(Area *);
/* these cannot fail and can take NULL (not for ap) */
#define alloc(n, ap) aresize(NULL, (n), (ap))
#define alloc(n, ap) aresize(NULL, (n), (ap))
#define alloc2(m, n, ap) aresize2(NULL, (m), (n), (ap))
void *aresize(void *, size_t, Area *);
void *aresize2(void *, size_t, size_t, Area *);
void afree(void *, Area *); /* can take NULL */
/* edit.c */
#ifndef MKSH_SMALL

13
shf.c
View File

@ -24,7 +24,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.39 2010/08/28 20:22:23 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.40 2010/09/14 21:26:17 tg Exp $");
/* flags to shf_emptybuf() */
#define EB_READSW 0x01 /* about to switch to reading */
@ -47,7 +47,8 @@ struct shf *
shf_open(const char *name, int oflags, int mode, int sflags)
{
struct shf *shf;
int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
int bsize = /* at most 512 */
sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
int fd;
/* Done before open so if alloca fails, fd won't be lost. */
@ -85,7 +86,8 @@ shf_open(const char *name, int oflags, int mode, int sflags)
struct shf *
shf_fdopen(int fd, int sflags, struct shf *shf)
{
int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
int bsize = /* at most 512 */
sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
/* use fcntl() to figure out correct read/write flags */
if (sflags & SHF_GETFL) {
@ -142,7 +144,8 @@ shf_fdopen(int fd, int sflags, struct shf *shf)
struct shf *
shf_reopen(int fd, int sflags, struct shf *shf)
{
int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
int bsize = /* at most 512 */
sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
/* use fcntl() to figure out correct read/write flags */
if (sflags & SHF_GETFL) {
@ -344,7 +347,7 @@ shf_emptybuf(struct shf *shf, int flags)
!(shf->flags & SHF_ALLOCB))
return (EOF);
/* allocate more space for buffer */
nbuf = aresize(shf->buf, 2 * shf->wbsize, shf->areap);
nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap);
shf->rp = nbuf + (shf->rp - shf->buf);
shf->wp = nbuf + (shf->wp - shf->buf);
shf->rbsize += shf->wbsize;

10
syn.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.51 2010/08/28 20:22:23 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.52 2010/09/14 21:26:18 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@ -231,7 +231,8 @@ get_command(int cf)
XPtrV args, vars;
struct nesting_state old_nesting;
iops = alloc((NUFILE + 1) * sizeof(struct ioword *), ATEMP);
/* NUFILE is small enough to leave this addition unchecked */
iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP);
XPinit(args, 16);
XPinit(vars, 16);
@ -476,7 +477,7 @@ get_command(int cf)
t->ioact = NULL;
} else {
iops[iopn++] = NULL;
iops = aresize(iops, iopn * sizeof(struct ioword *), ATEMP);
iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP);
t->ioact = iops;
}
@ -656,12 +657,13 @@ function_body(char *name,
if ((t->left = get_command(CONTIN)) == NULL) {
char *tv;
/*
* Probably something like foo() followed by eof or ;.
* Probably something like foo() followed by EOF or ';'.
* This is accepted by sh and ksh88.
* To make "typeset -f foo" work reliably (so its output can
* be used as input), we pretend there is a colon here.
*/
t->left = newtp(TCOM);
/* (2 * sizeof(char *)) is small enough */
t->left->args = alloc(2 * sizeof(char *), ATEMP);
t->left->args[0] = tv = alloc(3, ATEMP);
tv[0] = CHAR;

8
tree.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.31 2010/08/28 20:22:24 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.32 2010/09/14 21:26:19 tg Exp $");
#define INDENT 4
@ -454,7 +454,7 @@ tcopy(struct op *t, Area *ap)
else {
for (tw = (const char **)t->vars; *tw++ != NULL; )
;
rw = r->vars = alloc((tw - (const char **)t->vars + 1) *
rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
sizeof(*tw), ap);
for (tw = (const char **)t->vars; *tw != NULL; )
*rw++ = wdcopy(*tw++, ap);
@ -466,7 +466,7 @@ tcopy(struct op *t, Area *ap)
else {
for (tw = t->args; *tw++ != NULL; )
;
r->args = (const char **)(rw = alloc((tw - t->args + 1) *
r->args = (const char **)(rw = alloc2(tw - t->args + 1,
sizeof(*tw), ap));
for (tw = t->args; *tw != NULL; )
*rw++ = wdcopy(*tw++, ap);
@ -636,7 +636,7 @@ iocopy(struct ioword **iow, Area *ap)
for (ior = iow; *ior++ != NULL; )
;
ior = alloc((ior - iow + 1) * sizeof(struct ioword *), ap);
ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
for (i = 0; iow[i] != NULL; i++) {
struct ioword *p, *q;

14
var.c
View File

@ -26,7 +26,7 @@
#include <sys/sysctl.h>
#endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.112 2010/08/28 20:22:24 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.113 2010/09/14 21:26:19 tg Exp $");
/*
* Variables
@ -649,10 +649,13 @@ exportprep(struct tbl *vp, const char *val)
{
char *xp;
char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
int namelen = strlen(vp->name);
int vallen = strlen(val) + 1;
size_t namelen, vallen;
namelen = strlen(vp->name);
vallen = strlen(val) + 1;
vp->flag |= ALLOC;
/* since name+val are both in memory this can go unchecked */
xp = alloc(namelen + 1 + vallen, vp->areap);
memcpy(vp->val.s = xp, vp->name, namelen);
xp += namelen;
@ -1317,9 +1320,10 @@ arraysearch(struct tbl *vp, uint32_t val)
news = curr;
} else
news = NULL;
len = strlen(vp->name) + 1;
if (!news) {
news = alloc(offsetof(struct tbl, name[0]) + len, vp->areap);
len = strlen(vp->name);
checkoktoadd(len, 1 + offsetof(struct tbl, name[0]));
news = alloc(offsetof(struct tbl, name[0]) + ++len, vp->areap);
memcpy(news->name, vp->name, len);
}
news->flag = (vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL)) | AINDEX;