Unzureichende Präzision oder Genauigkeit einer reellen Zahl

Beschreibung

Unzureichende Präzision oder Genauigkeit einer reellen Zahl tritt auf, wenn ein Produkt reelle Zahlen mit einer Implementierung verarbeitet, bei der die Darstellung die erforderliche Genauigkeit und Präzision im Nachkommateil nicht bewahrt, was zu fehlerhaften Ergebnissen führt. Wenn Sicherheitsentscheidungen oder Berechnungen von hochpräzisen Zahlen abhängen -- wie bei Finanztransaktionen oder Preisberechnungen -- können kleine Abweichungen ausgenutzt werden. Es existieren mehrere Speichermethoden einschließlich Festkomma-, Gleitkomma- und verhältnisbasierter Darstellungen, jeweils mit Genauigkeitsbeschränkungen. Probleme entstehen, wenn Brüche nicht in festen Ziffern dargestellt werden können, periodische Dezimalzahlen auftreten oder transzendente Zahlen erscheinen. Rundungsfehler führen dazu, dass Computerergebnisse von mathematisch korrekten Resultaten abweichen.

Risiko

Unzureichende Präzision hat schwerwiegende Auswirkungen. Fehler bei Finanzberechnungen, die zu monetären Verlusten führen. Sicherheitsumgehung durch Berechnungsmanipulation. Buffer Overflows durch fehlberechnete Grenzen. Anwendungsabstürze durch undefinierte Ergebnisse. Endlosschleifen durch Präzisionsfehler. Ausfälle sicherheitskritischer Systeme. Ausnutzbare Rundungsfehler. Hohe Wahrscheinlichkeit, wenn präzise Berechnungen Sicherheitsentscheidungen bestimmen.

Lösung

Genauere Darstellungen reeller Zahlen während der Architektur- und Designphase übernehmen. Verhältnisse von BigInts für extrem feine Präzision verwenden. Unum-Reals für verbesserte Genauigkeit implementieren. Speicher- und CPU-Kompromisse bewerten, da Alternativen zur Hardware-Gleitkommaberechnung Berechnungen typischerweise auf langsamere Software-Implementierungen verlagern. Festkomma-Arithmetik verwenden, wenn Präzisionsanforderungen klar definiert sind, während der Implementierungsphase.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

Undefinierte Ergebnisse verursachen oft Abstürze, Stillstände oder Endlosschleifen bei Überlaufbedingungen.
IntegritätBereich: Integrität

Fehlberechnete Werte erzeugen falsche Antworten mit Sicherheitsauswirkungen.
VertraulichkeitBereich: Vertraulichkeit, Integrität, Zugangskontrolle

Kann Buffer Overflows auslösen, die beliebige Codeausführung durch Grenzwert-Fehlberechnung ermöglichen.

Beispielcode

Verwundbarer Code

// VERWUNDBAR: Gleitkomma-Präzisionsprobleme

// VERWUNDBAR: Mullers Rekurrenz mit Standard-Floats
fn vulnerable_recurrence(y: f64, z: f64) -> f64 {
    // Diese Formel sollte gegen 5.0 konvergieren
    // Aber Gleitkommafehler führen zur Divergenz
    108.0 - ((815.0 - 1500.0 / z) / y)
}

fn vulnerable_muller_sequence() {
    let mut y = 4.0_f64;
    let mut z = 4.25_f64;

    // VERWUNDBAR: Präzisionsverlust verursacht falsche Konvergenz
    for i in 0..30 {
        let next = vulnerable_recurrence(y, z);
        println!("Iteration {}: {}", i, next);
        z = y;
        y = next;
        // Erwartet: konvergiert gegen 5.0
        // Tatsächlich: divergiert gegen 100.0 durch Präzisionsfehler
    }
}
# VERWUNDBAR: Python Gleitkomma-Probleme

# VERWUNDBAR: Finanzberechnung mit float
def vulnerable_calculate_total(prices):
    # VERWUNDBAR: Gleitkomma-Akkumulationsfehler
    total = 0.0
    for price in prices:
        total += price
    return total

    # Beispiel: 0.1 + 0.2 != 0.3 bei Gleitkomma
    # >>> 0.1 + 0.2
    # 0.30000000000000004

# VERWUNDBAR: Währungsumrechnung
def vulnerable_convert_currency(amount, rate):
    # VERWUNDBAR: Präzisionsverlust bei Umrechnung
    return amount * rate
    # Kleine Fehler summieren sich über viele Transaktionen

# VERWUNDBAR: Zinsberechnung
def vulnerable_compound_interest(principal, rate, years, compounds_per_year):
    # VERWUNDBAR: Exponentielle Berechnung verstärkt Präzisionsfehler
    return principal * (1 + rate / compounds_per_year) ** (compounds_per_year * years)

# VERWUNDBAR: Division, die exakt sein sollte
def vulnerable_split_bill(total, num_people):
    # VERWUNDBAR: Teilt möglicherweise nicht gleichmäßig
    per_person = total / num_people
    calculated_total = per_person * num_people
    # calculated_total stimmt möglicherweise wegen Präzision nicht mit total überein
    return per_person

