path: root/shell
diff options
authorGravatar Christoph Schulz <develop@kristov.de>2018-11-20 17:45:52 +0100
committerGravatar Denys Vlasenko <vda.linux@googlemail.com>2018-11-20 17:45:52 +0100
commit03ad7ae08189ed88dd7e0fcb6c6001fbf3b12efb (patch)
tree8cadf600f6d43bfc4f98ca5a006fb982667a4e60 /shell
parent32511da87ddaea0824801eafebd27e11409bf444 (diff)
ash: reset tokpushback before prompting while parsing heredoc
The parser reads from an already freed memory location, thereby causing unpredictable results, in the following situation: - ENABLE_ASH_EXPAND_PRMT is enabled - heredoc is being parsed - command substitution is used within heredoc Examples where this bug crops up are (PS2 is set to "> "): $ cat <<EOF > `echo abc` > EOF -sh: O: not found $ cat <<EOF > $(echo abc) > EOF -sh: {garbage}: not found The presumable reason is that setprompt_if() causes a nested expansion when ENABLE_ASH_EXPAND_PRMT is enabled, therefore leaving "wordtext" in an unusable state. However, when parseheredoc() is called, "tokpushback" is non-zero, which causes the next call to xxreadtoken() to return TWORD, causing the caller to use the invalid "wordtoken" instead of reading the next valid token. The call chain is: list() -> peektoken() [sets tokpushback to 1] -> parseheredoc() -> setprompt_if() -> pushstackmark() -> expandstr() -> readtoken1() [sets lasttoken to TWORD, wordtoken points to expanded prompt] -> popstackmark() [invalidates wordtoken, leaves lasttoken as is] -> readtoken1() -> ...parsebackq -> list() -> andor() -> pipeline() -> readtoken() -> xxreadtoken() [tokpushback non-zero, reuse lasttoken and wordtext] Note that in almost all other contexts, each call to setprompt_if() is preceded by setting "tokpushback" to zero. One exception is "oldstyle" backquote parsing in readtoken1(), but there "tokpushback" is reset afterwards. The other exception is nlprompt(), but this function is only used within readtoken1() (but in contexts where no nested calls to xxreadtoken() occur) and xxreadtoken() (where "tokpushback" is guaranteed to be zero). function old new delta parseheredoc 124 131 +7 Signed-off-by: Christoph Schulz <develop@kristov.de> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
1 files changed, 1 insertions, 0 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 44b3569dc..04e4006c8 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -12961,6 +12961,7 @@ parseheredoc(void)
heredoclist = NULL;
while (here) {
+ tokpushback = 0;
setprompt_if(needprompt, 2);
readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
here->eofmark, here->striptabs);