dovecot-2.2: lib: make printf_format_fix safer against shadowed ...

dovecot at dovecot.org dovecot at dovecot.org
Fri Jun 27 13:22:41 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/06f90ecbfb70
changeset: 17528:06f90ecbfb70
user:      Phil Carmody <phil at dovecot.fi>
date:      Fri Jun 27 16:13:09 2014 +0300
description:
lib: make printf_format_fix safer against shadowed %m behaviour
If there's a %m followed by a %n or %m, then the %n or %m won't be seen.
For %m, that's mostly harmless, but for %n it's potentially kaboom.

Signed-off-by: Phil Carmody <phil at dovecot.fi>

diffstat:

 src/lib/printf-format-fix.c |  16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diffs (51 lines):

diff -r 2c0b4244b935 -r 06f90ecbfb70 src/lib/printf-format-fix.c
--- a/src/lib/printf-format-fix.c	Fri Jun 27 16:12:40 2014 +0300
+++ b/src/lib/printf-format-fix.c	Fri Jun 27 16:13:09 2014 +0300
@@ -11,12 +11,13 @@
 	unsigned int len1, len2, len3;
 
 	i_assert((size_t)(p - fmt) < INT_MAX);
+	i_assert(p[0] == '%' && p[1] == 'm');
 
 	errstr = strerror(errno);
 
 	/* we'll assume that there's only one %m in the format string.
 	   this simplifies the code and there's really no good reason to have
-	   it multiple times. */
+	   it multiple times. Callers can trap this case themselves. */
 	len1 = p - fmt;
 	len2 = strlen(errstr);
 	len3 = strlen(p + 2);
@@ -35,6 +36,7 @@
 printf_format_fix_noalloc(const char *format, unsigned int *len_r)
 {
 	const char *p;
+	const char *ret = format;
 
 	for (p = format; *p != '\0'; ) {
 		if (*p++ == '%') {
@@ -42,16 +44,20 @@
 			case 'n':
 				i_panic("%%n modifier used");
 			case 'm':
-				return fix_format_real(format, p-1, len_r);
+				if (ret != format)
+					i_panic("%%m used twice");
+				ret = fix_format_real(format, p-1, len_r);
+				break;
 			case '\0':
-				i_panic("%% modifier missing");
+				i_panic("%% modifier missing in '%s'", format);
 			}
 			p++;
 		}
 	}
 
-	*len_r = p - format;
-	return format;
+	if (ret == format)
+		*len_r = p - format;
+	return ret;
 }
 
 const char *printf_format_fix_get_len(const char *format, unsigned int *len_r)


More information about the dovecot-cvs mailing list