Limit history file size to 1 GiB for sanity (especially considering struct stat.sb_size is sometimes unsigned, sometimes signed, and sometimes larger than long, ugh…)

This commit is contained in:
tg 2011-02-09 15:08:01 +00:00
parent 5161342b9b
commit d158038191
1 changed files with 61 additions and 43 deletions

104
histrap.c
View File

@ -26,7 +26,7 @@
#include <sys/file.h> #include <sys/file.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.105 2011/02/09 13:08:25 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.106 2011/02/09 15:08:01 tg Exp $");
/*- /*-
* MirOS: This is the default mapping type, and need not be specified. * MirOS: This is the default mapping type, and need not be specified.
@ -60,11 +60,15 @@ static int hstarted; /* set after hist_init() called */
static Source *hist_source; static Source *hist_source;
#if HAVE_PERSISTENT_HISTORY #if HAVE_PERSISTENT_HISTORY
static char *hname; /* current name of history file */ /* current history file: name, fd, size */
static char *hname;
static int histfd; static int histfd;
static int hsize; static int hsize;
#endif #endif
static const char T_not_in_history[] = "not in history";
#define T_history (T_not_in_history + 7)
int int
c_fc(const char **wp) c_fc(const char **wp)
{ {
@ -86,6 +90,7 @@ c_fc(const char **wp)
while ((optc = ksh_getopt(wp, &builtin_opt, while ((optc = ksh_getopt(wp, &builtin_opt,
"e:glnrs0,1,2,3,4,5,6,7,8,9,")) != -1) "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != -1)
switch (optc) { switch (optc) {
case 'e': case 'e':
p = builtin_opt.optarg; p = builtin_opt.optarg;
if (ksh_isdash(p)) if (ksh_isdash(p))
@ -99,21 +104,29 @@ c_fc(const char **wp)
memcpy(editor + len, " $_", 4); memcpy(editor + len, " $_", 4);
} }
break; break;
case 'g': /* non-AT&T ksh */
/* non-AT&T ksh */
case 'g':
gflag = true; gflag = true;
break; break;
case 'l': case 'l':
lflag = true; lflag = true;
break; break;
case 'n': case 'n':
nflag = true; nflag = true;
break; break;
case 'r': case 'r':
rflag = true; rflag = true;
break; break;
case 's': /* POSIX version of -e - */
/* POSIX version of -e - */
case 's':
sflag = true; sflag = true;
break; break;
/* kludge city - accept -num as -- -num (kind of) */ /* kludge city - accept -num as -- -num (kind of) */
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
@ -128,6 +141,7 @@ c_fc(const char **wp)
return (1); return (1);
} }
break; break;
case '?': case '?':
return (1); return (1);
} }
@ -185,9 +199,10 @@ c_fc(const char **wp)
/* can't fail if hfirst didn't fail */ /* can't fail if hfirst didn't fail */
hlast = hist_get_newest(false); hlast = hist_get_newest(false);
} else { } else {
/* POSIX says not an error if first/last out of bounds /*
* when range is specified; AT&T ksh and pdksh allow out of * POSIX says not an error if first/last out of bounds
* bounds for -l as well. * when range is specified; AT&T ksh and pdksh allow out
* of bounds for -l as well.
*/ */
hfirst = hist_get(first, (lflag || last) ? true : false, lflag); hfirst = hist_get(first, (lflag || last) ? true : false, lflag);
if (!hfirst) if (!hfirst)
@ -201,7 +216,8 @@ c_fc(const char **wp)
char **temp; char **temp;
temp = hfirst; hfirst = hlast; hlast = temp; temp = hfirst; hfirst = hlast; hlast = temp;
rflag = !rflag; /* POSIX */ /* POSIX */
rflag = !rflag;
} }
/* List history */ /* List history */
@ -273,22 +289,12 @@ c_fc(const char **wp)
if (stat(tf->name, &statb) < 0) if (stat(tf->name, &statb) < 0)
n = 128; n = 128;
else { else if (statb.st_size > (1024 * 1048576)) {
unsigned long st_sizeUL; bi_errorf("%s %s too large: %lu", T_history,
"file", (unsigned long)statb.st_size);
/* we pretty much assume ulong >= size_t */ goto errout;
st_sizeUL = (unsigned long)statb.st_size; } else
if (
/* too big, truncated by the cast */
statb.st_size != (long)st_sizeUL ||
/* a few additional bytes do not fit */
notoktoadd(st_sizeUL, 1 + X_EXTRA)) {
bi_errorf(T_intovfl, st_sizeUL, '+',
1UL + X_EXTRA);
goto errout;
}
n = statb.st_size + 1; n = statb.st_size + 1;
}
Xinit(xs, xp, n, hist_source->areap); Xinit(xs, xp, n, hist_source->areap);
while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) { while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
xp += n; xp += n;
@ -321,8 +327,10 @@ hist_execute(char *cmd)
for (p = cmd; p; p = q) { for (p = cmd; p; p = q) {
if ((q = strchr(p, '\n'))) { if ((q = strchr(p, '\n'))) {
*q++ = '\0'; /* kill the newline */ /* kill the newline */
if (!*q) /* ignore trailing newline */ *q++ = '\0';
if (!*q)
/* ignore trailing newline */
q = NULL; q = NULL;
} }
histsave(&hist_source->line, p, true, true); histsave(&hist_source->line, p, true, true);
@ -334,7 +342,7 @@ hist_execute(char *cmd)
q[-1] = '\n'; q[-1] = '\n';
} }
/* /*-
* Commands are executed here instead of pushing them onto the * Commands are executed here instead of pushing them onto the
* input 'cause POSIX says the redirection and variable assignments * input 'cause POSIX says the redirection and variable assignments
* in * in
@ -370,9 +378,11 @@ hist_replace(char **hp, const char *pat, const char *rep, bool globr)
any_subst = true; any_subst = true;
len = s1 - s; len = s1 - s;
XcheckN(xs, xp, len + rep_len); XcheckN(xs, xp, len + rep_len);
memcpy(xp, s, len); /* first part */ /*; first part */
memcpy(xp, s, len);
xp += len; xp += len;
memcpy(xp, rep, rep_len); /* replacement */ /* replacement */
memcpy(xp, rep, rep_len);
xp += rep_len; xp += rep_len;
} }
if (!any_subst) { if (!any_subst) {
@ -404,14 +414,14 @@ hist_get(const char *str, bool approx, bool allow_cur)
if (approx) if (approx)
hp = hist_get_oldest(); hp = hist_get_oldest();
else { else {
bi_errorf("%s: %s", str, "not in history"); bi_errorf("%s: %s", str, T_not_in_history);
hp = NULL; hp = NULL;
} }
} else if ((ptrdiff_t)hp > (ptrdiff_t)histptr) { } else if ((ptrdiff_t)hp > (ptrdiff_t)histptr) {
if (approx) if (approx)
hp = hist_get_newest(allow_cur); hp = hist_get_newest(allow_cur);
else { else {
bi_errorf("%s: %s", str, "not in history"); bi_errorf("%s: %s", str, T_not_in_history);
hp = NULL; hp = NULL;
} }
} else if (!allow_cur && hp == histptr) { } else if (!allow_cur && hp == histptr) {
@ -423,7 +433,7 @@ hist_get(const char *str, bool approx, bool allow_cur)
/* the -1 is to avoid the current fc command */ /* the -1 is to avoid the current fc command */
if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0) if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0)
bi_errorf("%s: %s", str, "not in history"); bi_errorf("%s: %s", str, T_not_in_history);
else else
hp = &history[n]; hp = &history[n];
} }
@ -452,9 +462,9 @@ hist_get_oldest(void)
return (history); return (history);
} }
/******************************/ /*
/* Back up over last histsave */ * Back up over last histsave
/******************************/ */
static void static void
histbackup(void) histbackup(void)
{ {
@ -669,7 +679,8 @@ histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups)
hp = histptr; hp = histptr;
if (++hp >= history + histsize) { /* remove oldest command */ if (++hp >= history + histsize) {
/* remove oldest command */
afree(*history, APERM); afree(*history, APERM);
for (hp = history; hp < history + histsize - 1; hp++) for (hp = history; hp < history + histsize - 1; hp++)
hp[0] = hp[1]; hp[0] = hp[1];
@ -689,7 +700,7 @@ histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups)
* if your system ain't got it - then you'll have to undef HISTORYFILE * if your system ain't got it - then you'll have to undef HISTORYFILE
*/ */
/* /*-
* Open a history file * Open a history file
* Format is: * Format is:
* Bytes 1, 2: * Bytes 1, 2:
@ -1116,7 +1127,8 @@ inittraps(void)
"Signal", i); "Signal", i);
} }
} }
sigtraps[SIGEXIT_].name = "EXIT"; /* our name for signal 0 */ /* our name for signal 0 */
sigtraps[SIGEXIT_].name = "EXIT";
(void)sigemptyset(&Sigact_ign.sa_mask); (void)sigemptyset(&Sigact_ign.sa_mask);
Sigact_ign.sa_flags = 0; /* interruptible */ Sigact_ign.sa_flags = 0; /* interruptible */
@ -1124,7 +1136,8 @@ inittraps(void)
sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR; sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR; sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGTERM].flags |= TF_DFL_INTR; /* not fatal for interactive */ /* SIGTERM is not fatal for interactive */
sigtraps[SIGTERM].flags |= TF_DFL_INTR;
sigtraps[SIGHUP].flags |= TF_FATAL; sigtraps[SIGHUP].flags |= TF_FATAL;
sigtraps[SIGCHLD].flags |= TF_SHELL_USES; sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
@ -1318,7 +1331,8 @@ runtrap(Trap *p, bool is_last)
if (trapstr[0] == '\0') if (trapstr[0] == '\0')
/* SIG_IGN */ /* SIG_IGN */
goto donetrap; goto donetrap;
if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */ if (i == SIGEXIT_ || i == SIGERR_) {
/* avoid recursion on these */
old_changed = p->flags & TF_CHANGED; old_changed = p->flags & TF_CHANGED;
p->flags &= ~TF_CHANGED; p->flags &= ~TF_CHANGED;
p->trap = NULL; p->trap = NULL;
@ -1384,7 +1398,8 @@ settrap(Trap *p, const char *s)
if (p->trap) if (p->trap)
afree(p->trap, APERM); afree(p->trap, APERM);
strdupx(p->trap, s, APERM); /* handles s == 0 */ /* handles s == NULL */
strdupx(p->trap, s, APERM);
p->flags |= TF_CHANGED; p->flags |= TF_CHANGED;
f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN; f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN;
@ -1428,7 +1443,8 @@ block_pipe(void)
restore_dfl = 1; restore_dfl = 1;
} else if (p->cursig == SIG_DFL) { } else if (p->cursig == SIG_DFL) {
setsig(p, SIG_IGN, SS_RESTORE_CURR); setsig(p, SIG_IGN, SS_RESTORE_CURR);
restore_dfl = 1; /* restore to SIG_DFL */ /* restore to SIG_DFL */
restore_dfl = 1;
} }
return (restore_dfl); return (restore_dfl);
} }
@ -1491,7 +1507,8 @@ setsig(Trap *p, sig_t f, int flags)
if (p->cursig != f) { if (p->cursig != f) {
p->cursig = f; p->cursig = f;
(void)sigemptyset(&sigact.sa_mask); (void)sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0 /* interruptible */; /* interruptible */
sigact.sa_flags = 0;
sigact.sa_handler = f; sigact.sa_handler = f;
sigaction(p->signal, &sigact, NULL); sigaction(p->signal, &sigact, NULL);
} }
@ -1511,7 +1528,8 @@ setexecsig(Trap *p, int restore)
/* restore original value for exec'd kids */ /* restore original value for exec'd kids */
p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
switch (restore & SS_RESTORE_MASK) { switch (restore & SS_RESTORE_MASK) {
case SS_RESTORE_CURR: /* leave things as they currently are */ case SS_RESTORE_CURR:
/* leave things as they currently are */
break; break;
case SS_RESTORE_ORIG: case SS_RESTORE_ORIG:
p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL; p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;