aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-10-27 14:46:50 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-10-27 14:46:50 +0200
commit5ac04f2f02207f1c9109f8d40b2b427999c44e75 (patch)
tree95b4ae7dca9fa078e9a50c558f60774747c6ded9
parent455e422814105b0904c79639fd318f3cec25efe6 (diff)
downloadbusybox-w32-5ac04f2f02207f1c9109f8d40b2b427999c44e75.tar.gz
busybox-w32-5ac04f2f02207f1c9109f8d40b2b427999c44e75.tar.bz2
busybox-w32-5ac04f2f02207f1c9109f8d40b2b427999c44e75.zip
ash: [EXPAND] Fix ifsfirst/ifslastp leak
Upstream commit: Date: Wed, 8 Sep 2010 20:07:26 +0800 [EXPAND] Fix ifsfirst/ifslastp leak As it stands expandarg may return with a non-NULL ifslastp which then confuses any subsequent ifsbreakup user that doesn't clear it directly. What's worse, if we get interrupted before we hit ifsfree in expandarg we will leak memory. This patch fixes this by always calling ifsfree in expandarg thus ensuring that ifslastp is always NULL on the normal path. It also adds an ifsfree call to the RESET path to ensure that memory isn't leaked. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Fallout 1: Date: Mon, 18 Oct 2010 10:55:42 +0800 [EXPAND] Fix ifsfirst/ifslastp leak in casematch The commit f42e443bb511ed3224f09b4fcf0772438ebdbbfa [EXPAND] Fix ifsfirst/ifslastp leak revealed yet another ifsfirst/ifslastp leak in casematch. Previously it was hidden because ifsfirst/ifslastp was cleared unconditionally on entry (which caused the leakage of those entries). Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Fallout 2: Date: Sun, 28 Nov 2010 21:09:51 +0800 [EXPAND] Free IFS state in evalbackcmd On Sun, Nov 07, 2010 at 04:04:20PM -0600, Jonathan Nieder wrote: > Herbert Xu wrote: > > commit f42e443bb511ed3224f09b4fcf0772438ebdbbfa > > Author: Herbert Xu <herbert@gondor.apana.org.au> > > Date: Wed Sep 8 20:07:26 2010 +0800 > > > > [EXPAND] Fix ifsfirst/ifslastp leak > > Another puzzle bisecting to f42e443bb. This one comes from the > grub-mkconfig script: > > $ sh -c 'datadir=/usr/share; pkgdatadir=${datadir}/`cat`' 2>&1 | cat -A > cat: M-^\^M^F^HM-4^M^F^HM-(^M^F^H: No such file or directory$ > cat: M-(^M^F^H: No such file or directory$ > > Still reproducible with 016b529. I'll try to find time to look into > it, but thought you might like to know nevertheless. This is the symptom of another leak. In this case evalbackcmd occurs in the middle of an expansion (as it should) but the forked child never clears the previous IFS state. This patch adds the missing ifsfree call. This wasn't as much of a problem as the previously discovered leaks since all it means is that the child gets to carry around the parent's expansion state and the child is usually short-lived. Reported-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Fallout 3: Date: Tue, 15 Mar 2011 16:01:34 +0800 [EXPAND] Free IFS state after here document expansion Here's another bug bisecting to f42e443bb ([EXPAND] Fix ifsfirst/ifslastp leak, 2010-09-08). It was found with the following test case, based on the configure script for Tracker: dash -x -c ' <<-_ACEOF $@ _ACEOF exec ' - abcdefgh + + exec ?a exec: 1: : Permission denied The missing ifsfree call is in expandarg when it returns to openhere during here document expansion. Reported-by: Aurelien Jarno <aurel32@debian.org> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> function old new delta ifsfree - 66 +66 ash_main 1490 1495 +5 argstr 1154 1159 +5 evalcase 275 270 -5 expandarg 972 888 -84 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 76/-89) Total: -13 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 7acb33e7e..d38378411 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5663,19 +5663,22 @@ ifsbreakup(char *string, struct arglist *arglist)
5663static void 5663static void
5664ifsfree(void) 5664ifsfree(void)
5665{ 5665{
5666 struct ifsregion *p; 5666 struct ifsregion *p = ifsfirst.next;
5667
5668 if (!p)
5669 goto out;
5667 5670
5668 INT_OFF; 5671 INT_OFF;
5669 p = ifsfirst.next;
5670 do { 5672 do {
5671 struct ifsregion *ifsp; 5673 struct ifsregion *ifsp;
5672 ifsp = p->next; 5674 ifsp = p->next;
5673 free(p); 5675 free(p);
5674 p = ifsp; 5676 p = ifsp;
5675 } while (p); 5677 } while (p);
5676 ifslastp = NULL;
5677 ifsfirst.next = NULL; 5678 ifsfirst.next = NULL;
5678 INT_ON; 5679 INT_ON;
5680 out:
5681 ifslastp = NULL;
5679} 5682}
5680 5683
5681static size_t 5684static size_t
@@ -5989,6 +5992,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5989 * For now, preserve bash-like behavior, it seems to be somewhat more useful: 5992 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
5990 */ 5993 */
5991 eflag = 0; 5994 eflag = 0;
5995 ifsfree();
5992 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 5996 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5993 /* NOTREACHED */ 5997 /* NOTREACHED */
5994 } 5998 }
@@ -7296,15 +7300,14 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7296 7300
7297 argbackq = arg->narg.backquote; 7301 argbackq = arg->narg.backquote;
7298 STARTSTACKSTR(expdest); 7302 STARTSTACKSTR(expdest);
7299 ifsfirst.next = NULL;
7300 ifslastp = NULL;
7301 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); 7303 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7302 argstr(arg->narg.text, flag, 7304 argstr(arg->narg.text, flag,
7303 /* var_str_list: */ arglist ? arglist->list : NULL); 7305 /* var_str_list: */ arglist ? arglist->list : NULL);
7304 p = _STPUTC('\0', expdest); 7306 p = _STPUTC('\0', expdest);
7305 expdest = p - 1; 7307 expdest = p - 1;
7306 if (arglist == NULL) { 7308 if (arglist == NULL) {
7307 return; /* here document expanded */ 7309 /* here document expanded */
7310 goto out;
7308 } 7311 }
7309 p = grabstackstr(p); 7312 p = grabstackstr(p);
7310 TRACE(("expandarg: p:'%s'\n", p)); 7313 TRACE(("expandarg: p:'%s'\n", p));
@@ -7327,13 +7330,14 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
7327 *exparg.lastp = sp; 7330 *exparg.lastp = sp;
7328 exparg.lastp = &sp->next; 7331 exparg.lastp = &sp->next;
7329 } 7332 }
7330 if (ifsfirst.next)
7331 ifsfree();
7332 *exparg.lastp = NULL; 7333 *exparg.lastp = NULL;
7333 if (exparg.list) { 7334 if (exparg.list) {
7334 *arglist->lastp = exparg.list; 7335 *arglist->lastp = exparg.list;
7335 arglist->lastp = exparg.lastp; 7336 arglist->lastp = exparg.lastp;
7336 } 7337 }
7338
7339 out:
7340 ifsfree();
7337} 7341}
7338 7342
7339/* 7343/*
@@ -7367,10 +7371,10 @@ casematch(union node *pattern, char *val)
7367 setstackmark(&smark); 7371 setstackmark(&smark);
7368 argbackq = pattern->narg.backquote; 7372 argbackq = pattern->narg.backquote;
7369 STARTSTACKSTR(expdest); 7373 STARTSTACKSTR(expdest);
7370 ifslastp = NULL;
7371 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, 7374 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7372 /* var_str_list: */ NULL); 7375 /* var_str_list: */ NULL);
7373 STACKSTRNUL(expdest); 7376 STACKSTRNUL(expdest);
7377 ifsfree();
7374 result = patmatch(stackblock(), val); 7378 result = patmatch(stackblock(), val);
7375 popstackmark(&smark); 7379 popstackmark(&smark);
7376 return result; 7380 return result;
@@ -13293,6 +13297,7 @@ read_profile(const char *name)
13293/* 13297/*
13294 * This routine is called when an error or an interrupt occurs in an 13298 * This routine is called when an error or an interrupt occurs in an
13295 * interactive shell and control is returned to the main command loop. 13299 * interactive shell and control is returned to the main command loop.
13300 * (In dash, this function is auto-generated by build machinery).
13296 */ 13301 */
13297static void 13302static void
13298reset(void) 13303reset(void)
@@ -13300,13 +13305,19 @@ reset(void)
13300 /* from eval.c: */ 13305 /* from eval.c: */
13301 evalskip = 0; 13306 evalskip = 0;
13302 loopnest = 0; 13307 loopnest = 0;
13308
13309 /* from expand.c: */
13310 ifsfree();
13311
13303 /* from input.c: */ 13312 /* from input.c: */
13304 g_parsefile->left_in_buffer = 0; 13313 g_parsefile->left_in_buffer = 0;
13305 g_parsefile->left_in_line = 0; /* clear input buffer */ 13314 g_parsefile->left_in_line = 0; /* clear input buffer */
13306 popallfiles(); 13315 popallfiles();
13316
13307 /* from parser.c: */ 13317 /* from parser.c: */
13308 tokpushback = 0; 13318 tokpushback = 0;
13309 checkkwd = 0; 13319 checkkwd = 0;
13320
13310 /* from redir.c: */ 13321 /* from redir.c: */
13311 while (redirlist) 13322 while (redirlist)
13312 popredir(/*drop:*/ 0, /*restore:*/ 0); 13323 popredir(/*drop:*/ 0, /*restore:*/ 0);