[v2 PATCH] builtin: Fix octal escapes in dollar-single-quotes
Herbert Xu <[email protected]> Sun, 31 May 2026 13:36:09 +0800
| Newsgroups | org.kernel.vger.dash |
|---|---|
| Message-ID | <[email protected]> |
Kerin Millar <[email protected]> wrote: > > The test suite of the gentoo-functions project recently uncovered a bug whereby octal sequences within dollar-single-quotes are evaluated as internal control characters, resulting in faulty decoding at best, and segmentation faults at worse. The attached patch rectifies this bug. Thanks for the patch. While looking at this I found out that the logic for \x is broken as it always produces a multi-byte character even for the value of \x81. So here is a rolled-up patch which fixes both problems. ---8<--- From: Kerin Millar <[email protected]> The test suite of gentoo-functions recently uncovered a bug concerning the handling of octal escape sequences within dollar-single-quotes. Here is a reproducer: $ dash -c "x=\$'\\201'; printf '%s' \"\$x\"" | od -An -tx1 88 That is, despite the input being 0x81, the output is 0x88. Indeed, any input between 0x81..0x88 is adversely affected and some - such as 0x82 - induce a segfault. I noticed the following macros in src/parser.h: #define CTL_FIRST -127 /* first 'special' character */ #define CTLESC -127 /* escape next character */ #define CTL_LAST -120 /* last 'special' character */ Reinterpreted as unsigned char, the CTL_FIRST..CTL_LAST range maps exactly to 0x81..0x88: $ perl -e 'printf "%x\0", $_ & 0xFF for -127..-120' | xargs -0 81 82 83 84 85 86 87 88 From this, I was able to deduce that all of these bytes must be preceded by CTLESC in order to be taken literally. Make it so. Link: https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=947090fb7704 Signed-off-by: Kerin Millar <[email protected]> The escape should also be applied to \x sequences. In fact \x81 was totally broken as it produced a multi-byte character. Fix this by merging these two code paths. Signed-off-by: Herbert Xu <[email protected]> diff --git a/src/bltin/printf.c b/src/bltin/printf.c index 106aecd..671e781 100644 --- a/src/bltin/printf.c +++ b/src/bltin/printf.c @@ -332,6 +332,7 @@ unsigned conv_escape(char *str0, char *out0, bool mbchar) char *out = out0; char *str = str0; unsigned value; + int och; int ch; ch = *str; @@ -359,12 +360,18 @@ unsigned conv_escape(char *str0, char *out0, bool mbchar) } str--; + +check_value: + if (mbchar && (signed char)value >= CTL_FIRST && + (signed char)value <= CTL_LAST) + USTPUTC(CTLESC, out); break; case 'x': ch = 2; hex: + och = ch; value = 0; do { int c = *++str; @@ -391,6 +398,9 @@ hex: if (value < 0x80) break; + if (och <= 2) + goto check_value; + if (value < 0x110000) { int mboff = (mbchar - 1) * 2; unsigned uni = value; -- Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt