Mercurial > dovecot > core-2.2
changeset 17528:06f90ecbfb70
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@dovecot.fi>
author | Phil Carmody <phil@dovecot.fi> |
---|---|
date | Fri, 27 Jun 2014 16:13:09 +0300 |
parents | 2c0b4244b935 |
children | 60fbbf7ea75d |
files | src/lib/printf-format-fix.c |
diffstat | 1 files changed, 11 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- 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)