• 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

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