changeset 21340:4efaa627264d

lib: Allow only known %chars in printf_format_fix_noalloc() Otherwise if some libc adds a new unsupported character, our %n check might break.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 29 Nov 2016 23:37:43 +0200
parents 8d49b6ed7bab
children 499e52172881
files src/lib/printf-format-fix.c
diffstat 1 files changed, 19 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/printf-format-fix.c	Tue Nov 29 23:29:04 2016 +0200
+++ b/src/lib/printf-format-fix.c	Tue Nov 29 23:37:43 2016 +0200
@@ -36,6 +36,9 @@
 printf_format_fix_noalloc(const char *format, size_t *len_r)
 {
 	static const char *printf_skip_chars = "# -+'I.*0123456789hlLjzt";
+	/* as a tiny optimization keep the most commonly used conversion
+	   modifiers first, so strchr() stops early. */
+	static const char *printf_allowed_conversions = "sudcioxXp%eEfFgGaA";
 	const char *ret, *p, *p2;
 
 	p = ret = format;
@@ -43,16 +46,23 @@
 		p = p2+1;
 		while (*p != '\0' && strchr(printf_skip_chars, *p) != NULL)
 			p++;
-		switch (*p) {
-		case 'n':
-			i_panic("%%n modifier used");
-		case 'm':
-			if (ret != format)
-				i_panic("%%m used twice");
-			ret = fix_format_real(format, p-1, len_r);
-			break;
-		case '\0':
+
+		if (*p == '\0') {
 			i_panic("%% modifier missing in '%s'", format);
+		} else if (strchr(printf_allowed_conversions, *p) != NULL) {
+			/* allow & ignore */
+		} else {
+			switch (*p) {
+			case 'n':
+				i_panic("%%n modifier used");
+			case 'm':
+				if (ret != format)
+					i_panic("%%m used twice");
+				ret = fix_format_real(format, p-1, len_r);
+				break;
+			default:
+				i_panic("Unsupported %%%c modifier", *p);
+			}
 		}
 		p++;
 	}