tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

printf(1) and incomplete escape sequence



Hello folks,
I have discovered a possible edge-case in printf(1) usage when
providing as an argument just a single backslash (`\'). In that
case printf(1) try to print through the end of *argv[] leading to
print out the first environment variable, e.g.:
 | % /usr/bin/printf '\'
 | printf: unknown escape sequence `\'
 | ACRONYMDB=...
This happen because in printf.c:173 (-r1.37) conv_escape() is called
with a fmt that is just a `0円':
 169			/* find next format specification */
 170			for (fmt = format; (ch = *fmt++) != '0円';) {
 171				if (ch == '\\') {
 172					char c_ch;
 173					fmt = conv_escape(fmt, &c_ch);
 174					putchar(c_ch);
 175					continue;
 176				}
...and then in conv_escape() we do:
 426	static char *
 427	conv_escape(char *str, char *conv_ch)
 428	{
 429		char value;
 430		char ch;
 431		char num_buf[4], *num_end;
 432	
 433		ch = *str++;
 434	
 435		switch (ch) {
 ...		...
 472		default:
 473			warnx("unknown escape sequence `\\%c'", ch);
 474			rval = 1;
 475			value = ch;
 476			break;
 477		}
 478	
 479		*conv_ch = value;
 480		return str;
 481	}
So ch is actually `0円' and due the *str++ we "jump" over the `0円', so
when the execution come back to printf.c:174 no `0円' will be found and
we iterate pass through *argv[].
What should we do if we receive just a `printf '\''?
IIUC according POSIX this is unspecified behaviour and for consistency
I have treated it similarly to the `default' case for "unknown
escape sequence" (possible patch with a candidate commit message
attached in this email).
What do you think we should do? Any feedbacks/comments about it?
Thank you!
Fix possible out-of-bounds read for empty escape sequence (i.e. a `\' alone).
The single `\' is treated as `\\' and a warning is printed and the exit status
raised (like other unknown escape sequences).
Index: printf.c
===================================================================
RCS file: /cvsroot/src/usr.bin/printf/printf.c,v
retrieving revision 1.37
diff -u -p -r1.37 printf.c
--- printf.c	16 Jun 2015 22:54:10 -0000	1.37
+++ printf.c	2 Jul 2018 14:35:45 -0000
@@ -430,6 +430,14 @@ conv_escape(char *str, char *conv_ch)
 	char ch;
 	char num_buf[4], *num_end;
 
+	if (*str == '0円') {
+		warnx("incomplete escape sequence");
+		rval = 1;
+		value = '\\';
+		*conv_ch = value;
+		return str;
+	}
+
 	ch = *str++;
 
 	switch (ch) {


Home | Main Index | Thread Index | Old Index

AltStyle によって変換されたページ (->オリジナル) /