Mercurial > dovecot > core-2.2
view src/lib/printf-format-fix.c @ 21339:8d49b6ed7bab
lib: Fix %n detection in printf_format_fix_noalloc()
It's undefined how flags, precision or length modifiers are handled with %n,
so make sure we catch all of them to detect an unwanted %n.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Tue, 29 Nov 2016 23:29:04 +0200 |
parents | bc57c62167fc |
children | 4efaa627264d |
line wrap: on
line source
/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "printf-format-fix.h" static const char * fix_format_real(const char *fmt, const char *p, size_t *len_r) { const char *errstr; char *buf; size_t 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. Callers can trap this case themselves. */ len1 = p - fmt; len2 = strlen(errstr); len3 = strlen(p + 2); /* @UNSAFE */ buf = t_buffer_get(len1 + len2 + len3 + 1); memcpy(buf, fmt, len1); memcpy(buf + len1, errstr, len2); memcpy(buf + len1 + len2, p + 2, len3 + 1); *len_r = len1 + len2 + len3; return buf; } static const char * printf_format_fix_noalloc(const char *format, size_t *len_r) { static const char *printf_skip_chars = "# -+'I.*0123456789hlLjzt"; const char *ret, *p, *p2; p = ret = format; while ((p2 = strchr(p, '%')) != NULL) { 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': i_panic("%% modifier missing in '%s'", format); } p++; } if (ret == format) *len_r = p - format + strlen(p); return ret; } const char *printf_format_fix_get_len(const char *format, size_t *len_r) { const char *ret; ret = printf_format_fix_noalloc(format, len_r); if (ret != format) t_buffer_alloc(*len_r + 1); return ret; } const char *printf_format_fix(const char *format) { const char *ret; size_t len; ret = printf_format_fix_noalloc(format, &len); if (ret != format) t_buffer_alloc(len + 1); return ret; } const char *printf_format_fix_unsafe(const char *format) { size_t len; return printf_format_fix_noalloc(format, &len); }