Message ID | 5C58DC48-8E92-4581-A1DC-1491A3DC7CEB@gmail.com |
---|---|
State | New |
Headers | show |
On 04/02/2016 11:49 AM, Marcel Böhme wrote: > > Bootstrapped and regression tested on x86_64-pc-linux-gnu. Test cases > added + checked PR70498 is resolved. Richard - any objections from an RM perspective to check in such potentially security-related fixes now even if not regressions? > The patch now also accounts for overflows in d_compact_number which > is supposed to return -1 in case of negative numbers. I take it this isn't for the normal 'n' case, but for instances where we encounter overflows in d_number? Bernd
> On 4 Apr 2016, at 9:24 PM, Bernd Schmidt <bschmidt@redhat.com> wrote: > >> >> The patch now also accounts for overflows in d_compact_number which >> is supposed to return -1 in case of negative numbers. > > I take it this isn't for the normal 'n' case, but for instances where we encounter overflows in d_number? Yes. Best regards, - Marcel
I've been looking through this patch. I had intended to commit it, but after looking through it a little more carefully I think there are a few things left to solve. So, d_number/d_compact_number now return ints rather than longs, which makes sense since the lengths in things like struct demangle_component's s_name are integers. However, s_number there is defined as a long, so this does mean a tighter limit for things like d_template_param/d_make_template_param. Cc'ing Jason for an opinion on whether that's a problem or not (I suspect it isn't - t). > -static long > +static int > d_compact_number (struct d_info *di) > { > - long num; > + int num; > if (d_peek_char (di) == '_') > num = 0; > else if (d_peek_char (di) == 'n') > @@ -2957,7 +2957,7 @@ d_compact_number (struct d_info *di) > else > num = d_number (di) + 1; > > - if (! d_check_char (di, '_')) > + if (num < 0 || ! d_check_char (di, '_')) > return -1; > return num; > } Shouldn't we check for overflows before performing the +1 addition (i.e. 0 <= num < INT_MAX)? Ideally we'd also have a way to signal from d_number if we had an overflow while parsing that number. There's also this, in d_expression_1: index = d_compact_number (di) + 1; if (index == 0) return NULL; which probably ought to have the same kind of check (I'll note that at this point we've accumulated two "+1"s, I'll assume that's what we want). Please include a ChangeLog entry with the next patch. Bernd
Hi Bernd, > -static long > +static int > d_compact_number (struct d_info *di) > { > - long num; > + int num; > if (d_peek_char (di) == '_') > num = 0; > else if (d_peek_char (di) == 'n') > @@ -2957,7 +2957,7 @@ d_compact_number (struct d_info *di) > else > num = d_number (di) + 1; > > - if (! d_check_char (di, '_')) > + if (num < 0 || ! d_check_char (di, '_')) > return -1; > return num; > } > Shouldn't we check for overflows before performing the +1 addition (i.e. 0 <= num < INT_MAX)? Ideally we'd also have a way to signal from d_number if we had an overflow while parsing that number. Without an overflow signal, d_number will already be prone to return a negative number for supposedly non-negative numbers (those not preceded with ’n’). In that case an overflow check would be unnecessary in d_compact_number which is supposed to always return a positive number or a negative one (-1). If you decide in favour of an overflow signal, it must be handled by the call-sites. Not sure what the “default behaviour” should be then. Otherwise, we can simply assume that the call sites for d_number can handle negative numbers. Kindly advice. > > There's also this, in d_expression_1: > > index = d_compact_number (di) + 1; > if (index == 0) > return NULL; > > which probably ought to have the same kind of check (I'll note that at this point we've accumulated two "+1"s, I'll assume that's what we want). Yes. There should be an overflow check here. Thanks! - Marcel
On 04/13/2016 03:04 PM, Marcel Böhme wrote: > Hi Bernd, >> Shouldn't we check for overflows before performing the +1 addition >> (i.e. 0 <= num < INT_MAX)? Ideally we'd also have a way to signal >> from d_number if we had an overflow while parsing that number. > Without an overflow signal, d_number will already be prone to return > a negative number for supposedly non-negative numbers (those not > preceded with ’n’). In that case an overflow check would be > unnecessary in d_compact_number which is supposed to always return a > positive number or a negative one (-1). If you decide in favour of an > overflow signal, it must be handled by the call-sites. Not sure what > the “default behaviour” should be then. Otherwise, we can simply > assume that the call sites for d_number can handle negative numbers. Shouldn't we look into fixing d_number eventually so it can signal error? >> index = d_compact_number (di) + 1; if (index == 0) return NULL; >> >> which probably ought to have the same kind of check (I'll note that >> at this point we've accumulated two "+1"s, I'll assume that's what >> we want). > Yes. There should be an overflow check here. Could you update the patch for that? Bernd
Index: libiberty/cp-demangle.c =================================================================== --- libiberty/cp-demangle.c (revision 234663) +++ libiberty/cp-demangle.c (working copy) @@ -398,7 +398,7 @@ d_make_dtor (struct d_info *, enum gnu_v struct demangle_component *); static struct demangle_component * -d_make_template_param (struct d_info *, long); +d_make_template_param (struct d_info *, int); static struct demangle_component * d_make_sub (struct d_info *, const char *, int); @@ -421,9 +421,9 @@ static struct demangle_component *d_unqu static struct demangle_component *d_source_name (struct d_info *); -static long d_number (struct d_info *); +static int d_number (struct d_info *); -static struct demangle_component *d_identifier (struct d_info *, long); +static struct demangle_component *d_identifier (struct d_info *, int); static struct demangle_component *d_operator_name (struct d_info *); @@ -1119,7 +1119,7 @@ d_make_dtor (struct d_info *di, enum gnu /* Add a new template parameter. */ static struct demangle_component * -d_make_template_param (struct d_info *di, long i) +d_make_template_param (struct d_info *di, int i) { struct demangle_component *p; @@ -1135,7 +1135,7 @@ d_make_template_param (struct d_info *di /* Add a new function parameter. */ static struct demangle_component * -d_make_function_param (struct d_info *di, long i) +d_make_function_param (struct d_info *di, int i) { struct demangle_component *p; @@ -1620,7 +1620,7 @@ d_unqualified_name (struct d_info *di) static struct demangle_component * d_source_name (struct d_info *di) { - long len; + int len; struct demangle_component *ret; len = d_number (di); @@ -1633,12 +1633,12 @@ d_source_name (struct d_info *di) /* number ::= [n] <(non-negative decimal integer)> */ -static long +static int d_number (struct d_info *di) { int negative; char peek; - long ret; + int ret; negative = 0; peek = d_peek_char (di); @@ -1681,7 +1681,7 @@ d_number_component (struct d_info *di) /* identifier ::= <(unqualified source code identifier)> */ static struct demangle_component * -d_identifier (struct d_info *di, long len) +d_identifier (struct d_info *di, int len) { const char *name; @@ -1702,7 +1702,7 @@ d_identifier (struct d_info *di, long le /* Look for something which looks like a gcc encoding of an anonymous namespace, and replace it with a more user friendly name. */ - if (len >= (long) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 + if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX, ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0) { @@ -1870,7 +1870,7 @@ d_java_resource (struct d_info *di) { struct demangle_component *p = NULL; struct demangle_component *next = NULL; - long len, i; + int len, i; char c; const char *str; @@ -2012,7 +2012,7 @@ d_special_name (struct d_info *di) case 'C': { struct demangle_component *derived_type; - long offset; + int offset; struct demangle_component *base_type; derived_type = cplus_demangle_type (di); @@ -2946,10 +2946,10 @@ d_pointer_to_member_type (struct d_info /* <non-negative number> _ */ -static long +static int d_compact_number (struct d_info *di) { - long num; + int num; if (d_peek_char (di) == '_') num = 0; else if (d_peek_char (di) == 'n') @@ -2957,7 +2957,7 @@ d_compact_number (struct d_info *di) else num = d_number (di) + 1; - if (! d_check_char (di, '_')) + if (num < 0 || ! d_check_char (di, '_')) return -1; return num; } @@ -2969,7 +2969,7 @@ d_compact_number (struct d_info *di) static struct demangle_component * d_template_param (struct d_info *di) { - long param; + int param; if (! d_check_char (di, 'T')) return NULL; @@ -3502,7 +3502,7 @@ d_local_name (struct d_info *di) static int d_discriminator (struct d_info *di) { - long discrim; + int discrim; if (d_peek_char (di) != '_') return 1; @@ -3558,7 +3558,7 @@ static struct demangle_component * d_unnamed_type (struct d_info *di) { struct demangle_component *ret; - long num; + int num; if (! d_check_char (di, 'U')) return NULL; @@ -4086,10 +4086,10 @@ d_append_string (struct d_print_info *dp } static inline void -d_append_num (struct d_print_info *dpi, long l) +d_append_num (struct d_print_info *dpi, int l) { char buf[25]; - sprintf (buf,"%ld", l); + sprintf (buf,"%d", l); d_append_string (dpi, buf); } Index: libiberty/testsuite/demangle-expected =================================================================== --- libiberty/testsuite/demangle-expected (revision 234663) +++ libiberty/testsuite/demangle-expected (working copy) @@ -4422,12 +4422,17 @@ _Z3fooI1FEN1XIXszdtcl1PclcvT__EEE5arrayEE4TypeEv X<sizeof ((P(((F)())())).array)>::Type foo<F>() # -# Tests a use-after-free problem +# Tests a use-after-free problem PR70481 _Q.__0 ::Q.(void) # -# Tests a use-after-free problem +# Tests a use-after-free problem PR70481 _Q10-__9cafebabe. cafebabe.::-(void) +# +# Tests write access violation PR70498 + +_Z80800000000000000000000 +_Z80800000000000000000000