readFloat: memory exhaustion with large exponent
Numeric.readFloat takes time and memory linear in the
size of the number denoted by the input string. In particular,
processing a number expressed in scientific notation with a very large
exponent could cause a denial of service. The slowdown is observable on
a modern machine running GHC 9.4.4:
ghci> import qualified Numeric
ghci> Numeric.readFloat "1e1000000"    -- near instantaneous
[(Infinity,"")]
ghci> Numeric.readFloat "1e10000000"   -- perceptible pause
[(Infinity,"")]
ghci> Numeric.readFloat "1e100000000"  -- ~ 3 seconds
[(Infinity,"")]
ghci> Numeric.readFloat "1e1000000000" -- ~ 35 seconds
[(Infinity,"")]
In base
Numeric.readFloat is defined for all
RealFrac a => a:
readFloat :: RealFrac a => ReadS aThe RealFrac type class does not express any bounds on
the size of values representable in the types for which instances exist,
so bounds checking is not possible (in this generic function).
readFloat uses to
Text.Read.Lex.numberToRational which, among other things,
calculates 10 ^ exponent, which seems to take linear time
and memory.
Mitigation: use read. The
Read instances for Float and
Double perform bounds checks on the exponent, via
Text.Read.Lex.numberToRangedRational.
In toml-reader
The issue was detected in toml-reader version 0.1.0.0, and
mitigated in version 0.2.0.0 by immediately returning
Infinity when the exponent is large enough that there's no
reason to process it.
Info
- Published
 - July 22, 2023
 - Modified
 - July 22, 2023
 - CAPECs
 - < none >
 - CWEs
 - 1284
 - 789
 - Keywords
 - toml, parser, dos
 - Aliases
 - < none >
 - Related
 - < none >
 - References
 - [REPORT] https://gitlab.haskell.org/ghc/ghc/-/issues/23538
 - [REPORT] https://github.com/brandonchinn178/toml-reader/issues/8
 - [FIX] https://github.com/brandonchinn178/toml-reader/pull/9
 
Affected
base
- CVSS
 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
 - Versions
 >=3.0.3.1- Declarations
 - < none >
 
toml-reader
- CVSS
 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
 - Versions
 >=0.1.0.0 && <0.2.0.0- Declarations
 - < none >