CWE-1339: Insufficient Precision or Accuracy of a Real Number

Export to Word

Description

The product processes a real number with an implementation in which the number's representation does not preserve required accuracy and precision in its fractional part, causing an incorrect result.

Extended Description

When a security decision or calculation requires highly precise, accurate numbers such as financial calculations or prices, then small variations in the number could be exploited by an attacker. There are multiple ways to store the fractional part of a real number in a computer. In all of these cases, there is a limit to the accuracy of recording a fraction. If the fraction can be represented in a fixed number of digits (binary or decimal), there might not be enough digits assigned to represent the number. In other cases the number cannot be represented in a fixed number of digits due to repeating in decimal or binary notation (e.g. 0.333333...) or due to a transcendental number such as Π or √2. Rounding of numbers can lead to situations where the computer results do not adequately match the result of sufficiently accurate math.


ThreatScore

Threat Mapped score: 0.0

Industry: Finiancial

Threat priority: Unclassified


Observed Examples (CVEs)

Related Attack Patterns (CAPEC)

N/A


Attack TTPs

N/A

Modes of Introduction

Phase Note
Implementation This weakness is introduced when the developer picks a method to represent a real number. The weakness may only be visible with very specific numeric inputs.

Common Consequences

Potential Mitigations

Applicable Platforms


Demonstrative Examples

Intro: Muller's Recurrence is a series that is supposed to converge to the number 5. When running this series with the following code, different implementations of real numbers fail at specific iterations:

Body: The chart below shows values for different data structures in the rust language when Muller's recurrence is executed to 80 iterations. The data structure f64 is a 64 bit float. The data structures I<number>F<number> are fixed representations 128 bits in length that use the first number as the size of the integer and the second size as the size of the fraction (e.g. I16F112 uses 16 bits for the integer and 112 bits for the fraction). The data structure of Ratio comes in three different implementations: i32 uses a ratio of 32 bit signed integers, i64 uses a ratio of 64 bit signed integers and BigInt uses a ratio of signed integer with up to 2^32 digits of base 256. Notice how even with 112 bits of fractions or ratios of 64bit unsigned integers, this math still does not converge to an expected value of 5.

fn rec_float(y: f64, z: f64) -> f64 { 108.0 - ((815.0 - 1500.0 / z) / y); } fn float_calc(turns: usize) -> f64 { let mut x: Vec<f64> = vec![4.0, 4.25]; (2..turns + 1).for_each(|number| { x.push(rec_float(x[number - 1], x[number - 2])); }); x[turns] }

Intro: On February 25, 1991, during the eve of the Iraqi invasion of Saudi Arabia, a Scud missile fired from Iraqi positions hit a US Army barracks in Dhahran, Saudi Arabia. It miscalculated time and killed 28 people [REF-1190].

Intro: Sleipner A, an offshore drilling platform in the North Sea, was incorrectly constructed with an underestimate of 50% of strength in a critical cluster of buoyancy cells needed for construction. This led to a leak in buoyancy cells during lowering, causing a seismic event of 3.0 on the Richter Scale and about $700M loss [REF-1281].

Notes

← Back to CWE list