Floating-point numbers can take on two classes of exceptional values; infinity and NaN (not-a-number). These values are returned as the result of exceptional or otherwise unresolvable floating-point operations. (See also : FLP32-C. Prevent or detect domain and range errors in math functions.) . Additionally, they can be directly input by a user by scanf
or similar functions. Failure to detect and handle such values can result in undefined behavior.
NaN values are particularly problematic , as because the expression NaN == NaN (for every possible value of NaN) returns false. Any comparisons made with NaN as one of the arguments returns false, and all arithmetic functions on NaNs simply propagate them through the code. Hence, a NaN entered in one location in the code and not properly handled could potentially cause problems in other, more distant sections.
Formatted-input functions such as sscanf scanf
will accept the values INF
, INFINITY
, or NAN
(not case sensitiveinsensitive) as valid inputs for the %f
format specification, allowing malicious users to feed them directly to a program. Programs should therefore check to ensure that all input floating-point values (especially those controlled by the user) do not have either neither of these values if doing so would be inappropriate. The <math.h>
library provides two macros for this purpose: isinf
and isnan
.
isinf
and isnan
The isinf
macro tests an input floating-point value for infinity. isinf
returns 1 if x is infinity, -1 if x is negative infinity(val)
is nonzero if val
is an infinity (positive or negative), and 0 otherwise.
isnan
tests if an input is NaN. isnan(
\xval)
is 1 nonzero if x val
is a NaN, and 0 otherwise.
If infinity or NaN values are not acceptable inputs in a program, these macros should be used to ensure they are not passed to vulnerable functions.
Noncompliant Code Example
The following This noncompliant code example accepts user data without first validating it.:
Code Block | ||||
---|---|---|---|---|
| ||||
float currentBalance; /* User's cash balance */ void doDeposit() { floatdouble val; scanf("%g%f", &val); if(val >= MAX_VALUE - currentBalance) { /* Handle range error */ } currentBalance += val; } |
This can be a problem if an invalid value is entered for val
and subsequently used for calculations or as control values. The user could, for example, input the values strings "INF"
, "INFINITY"
, or "NAN"
(case insensitive) on the command line, which would be parsed by scanf
into the floating-point representations of infinity and NaN. All subsequent calculations using these values would be invalid, possibly crashing the program and enabling a DOS attack.
Compliant Code Example
Here, for example, entering "nan"
for val
would force currentBalance
to also equal "nan"
, corrupting its value. If this value is used elsewhere for calculations, every resulting value would also be a NaN, possibly destroying important data.
Implementation Details
The following code was run on 32-bit GNU Linux using the GCC 3.4.6 compiler. On this platform, FLT_MAX
has the value 340282346638528859811704183484516925440.000000.
Code Block |
---|
#include <stdio.h>
int main(int argc, char *argv[]) {
float val, currentBalance=0;
scanf("%f", &val);
currentBalance+=val;
printf("%f\n", currentBalance);
return 0;
}
|
The following table shows the value of currentBalance
returned for various arguments:
Input |
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
As this example demonstrates, the user can enter the exceptional values infinity
and NaN
, as well as force a float's value to be infinite, by entering out-of-range floats. These entries subsequently corrupt the value of currentBalance
. So by entering exceptional floats, an attacker can corrupt the program data, possibly leading to a crash.
Compliant Solution
This compliant solution The following code first validates the input float before using it. The value is tested to ensure that it is within the acceptable range of MIN_VAL to MAX_VAL (and is therefore neither infinity nor negative infinity)neither an infinity nor a NaN.
Code Block | ||||
---|---|---|---|---|
| ||||
float currentBalance; /* User's cash balance */ void doDeposit() { floatdouble val; scanf("%g%f", &val); if(val<MIN_VAL || val>MAX_VAL (isinf(val)) { /* handleHandle rangeinfinity error */ } if (isnan(val)) { /* testHandle NaN error */ } { if (val >= MAX_VALUE - currentBalance) { /* handleHandle NaNrange error */ } } |
...
currentBalance += val;
}
|
Exceptions
Occasionally, NaN or infinity may be acceptable or expected inputs to a program. If this is the case, then explicit checks may not be necessary. Such programs must, however, be prepared to handle these inputs gracefully and not blindly use them in mathematical expressions where they are not appropriate.
Risk Assessment
Inappropriate floating-point inputs can result in invalid calculations and unexpected results, possibly leading to crashing and providing a DOS opportunitya denial-of-service opportunity.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
FLP04-C |
low
probable
high
P6
L2
...
Low | Probable | High | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported: Astrée reports potential runtime error resulting from missing checks for exceptional values. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule recommendation on the CERT website.
References
Related Guidelines
SEI CERT C++ Coding Standard | FLP04-CPP. Check floating-point inputs for exceptional values |
CERT Oracle Secure Coding Standard for Java | FLP06-J. Check floating-point inputs for exceptional values |
Bibliography
...
\[[IEEE 754|AA. C References#IEEE 754 2006]\]
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Wiki Markup