ash: fix handling of NULs in $'abc\000def\x00asd'. Closes 9286
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 25 Sep 2016 18:54:25 +0000 (20:54 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 25 Sep 2016 18:54:25 +0000 (20:54 +0200)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-quoting/dollar_squote_bash2.right [new file with mode: 0644]
shell/ash_test/ash-quoting/dollar_squote_bash2.tests [new file with mode: 0755]

index 2674937085178b8067f068bcaa855d5e6cfb0f06..578b3dc22376905382e59fc9add3e0d03415acfe 100644 (file)
@@ -5651,6 +5651,10 @@ rmescapes(char *str, int flag)
                }
                if ((unsigned char)*p == CTLESC) {
                        p++;
+#if DEBUG
+                       if (*p == '\0')
+                               ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
+#endif
                        if (protect_against_glob) {
                                *q++ = '\\';
                        }
@@ -11302,20 +11306,24 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
                        USTPUTC(c, out);
                        break;
                case CCTL:
-                       if (eofmark == NULL || dblquote)
-                               USTPUTC(CTLESC, out);
 #if ENABLE_ASH_BASH_COMPAT
                        if (c == '\\' && bash_dollar_squote) {
                                c = decode_dollar_squote();
+                               if (c == '\0') {
+                                       /* skip $'\000', $'\x00' (like bash) */
+                                       break;
+                               }
                                if (c & 0x100) {
-                                       USTPUTC('\\', out);
+                                       /* Unknown escape. Encode as '\z' */
+                                       c = (unsigned char)c;
                                        if (eofmark == NULL || dblquote)
-                                               /* Or else this SEGVs: $'\<0x82>' */
                                                USTPUTC(CTLESC, out);
-                                       c = (unsigned char)c;
+                                       USTPUTC('\\', out);
                                }
                        }
 #endif
+                       if (eofmark == NULL || dblquote)
+                               USTPUTC(CTLESC, out);
                        USTPUTC(c, out);
                        break;
                case CBACK:     /* backslash */
diff --git a/shell/ash_test/ash-quoting/dollar_squote_bash2.right b/shell/ash_test/ash-quoting/dollar_squote_bash2.right
new file mode 100644 (file)
index 0000000..f7a1731
--- /dev/null
@@ -0,0 +1,6 @@
+strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+80:\\80
+81:\\81
+82:\\82
+Done:0
diff --git a/shell/ash_test/ash-quoting/dollar_squote_bash2.tests b/shell/ash_test/ash-quoting/dollar_squote_bash2.tests
new file mode 100755 (executable)
index 0000000..4497728
--- /dev/null
@@ -0,0 +1,10 @@
+# Embedded NULs
+echo $'str\x00'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+echo $'str\000'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
+
+# The chars after '\' are hex 0x80,81,82...
+echo 80:$'\\80'
+echo 81:$'\\81'
+echo 82:$'\\82'
+
+echo Done:$?