Ticket #13104: 01-sscanf-arith-undef.patch

File 01-sscanf-arith-undef.patch, 9.0 KB (added by teor, 5 years ago)

Avoid overflows and underflows in sscanf and friends

  • src/common/util.c

    diff --git a/src/common/util.c b/src/common/util.c
    index 75dd6ed..ff1a371 100644
    a b scan_unsigned(const char **bufp, unsigned long *out, int width, int base) 
    28372837  while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
    28382838         && scanned_so_far < width) {
    28392839    int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
    2840     unsigned long new_result = result * base + digit;
    2841     if (new_result < result)
    2842       return -1; /* over/underflow. */
    2843     result = new_result;
     2840    // Check for overflow beforehand, without actually causing any overflow
     2841    // This preserves functionality on compilers that don't wrap overflow
     2842    // (i.e. that trap or optimise away overflow)
     2843    // result * base + digit > ULONG_MAX
     2844    // result * base > ULONG_MAX - digit
     2845    if (result > (ULONG_MAX - digit)/base)
     2846      return -1; /* Processing this digit would overflow */
     2847    result = result * base + digit;
    28442848    ++scanned_so_far;
    28452849  }
    28462850
    scan_signed(const char **bufp, long *out, int width) 
    28752879  if (scan_unsigned(bufp, &result, width, 10) < 0)
    28762880    return -1;
    28772881
    2878   if (neg) {
     2882  if (neg && result > 0) {
    28792883    if (result > ((unsigned long)LONG_MAX) + 1)
    28802884      return -1; /* Underflow */
    2881     *out = -(long)result;
     2885    // Avoid overflow on the cast to signed long when result is LONG_MIN
     2886    // by subtracting 1 from the unsigned long positive value,
     2887    // then, after it has been cast to signed and negated,
     2888    // subtracting the original 1 (the double-subtraction is intentional).
     2889    // Otherwise, the cast to signed could cause a temporary long
     2890    // to equal LONG_MAX + 1, which is undefined.
     2891    // We avoid underflow on the subtraction by treating -0 as positive.
     2892    *out = (-(long)(result - 1)) - 1;
    28822893  } else {
    28832894    if (result > LONG_MAX)
    28842895      return -1; /* Overflow */
  • src/test/test_util.c

    diff --git a/src/test/test_util.c b/src/test/test_util.c
    index 1b7c936..005c91a 100644
    a b static void 
    16881688test_util_sscanf(void)
    16891689{
    16901690  unsigned u1, u2, u3;
     1691  unsigned long ulng;
    16911692  char s1[20], s2[10], s3[10], ch;
    16921693  int r;
    16931694  long lng1,lng2;
    test_util_sscanf(void) 
    17291730  test_eq(0, tor_sscanf("", "%u", &u1)); /* absent number */
    17301731  test_eq(0, tor_sscanf("A", "%u", &u1)); /* bogus number */
    17311732  test_eq(0, tor_sscanf("-1", "%u", &u1)); /* negative number */
    1732   test_eq(1, tor_sscanf("4294967295", "%u", &u1)); /* UINT32_MAX should work */
    1733   test_eq(4294967295u, u1);
    1734   test_eq(0, tor_sscanf("4294967296", "%u", &u1)); /* But not at 32 bits */
    1735   test_eq(1, tor_sscanf("4294967296", "%9u", &u1)); /* but parsing only 9... */
    1736   test_eq(429496729u, u1);
    17371733
    17381734  /* Numbers with size (eg. %2u) */
    17391735  test_eq(0, tor_sscanf("-1", "%2u", &u1));
    test_util_sscanf(void) 
    18281824  test_eq(int2, -1);
    18291825
    18301826#if SIZEOF_INT == 4
     1827  /* %u */
     1828  /* UINT32_MAX should work */
     1829  test_eq(1, tor_sscanf("4294967295", "%u", &u1));
     1830  test_eq(4294967295U, u1);
     1831
     1832  /* But UINT32_MAX + 1 shouldn't work */
     1833  test_eq(0, tor_sscanf("4294967296", "%u", &u1));
     1834  /* but parsing only 9... */
     1835  test_eq(1, tor_sscanf("4294967296", "%9u", &u1));
     1836  test_eq(429496729U, u1);
     1837
     1838  /* %x */
     1839  /* UINT32_MAX should work */
     1840  test_eq(1, tor_sscanf("FFFFFFFF", "%x", &u1));
     1841  test_eq(0xFFFFFFFF, u1);
     1842
     1843  /* But UINT32_MAX + 1 shouldn't work */
     1844  test_eq(0, tor_sscanf("100000000", "%x", &u1));
     1845
     1846  /* %d */
     1847  /* INT32_MIN and INT32_MAX should work */
    18311848  r = tor_sscanf("-2147483648. 2147483647.", "%d. %d.", &int1, &int2);
    18321849  test_eq(r,2);
    1833   test_eq(int1, -2147483647-1);
     1850  test_eq(int1, -2147483647 - 1);
    18341851  test_eq(int2, 2147483647);
    18351852
    1836   r = tor_sscanf("-2147483679.", "%d.", &int1);
     1853  /* But INT32_MIN - 1 and INT32_MAX + 1 shouldn't work */
     1854  r = tor_sscanf("-2147483649.", "%d.", &int1);
    18371855  test_eq(r,0);
    18381856
    1839   r = tor_sscanf("2147483678.", "%d.", &int1);
     1857  r = tor_sscanf("2147483648.", "%d.", &int1);
     1858  test_eq(r,0);
     1859
     1860  /* and the first failure stops further processing */
     1861  r = tor_sscanf("-2147483648. 2147483648.",
     1862                 "%d. %d.", &int1, &int2);
     1863  test_eq(r,1);
     1864
     1865  r = tor_sscanf("-2147483649. 2147483647.",
     1866                 "%d. %d.", &int1, &int2);
     1867  test_eq(r,0);
     1868
     1869  r = tor_sscanf("2147483648. -2147483649.",
     1870                 "%d. %d.", &int1, &int2);
    18401871  test_eq(r,0);
    18411872#elif SIZEOF_INT == 8
     1873  /* %u */
     1874  /* UINT64_MAX should work */
     1875  test_eq(1, tor_sscanf("18446744073709551615", "%u", &u1));
     1876  test_eq(18446744073709551615U, u1);
     1877
     1878  /* But UINT64_MAX + 1 shouldn't work */
     1879  test_eq(0, tor_sscanf("18446744073709551616", "%u", &u1));
     1880  /* but parsing only 19... */
     1881  test_eq(1, tor_sscanf("18446744073709551616", "%19u", &u1));
     1882  test_eq(1844674407370955161U, u1);
     1883
     1884  /* %x */
     1885  /* UINT64_MAX should work */
     1886  test_eq(1, tor_sscanf("FFFFFFFFFFFFFFFF", "%x", &u1));
     1887  test_eq(0xFFFFFFFFFFFFFFFF, u1);
     1888
     1889  /* But UINT64_MAX + 1 shouldn't work */
     1890  test_eq(0, tor_sscanf("10000000000000000", "%x", &u1));
     1891
     1892  /* %d */
     1893  /* INT64_MIN and INT64_MAX should work */
    18421894  r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
    18431895                 "%d. %d.", &int1, &int2);
    18441896  test_eq(r,2);
    1845   test_eq(int1, -9223372036854775807-1);
     1897  test_eq(int1, -9223372036854775807 - 1);
    18461898  test_eq(int2, 9223372036854775807);
    18471899
     1900  /* But INT64_MIN - 1 and INT64_MAX + 1 shouldn't work */
    18481901  r = tor_sscanf("-9223372036854775809.", "%d.", &int1);
    18491902  test_eq(r,0);
    18501903
    18511904  r = tor_sscanf("9223372036854775808.", "%d.", &int1);
    18521905  test_eq(r,0);
     1906
     1907  /* and the first failure stops further processing */
     1908  r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
     1909                 "%d. %d.", &int1, &int2);
     1910  test_eq(r,1);
     1911
     1912  r = tor_sscanf("-9223372036854775809. 9223372036854775807.",
     1913                 "%d. %d.", &int1, &int2);
     1914  test_eq(r,0);
     1915
     1916  r = tor_sscanf("9223372036854775808. -9223372036854775809.",
     1917                 "%d. %d.", &int1, &int2);
     1918  test_eq(r,0);
    18531919#endif
    18541920
    18551921#if SIZEOF_LONG == 4
     1922  /* %lu */
     1923  /* UINT32_MAX should work */
     1924  test_eq(1, tor_sscanf("4294967295", "%lu", &ulng));
     1925  test_eq(4294967295UL, ulng);
     1926
     1927  /* But UINT32_MAX + 1 shouldn't work */
     1928  test_eq(0, tor_sscanf("4294967296", "%lu", &ulng));
     1929  /* but parsing only 9... */
     1930  test_eq(1, tor_sscanf("4294967296", "%9lu", &ulng));
     1931  test_eq(429496729UL, ulng);
     1932
     1933  /* %lx */
     1934  /* UINT32_MAX should work */
     1935  test_eq(1, tor_sscanf("FFFFFFFF", "%lx", &ulng));
     1936  test_eq(0xFFFFFFFFUL, ulng);
     1937
     1938  /* But UINT32_MAX + 1 shouldn't work */
     1939  test_eq(0, tor_sscanf("100000000", "%lx", &ulng));
     1940
     1941  /* %ld */
     1942  /* INT32_MIN and INT32_MAX should work */
    18561943  r = tor_sscanf("-2147483648. 2147483647.", "%ld. %ld.", &lng1, &lng2);
    18571944  test_eq(r,2);
    1858   test_eq(lng1, -2147483647 - 1);
    1859   test_eq(lng2, 2147483647);
     1945  test_eq(lng1, -2147483647L - 1L);
     1946  test_eq(lng2, 2147483647L);
     1947
     1948  /* But INT32_MIN - 1 and INT32_MAX + 1 shouldn't work */
     1949  r = tor_sscanf("-2147483649.", "%ld.", &lng1);
     1950  test_eq(r,0);
     1951
     1952  r = tor_sscanf("2147483648.", "%ld.", &lng1);
     1953  test_eq(r,0);
     1954
     1955  /* and the first failure stops further processing */
     1956  r = tor_sscanf("-2147483648. 2147483648.",
     1957                 "%ld. %ld.", &lng1, &lng2);
     1958  test_eq(r,1);
     1959
     1960  r = tor_sscanf("-2147483649. 2147483647.",
     1961                 "%ld. %ld.", &lng1, &lng2);
     1962  test_eq(r,0);
     1963
     1964  r = tor_sscanf("2147483648. -2147483649.",
     1965                 "%ld. %ld.", &lng1, &lng2);
     1966  test_eq(r,0);
    18601967#elif SIZEOF_LONG == 8
     1968  /* %lu */
     1969  /* UINT64_MAX should work */
     1970  test_eq(1, tor_sscanf("18446744073709551615", "%lu", &ulng));
     1971  test_eq(18446744073709551615UL, ulng);
     1972
     1973  /* But UINT64_MAX + 1 shouldn't work */
     1974  test_eq(0, tor_sscanf("18446744073709551616", "%lu", &ulng));
     1975  /* but parsing only 19... */
     1976  test_eq(1, tor_sscanf("18446744073709551616", "%19lu", &ulng));
     1977  test_eq(1844674407370955161UL, ulng);
     1978
     1979  /* %lx */
     1980  /* UINT64_MAX should work */
     1981  test_eq(1, tor_sscanf("FFFFFFFFFFFFFFFF", "%lx", &ulng));
     1982  test_eq(0xFFFFFFFFFFFFFFFFUL, ulng);
     1983
     1984  /* But UINT64_MAX + 1 shouldn't work */
     1985  test_eq(0, tor_sscanf("10000000000000000", "%lx", &ulng));
     1986
     1987  /* %ld */
     1988  /* INT64_MIN and INT64_MAX should work */
    18611989  r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
    18621990                 "%ld. %ld.", &lng1, &lng2);
    18631991  test_eq(r,2);
    1864   test_eq(lng1, -9223372036854775807L - 1);
     1992  test_eq(lng1, -9223372036854775807L - 1L);
    18651993  test_eq(lng2, 9223372036854775807L);
    18661994
     1995  /* But INT64_MIN - 1 and INT64_MAX + 1 shouldn't work */
     1996  r = tor_sscanf("-9223372036854775809.", "%ld.", &lng1);
     1997  test_eq(r,0);
     1998
     1999  r = tor_sscanf("9223372036854775808.", "%ld.", &lng1);
     2000  test_eq(r,0);
     2001
     2002  /* and the first failure stops further processing */
    18672003  r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
    18682004                 "%ld. %ld.", &lng1, &lng2);
    18692005  test_eq(r,1);
    1870   r = tor_sscanf("-9223372036854775809. 9223372036854775808.",
     2006
     2007  r = tor_sscanf("-9223372036854775809. 9223372036854775807.",
     2008                 "%ld. %ld.", &lng1, &lng2);
     2009  test_eq(r,0);
     2010
     2011  r = tor_sscanf("9223372036854775808. -9223372036854775809.",
    18712012                 "%ld. %ld.", &lng1, &lng2);
    18722013  test_eq(r,0);
    18732014#endif