# VERWUNDBAR: Vergleich mit Gleitkomma
def vulnerable_balance_check(balance, withdrawal):
    # VERWUNDBAR: Direkter Gleitkomma-Vergleich
    remaining = balance - withdrawal
    if remaining == 0.0:  # Wird möglicherweise nie exakt Null
        return "Konto leer"
    elif remaining < 0:
        return "Unzureichendes Guthaben"
    else:
        return "OK"
// VERWUNDBAR: C Gleitkomma-Probleme

#include <stdio.h>
#include <math.h>

// VERWUNDBAR: Puffergrößenberechnung mit float
void vulnerable_buffer_allocation(float data_size, float factor) {
    // VERWUNDBAR: Präzisionsverlust bei Größenberechnung
    int buffer_size = (int)(data_size * factor);

    // Wenn factor = 1.1 und data_size = 100
    // Erwartet: 110, könnte aber 109 sein wegen Abschneidung

    char* buffer = malloc(buffer_size);
    // Puffer möglicherweise zu klein für tatsächliche Daten
}

// VERWUNDBAR: Schleife mit Gleitkomma-Zähler
void vulnerable_float_loop() {
    // VERWUNDBAR: Terminiert möglicherweise nicht wie erwartet
    for (float f = 0.0f; f != 1.0f; f += 0.1f) {
        printf("%f\n", f);
        // 0.1 kann in Binär nicht exakt dargestellt werden
        // Schleife könnte 1.0 überschreiten und nie terminieren
    }
}

// VERWUNDBAR: Sicherheitsprüfung mit Float-Vergleich
int vulnerable_access_check(float user_level, float required_level) {
    // VERWUNDBAR: Direkter Gleichheitsvergleich
    if (user_level == required_level) {
        return 1;  // Zugang gewähren
    }
    // Kann fehlschlagen, auch wenn Werte gleich sein sollten
    return 0;
}

// VERWUNDBAR: Koordinatenberechnung für Sicherheitsgrenze
int vulnerable_point_in_boundary(float x, float y, float boundary) {
    // VERWUNDBAR: Präzisionsfehler an Grenzrändern
    float distance = sqrt(x*x + y*y);

    if (distance < boundary) {
        return 1;  // Innerhalb
    }
    // Punkte sehr nahe an der Grenze können falsch klassifiziert werden
    return 0;
}

Sichere Lösung

// SICHER: Verwendung präziser rationaler Arithmetik

use num_rational::BigRational;
use num_bigint::BigInt;

// SICHER: Mullers Rekurrenz mit beliebiger Präzision
fn safe_recurrence(y: BigRational, z: BigRational) -> BigRational {
    // SICHER: BigRational bietet exakte Arithmetik
    let c108 = BigRational::from_integer(BigInt::from(108));
    let c815 = BigRational::from_integer(BigInt::from(815));
    let c1500 = BigRational::from_integer(BigInt::from(1500));

    c108 - ((c815 - c1500 / z) / y)
}

fn safe_muller_sequence() {
    let mut y = BigRational::new(BigInt::from(4), BigInt::from(1));
    let mut z = BigRational::new(BigInt::from(17), BigInt::from(4));  // 4.25

    // SICHER: Konvergiert korrekt gegen 5.0
    for i in 0..30 {
        let next = safe_recurrence(y.clone(), z.clone());
        println!("Iteration {}: {}", i, next);
        z = y;
        y = next;
        // Konvergiert korrekt gegen 5
    }
}
# SICHER: Python mit präziser Dezimal-/Bruchbehandlung

from decimal import Decimal, ROUND_HALF_UP, getcontext
from fractions import Fraction

# SICHER: Präzision für Finanzberechnungen setzen
getcontext().prec = 28

# SICHER: Finanzberechnung mit Decimal
def safe_calculate_total(prices):
    # SICHER: Decimal für exakte Dezimalarithmetik verwenden
    total = Decimal('0')
    for price in prices:
        total += Decimal(str(price))
    return total

# SICHER: Währungsumrechnung mit kontrollierter Rundung
def safe_convert_currency(amount, rate, decimal_places=2):
    # SICHER: Explizite Präzision und Rundung
    amount_dec = Decimal(str(amount))
    rate_dec = Decimal(str(rate))
    result = amount_dec * rate_dec
    # Auf angegebene Dezimalstellen runden
    return result.quantize(Decimal(10) ** -decimal_places, rounding=ROUND_HALF_UP)

# SICHER: Zinsberechnung mit Decimal
def safe_compound_interest(principal, rate, years, compounds_per_year):
    # SICHER: Decimal-Arithmetik für finanzielle Präzision
    p = Decimal(str(principal))
    r = Decimal(str(rate))
    n = Decimal(str(compounds_per_year))
    t = Decimal(str(years))

    result = p * (1 + r / n) ** (n * t)
    return result.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

# SICHER: Exakte Division mit Fraction
def safe_split_bill(total, num_people):
    # SICHER: Fraction für exakte Division verwenden
    total_frac = Fraction(total).limit_denominator(100)
    per_person = total_frac / num_people

    # Für Anzeige in Cent umrechnen
    cents = int(per_person * 100)
    return cents / 100

