From 667d792d6afa963c014055f8ecb96418fc08b5fb Mon Sep 17 00:00:00 2001 From: tg Date: Tue, 14 Sep 2010 21:26:19 +0000 Subject: [PATCH] =?UTF-8?q?=E2=80=A2=20Address=20concerns=20of=20Chris=20P?= =?UTF-8?q?almer=20from=20the=20Android=20security=20team=20=20=20?= =?UTF-8?q?=E2=80=93=20possible=20integer=20overflows=20in=20memory=20allo?= =?UTF-8?q?cation,=20mostly=20=20=20=20=20=E2=80=A3=20multiplication:=20al?= =?UTF-8?q?l=20are=20checked=20now=20=20=20=20=20=E2=80=A3=20addition:=20r?= =?UTF-8?q?eviewed=20them,=20most=20were=20=E2=80=9Cproven=E2=80=9D=20or?= =?UTF-8?q?=20guessed=20to=20be=20=20=20=20=20=20=20=E2=80=9Calmost?= =?UTF-8?q?=E2=80=9D=20impossible=20to=20run=20over=20(e.g.=20when=20we=20?= =?UTF-8?q?have=20a=20string=20=20=20=20=20=20=20whose=20length=20is=20tak?= =?UTF-8?q?en=20it=20is=20assumed=20that=20the=20length=20will=20be=20=20?= =?UTF-8?q?=20=20=20=20=20more=20than=20only=20a=20few=20bytes=20below=20S?= =?UTF-8?q?IZE=5FMAX,=20since=20code=20and=20=20=20=20=20=20=20stack=20hav?= =?UTF-8?q?e=20to=20fit);=20some=20are=20checked=20now=20(e.g.=20when=20on?= =?UTF-8?q?e=20of=20=20=20=20=20=20=20the=20summands=20is=20an=20off=5Ft);?= =?UTF-8?q?=20most=20of=20the=20unchecked=20ones=20are=20=20=20=20=20=20?= =?UTF-8?q?=20annotated=20now=20=20=20=20=20=E2=87=92=20cost=20(MirBSD/i38?= =?UTF-8?q?6=20static):=20+76=20.text=20=20=20=20=20=E2=87=92=20cost=20(De?= =?UTF-8?q?bian=20sid/i386):=20+779=20.text=20=20-4=20.data=20=20=20?= =?UTF-8?q?=E2=80=93=20on=20Linux=20targets,=20setuid()=20setresuid()=20se?= =?UTF-8?q?tresgid()=20can=20fail=20=20=20=20=20with=20EAGAIN;=20check=20f?= =?UTF-8?q?or=20that=20and,=20if=20so,=20warn=20once=20and=20retry=20=20?= =?UTF-8?q?=20=20=20infinitely=20(other=20targets=20to=20be=20added=20late?= =?UTF-8?q?r=20once=20we=20know=20that=20=20=20=20=20they=20are=20?= =?UTF-8?q?=E2=80=9Cinsane=E2=80=9D)=20=20=20=20=20=E2=87=92=20cost=20(Deb?= =?UTF-8?q?ian=20sid/i386):=20+192=20.text=20(includes=20.rodata)=20?= =?UTF-8?q?=E2=80=A2=20setmode.c:=20Do=20overflow=20checking=20for=20reall?= =?UTF-8?q?oc()=20too;=20switch=20back=20=20=20from=20calloc()=20to=20a=20?= =?UTF-8?q?checked=20malloc()=20for=20simplification=20while=20there=20?= =?UTF-8?q?=E2=80=A2=20define=20-DIN=5FMKSH=20and=20let=20setmode.c=20look?= =?UTF-8?q?=20a=20tad=20nicer=20while=20here?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Build.sh | 6 +++--- Makefile | 4 ++-- check.t | 4 ++-- edit.c | 24 +++++++++++++++--------- eval.c | 6 +++++- exec.c | 4 ++-- funcs.c | 22 ++++++++++++++++++---- histrap.c | 21 +++++++++++++++++---- lalloc.c | 13 +++++++++++-- lex.c | 12 ++++++------ main.c | 21 ++++++++++++--------- misc.c | 38 +++++++++++++++++++++++++++++++------- setmode.c | 44 ++++++++++++++++++++++++++++++-------------- sh.h | 36 +++++++++++++++++++++++------------- shf.c | 13 ++++++++----- syn.c | 10 ++++++---- tree.c | 8 ++++---- var.c | 14 +++++++++----- 18 files changed, 204 insertions(+), 96 deletions(-) diff --git a/Build.sh b/Build.sh index 34ce5e2..134e5f5 100644 --- a/Build.sh +++ b/Build.sh @@ -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 @@ -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= diff --git a/Makefile b/Makefile index 5e5eb0d..25efcc6 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -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 diff --git a/check.t b/check.t index e9e122f..ae64589 100644 --- a/check.t +++ b/check.t @@ -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: diff --git a/edit.c b/edit.c index 766e57f..cd31d1f 100644 --- a/edit.c +++ b/edit.c @@ -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]; diff --git a/eval.c b/eval.c index 7063720..7c68ffa 100644 --- a/eval.c +++ b/eval.c @@ -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; diff --git a/exec.c b/exec.c index 801b120..012a900 100644 --- a/exec.c +++ b/exec.c @@ -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)); } diff --git a/funcs.c b/funcs.c index 6784a68..effd9ff 100644 --- a/funcs.c +++ b/funcs.c @@ -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; ) ; } diff --git a/histrap.c b/histrap.c index 62198ae..8134904 100644 --- a/histrap.c +++ b/histrap.c @@ -26,7 +26,7 @@ #include #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; } } diff --git a/lalloc.c b/lalloc.c index a4d160e..b6341e2 100644 --- a/lalloc.c +++ b/lalloc.c @@ -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) diff --git a/lex.c b/lex.c index 359bc41..126beb5 100644 --- a/lex.c +++ b/lex.c @@ -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]; diff --git a/main.c b/main.c index ee7f75e..0ed143e 100644 --- a/main.c +++ b/main.c @@ -33,7 +33,7 @@ #include #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; diff --git a/misc.c b/misc.c index eba4e64..4d057e0 100644 --- a/misc.c +++ b/misc.c @@ -29,7 +29,7 @@ #include #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 diff --git a/setmode.c b/setmode.c index a78f1fa..74cc1b0 100644 --- a/setmode.c +++ b/setmode.c @@ -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 #include @@ -55,20 +51,36 @@ #include #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); diff --git a/sh.h b/sh.h index ef517f9..5a11b47 100644 --- a/sh.h +++ b/sh.h @@ -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 diff --git a/shf.c b/shf.c index 8a5e45e..2c9e782 100644 --- a/shf.c +++ b/shf.c @@ -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; diff --git a/syn.c b/syn.c index 4daa04e..2ed737b 100644 --- a/syn.c +++ b/syn.c @@ -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; diff --git a/tree.c b/tree.c index 88b03e8..56698b4 100644 --- a/tree.c +++ b/tree.c @@ -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; diff --git a/var.c b/var.c index 383d57f..9c201c6 100644 --- a/var.c +++ b/var.c @@ -26,7 +26,7 @@ #include #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;