Page MenuHome GnuPG

Exception handling for very large or invalid number in function parse_number(...) in the file cJSON.c:184
Closed, ResolvedPublic

Description

(SYSTEM: ArchLinux - current version, gpgme version 1.12.0)
Problem:
runtime error: signed integer overflow: 2147483640 + 8 cannot be represented in type 'int'
if

const char * num

is a very large number, then the variable subscale will overflow

 while (*num >= '0' && *num <= '9'){
          subscale = (subscale * 10) + (*num++ - '0');	/* Number? */
      }

Example:

{
   "name": "123e11235135987",
}

The exponent integer is larger then the representation of an integer value

FIX:

/* Parse the input text to generate a number, and populate the result
 * into item. */
static const char *
parse_number (cJSON * item, const char *num)
{
  double n = 0, sign = 1, scale = 0;
  int subscale = 0, signsubscale = 1;

  if (*num == '-')
    sign = -1, num++;		/* Has sign? */
  if (*num == '0')
    num++;			/* is zero */
  if (*num >= '1' && *num <= '9')
    do
      n = (n * 10.0) + (*num++ - '0');
    while (*num >= '0' && *num <= '9');	/* Number? */
  if (*num == '.' && num[1] >= '0' && num[1] <= '9')
    {
      num++;
      do
	      n = (n * 10.0) + (*num++ - '0'), scale--;
      while (*num >= '0' && *num <= '9');
    }				/* Fractional part? */
  if (*num == 'e' || *num == 'E')	/* Exponent? */
    {
      num++;
      if (*num == '+')
	      num++;
      else if (*num == '-')
	      signsubscale = -1, num++;	/* With sign? */
      while (*num >= '0' && *num <= '9'){
        double tmp = ((double) subscale)*10;
        double max_value = INT32_MAX;
        if(tmp >  max_value){
          break;
        }else{
          subscale = (subscale * 10) + (*num++ - '0');	/* Number? */
        }
      }
    }

  /* number = +/- number.fraction * 10^+/- exponent */
  n = sign * n * pow (10.0, (scale + subscale * signsubscale));
  
  // proof if n is "nan" or "inf"
  if( isnan(n) || isinf(n) )  {
      item->valuedouble = 0;
      item->valueint = 0;
  } else {
      double max_value = INT32_MAX;
      double min_value = INT32_MIN; 
      if(n > max_value){
        item->valueint = 0;
        item->valuedouble = n;
      } else if(n < min_value) {
        item->valueint = 0;
        item->valuedouble = n;
      } else {
        item->valuedouble = n;
        item->valueint = (int) n;
      }
  }

  item->type = cJSON_Number;
  return num;
}

found with libFuzzer and ASAN by clang 7.0.1

regards
Sirko Höer
Code Intelligence GmbH

Details

Version
1.12.0