# SICHER: Vergleich mit Toleranz
EPSILON = Decimal('0.0001')

def safe_balance_check(balance, withdrawal):
    # SICHER: Mit Toleranz vergleichen
    remaining = Decimal(str(balance)) - Decimal(str(withdrawal))

    if abs(remaining) < EPSILON:
        return "Konto leer"
    elif remaining < 0:
        return "Unzureichendes Guthaben"
    else:
        return "OK"

# SICHER: Präzisionsanforderungen validieren
def safe_calculation_with_validation(a, b, required_precision):
    """Berechnung mit Präzisionsvalidierung durchführen."""
    # SICHER: Angemessene Präzision setzen
    getcontext().prec = required_precision + 10  # Zusätzlicher Spielraum

    a_dec = Decimal(str(a))
    b_dec = Decimal(str(b))

    result = a_dec * b_dec

    # SICHER: Prüfen ob Präzision erhalten bleibt
    if len(str(result).replace('.', '').lstrip('0')) > required_precision:
        # Auf erforderliche Präzision runden
        result = result.quantize(Decimal(10) ** -(required_precision - 1))

    return result
// SICHER: C mit präziser Arithmetik

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>

// SICHER: Ganzzahlige Cent statt Float-Dollar verwenden
typedef int64_t cents_t;

// SICHER: Puffergrößenberechnung mit Ganzzahlarithmetik
void safe_buffer_allocation(size_t data_size, int factor_percent) {
    // SICHER: Ganzzahligen Prozentsatz verwenden (110% = 110)
    size_t buffer_size = (data_size * factor_percent + 99) / 100;
    // +99 stellt Aufrundung sicher

    char* buffer = malloc(buffer_size);
    // Puffergröße ist exakt
}

// SICHER: Schleife mit Ganzzahl-Zähler
void safe_integer_loop(int iterations) {
    // SICHER: Ganzzahl-Zähler verwenden
    for (int i = 0; i < iterations; i++) {
        // Operationen durchführen
        float progress = (float)i / iterations;  // Nur für Anzeige
        printf("Fortschritt: %.1f%%\n", progress * 100);
    }
}

// SICHER: Gleitkomma-Vergleich mit Epsilon
#define EPSILON 1e-9

int safe_float_equal(double a, double b) {
    // SICHER: Mit Toleranz vergleichen
    return fabs(a - b) < EPSILON;
}

int safe_float_less_than(double a, double b) {
    // SICHER: Präzision berücksichtigen
    return (a - b) < -EPSILON;
}

// SICHER: Sicherheitsprüfung mit Toleranz
int safe_access_check(double user_level, double required_level) {
    // SICHER: Epsilon-Vergleich verwenden
    if (fabs(user_level - required_level) < EPSILON) {
        return 1;  // Zugang gewähren
    }
    if (user_level > required_level + EPSILON) {
        return 1;  // Auch gewähren wenn darüber
    }
    return 0;
}

// SICHER: Grenzprüfung mit Sicherheitsabstand
int safe_point_in_boundary(double x, double y, double boundary) {
    // SICHER: Epsilon für Grenzunsicherheit einbeziehen
    double distance = sqrt(x*x + y*y);

    // Punkte innerhalb Epsilon der Grenze werden als unsicher behandelt
    if (distance < boundary - EPSILON) {
        return 1;  // Definitiv innerhalb
    } else if (distance > boundary + EPSILON) {
        return 0;  // Definitiv außerhalb
    } else {
        return -1;  // An der Grenze - speziell behandeln
    }
}

// SICHER: Festkomma-Arithmetik für Finanzen
typedef struct {
    int64_t value;    // Wert in kleinster Einheit (Cent)
    int decimals;     // Anzahl der Dezimalstellen
} fixed_point_t;

fixed_point_t fp_multiply(fixed_point_t a, fixed_point_t b) {
    // SICHER: Exakte Multiplikation mit bekannter Präzision
    fixed_point_t result;
    result.value = (a.value * b.value) / pow(10, b.decimals);
    result.decimals = a.decimals;
    return result;
}

CVE-Beispiele

  • CVE-1991-0001: Patriot-Raketensystem-Taktdrift durch Gleitkomma-Akkumulation, die Verfolgungsversagen verursachte (28 Opfer in Dhahran).
  • CVE-1996-0001: Ariane-5-Raketenexplosion durch Überlauf bei Gleitkomma-zu-Ganzzahl-Konvertierung.

Verwandte CWEs

  • CWE-682: Incorrect Calculation (übergeordnet)
  • CWE-190: Integer Overflow or Wraparound (verwandt)
  • CWE-119: Improper Restriction of Operations within Memory Buffer Bounds (kann folgen)
  • CWE-834: Excessive Iteration (kann folgen)
  • CWE-189: Numeric Errors (Kategorie)

Referenzen

  1. MITRE Corporation. "CWE-1339: Insufficient Precision or Accuracy of a Real Number." https://cwe.mitre.org/data/definitions/1339.html
  2. Goldberg, David. "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
  3. IEEE 754. "Standard for Floating-Point Arithmetic"