From 56a335378ac100d51c30b21eee499a2effa37fba Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Tue, 15 Jun 2021 16:05:57 +0200
Subject: hush: fix handling of \^C and "^C"

function                                             old     new   delta
parse_stream                                        2238    2252     +14
encode_string                                        243     256     +13
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 27/0)               Total: 27 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
(cherry picked from commit 1b7a9b68d0e9aa19147d7fda16eb9a6b54156985)

Signed-off-by: Pavel Zhukov <pavel.zhukov@huawei.com>

CVE: CVE-2021-42376
Upstream-Status: Backport [https://git.busybox.net/busybox/patch/?id=56a335378ac100d51c30b21eee499a2effa37fba]
Comment: No changes in any hunk
---
 shell/ash_test/ash-misc/control_char3.right   |  1 +
 shell/ash_test/ash-misc/control_char3.tests   |  2 ++
 shell/ash_test/ash-misc/control_char4.right   |  1 +
 shell/ash_test/ash-misc/control_char4.tests   |  2 ++
 shell/hush.c                                  | 11 +++++++++++
 shell/hush_test/hush-misc/control_char3.right |  1 +
 shell/hush_test/hush-misc/control_char3.tests |  2 ++
 shell/hush_test/hush-misc/control_char4.right |  1 +
 shell/hush_test/hush-misc/control_char4.tests |  2 ++
 9 files changed, 23 insertions(+)
 create mode 100644 shell/ash_test/ash-misc/control_char3.right
 create mode 100755 shell/ash_test/ash-misc/control_char3.tests
 create mode 100644 shell/ash_test/ash-misc/control_char4.right
 create mode 100755 shell/ash_test/ash-misc/control_char4.tests
 create mode 100644 shell/hush_test/hush-misc/control_char3.right
 create mode 100755 shell/hush_test/hush-misc/control_char3.tests
 create mode 100644 shell/hush_test/hush-misc/control_char4.right
 create mode 100755 shell/hush_test/hush-misc/control_char4.tests

diff --git a/shell/ash_test/ash-misc/control_char3.right b/shell/ash_test/ash-misc/control_char3.right
new file mode 100644
index 000000000..283e02cbb
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char3.right
@@ -0,0 +1 @@
+SHELL: line 1: : not found
diff --git a/shell/ash_test/ash-misc/control_char3.tests b/shell/ash_test/ash-misc/control_char3.tests
new file mode 100755
index 000000000..4359db3f3
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char3.tests
@@ -0,0 +1,2 @@
+# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages)
+$THIS_SH -c '\' SHELL
diff --git a/shell/ash_test/ash-misc/control_char4.right b/shell/ash_test/ash-misc/control_char4.right
new file mode 100644
index 000000000..2bf18e684
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char4.right
@@ -0,0 +1 @@
+SHELL: line 1: -: not found
diff --git a/shell/ash_test/ash-misc/control_char4.tests b/shell/ash_test/ash-misc/control_char4.tests
new file mode 100755
index 000000000..48010f154
--- /dev/null
+++ b/shell/ash_test/ash-misc/control_char4.tests
@@ -0,0 +1,2 @@
+# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages)
+$THIS_SH -c '"-"' SHELL
diff --git a/shell/hush.c b/shell/hush.c
index 9fead37da..249728b9d 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -5235,6 +5235,11 @@ static int encode_string(o_string *as_string,
 	}
 #endif
 	o_addQchr(dest, ch);
+	if (ch == SPECIAL_VAR_SYMBOL) {
+		/* Convert "^C" to corresponding special variable reference */
+		o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
+		o_addchr(dest, SPECIAL_VAR_SYMBOL);
+	}
 	goto again;
 #undef as_string
 }
@@ -5346,6 +5351,11 @@ static struct pipe *parse_stream(char **pstring,
 			if (ch == '\n')
 				continue; /* drop \<newline>, get next char */
 			nommu_addchr(&ctx.as_string, '\\');
+			if (ch == SPECIAL_VAR_SYMBOL) {
+				nommu_addchr(&ctx.as_string, ch);
+				/* Convert \^C to corresponding special variable reference */
+				goto case_SPECIAL_VAR_SYMBOL;
+			}
 			o_addchr(&ctx.word, '\\');
 			if (ch == EOF) {
 				/* Testcase: eval 'echo Ok\' */
@@ -5670,6 +5680,7 @@ static struct pipe *parse_stream(char **pstring,
 		/* Note: nommu_addchr(&ctx.as_string, ch) is already done */
 
 		switch (ch) {
+		case_SPECIAL_VAR_SYMBOL:
 		case SPECIAL_VAR_SYMBOL:
 			/* Convert raw ^C to corresponding special variable reference */
 			o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
diff --git a/shell/hush_test/hush-misc/control_char3.right b/shell/hush_test/hush-misc/control_char3.right
new file mode 100644
index 000000000..94b4f8699
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char3.right
@@ -0,0 +1 @@
+hush: can't execute '': No such file or directory
diff --git a/shell/hush_test/hush-misc/control_char3.tests b/shell/hush_test/hush-misc/control_char3.tests
new file mode 100755
index 000000000..4359db3f3
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char3.tests
@@ -0,0 +1,2 @@
+# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages)
+$THIS_SH -c '\' SHELL
diff --git a/shell/hush_test/hush-misc/control_char4.right b/shell/hush_test/hush-misc/control_char4.right
new file mode 100644
index 000000000..698e21427
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char4.right
@@ -0,0 +1 @@
+hush: can't execute '-': No such file or directory
diff --git a/shell/hush_test/hush-misc/control_char4.tests b/shell/hush_test/hush-misc/control_char4.tests
new file mode 100755
index 000000000..48010f154
--- /dev/null
+++ b/shell/hush_test/hush-misc/control_char4.tests
@@ -0,0 +1,2 @@
+# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages)
+$THIS_SH -c '"-"' SHELL
-- 
cgit v1.2.3

