1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

Tighten up vfprintf width, precision, and total length overflow handling.

With help from Paul Eggert, Carlos O'Donell, and Roland McGrath.
	* stdio-common/printf-parse.h (read_int): Change return type to
	'int', return -1 on INT_MAX overflow.
	* stdio-common/vfprintf.c (vfprintf): Validate width and precision
	against overflow of INT_MAX.  Set errno to EOVERFLOW when 'done'
	overflows INT_MAX.  Check for overflow of in-format-string precision
	values properly.  Use EOVERFLOW rather than ERANGE throughout.  Use
	SIZE_MAX not INT_MAX for integer overflow test.
	* stdio-common/printf-parsemb.c: If read_int signals an overflow,
	skip the construct in the format string but do not record anything.
	* stdio-common/bug22.c: Adjust to test both width/prevision
	INT_MAX overflow as well as total length INT_MAX overflow.  Check
	explicitly for proper errno values.
This commit is contained in:
David S. Miller
2012-04-02 14:31:19 -07:00
parent 302cadd343
commit 135ffda8b8
5 changed files with 147 additions and 39 deletions

View File

@ -87,12 +87,15 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
n = read_int (&format);
if (n > 0 && *format == L_('$'))
if (n != 0 && *format == L_('$'))
/* Is positional parameter. */
{
++format; /* Skip the '$'. */
spec->data_arg = n - 1;
*max_ref_arg = MAX (*max_ref_arg, n);
if (n != -1)
{
spec->data_arg = n - 1;
*max_ref_arg = MAX (*max_ref_arg, n);
}
}
else
/* Oops; that was actually the width and/or 0 padding flag.
@ -160,10 +163,13 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
/* The width argument might be found in a positional parameter. */
n = read_int (&format);
if (n > 0 && *format == L_('$'))
if (n != 0 && *format == L_('$'))
{
spec->width_arg = n - 1;
*max_ref_arg = MAX (*max_ref_arg, n);
if (n != -1)
{
spec->width_arg = n - 1;
*max_ref_arg = MAX (*max_ref_arg, n);
}
++format; /* Skip '$'. */
}
}
@ -177,9 +183,13 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
}
}
else if (ISDIGIT (*format))
/* Constant width specification. */
spec->info.width = read_int (&format);
{
int n = read_int (&format);
/* Constant width specification. */
if (n != -1)
spec->info.width = n;
}
/* Get the precision. */
spec->prec_arg = -1;
/* -1 means none given; 0 means explicit 0. */
@ -196,10 +206,13 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
{
n = read_int (&format);
if (n > 0 && *format == L_('$'))
if (n != 0 && *format == L_('$'))
{
spec->prec_arg = n - 1;
*max_ref_arg = MAX (*max_ref_arg, n);
if (n != -1)
{
spec->prec_arg = n - 1;
*max_ref_arg = MAX (*max_ref_arg, n);
}
++format;
}
}
@ -213,7 +226,12 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
}
}
else if (ISDIGIT (*format))
spec->info.prec = read_int (&format);
{
int n = read_int (&format);
if (n != -1)
spec->info.prec = n;
}
else
/* "%.?" is treated like "%.0?". */
spec->info.prec = 0;