Fehlende Referenz auf aktive allozierte Ressource

Beschreibung

Fehlende Referenz auf aktive allozierte Ressource ist eine Ressourcenverwaltungsschwachstelle, bei der Software eine Ressource alloziert, aber keine Referenz darauf behält, was verhindert, dass die Ressource zurückgewonnen oder ordnungsgemäß verwaltet werden kann. Dies tritt typischerweise auf, wenn ein Pointer oder Handle auf eine allozierte Ressource überschrieben wird, den Gültigkeitsbereich verlässt oder anderweitig verloren geht, bevor die Ressource freigegeben wird. Die verwaiste Ressource kann nicht für die Bereinigung erreicht werden, was zu Ressourcenlecks führt.

Risiko

Wenn Referenzen auf allozierte Ressourcen verloren gehen, werden diese Ressourcen verwaist und können nicht freigegeben werden, was zu Ressourcenerschöpfung führt. Angreifer können dies ausnutzen, indem sie wiederholt Allokations-Codepfade auslösen und schließlich verfügbare Ressourcen (Speicher, Dateideskriptoren, Netzwerkverbindungen) erschöpfen und Denial of Service verursachen. Bei langlebigen Diensten akkumulieren selbst kleine Lecks im Laufe der Zeit, verschlechtern die Leistung und verursachen schließlich Ausfälle. Die Schwachstelle ist besonders schwerwiegend für begrenzte Ressourcen wie Dateideskriptoren oder Datenbankverbindungen.

Lösung

Behalten Sie immer Referenzen auf allozierte Ressourcen, bis sie ordnungsgemäß freigegeben werden. Verwenden Sie RAII (Resource Acquisition Is Initialization) Muster in C++, um die Ressourcenlebensdauer an den Objektbereich zu binden. In anderen Sprachen verwenden Sie try-finally oder try-with-resources Muster, um Bereinigung sicherzustellen. Bevor Sie einen Pointer oder eine Referenz überschreiben, stellen Sie sicher, dass die alte Ressource zuerst freigegeben wird. Verwenden Sie Smart Pointer oder Handle-Klassen, die automatisch die Ressourcenlebensdauer verwalten. Verwenden Sie Speicherleck-Erkennungstools während der Entwicklung.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS: Ressourcenverbrauch - Verlorene Referenzen verhindern Ressourcenrückgewinnung, was zu Erschöpfung und Denial of Service führt.
IntegritätBereich: Integrität

Unerwarteter Zustand - Programmzustand wird inkonsistent, da Ressourcen ohne ordnungsgemäße Verfolgung existieren.
VertraulichkeitBereich: Vertraulichkeit

Informationsoffenlegung - Durchgesickerte Ressourcen können sensible Daten länger als beabsichtigt behalten.

Beispielcode

Verwundbarer Code

// Verwundbar: Pointer ohne Freigabe des Originals überschrieben
void vulnerable_overwrite() {
    char* buffer = malloc(1024);
    strcpy(buffer, "Initiale Daten");

    // Verwundbar: Ursprüngliche Allokation verloren
    buffer = malloc(2048);  // Ursprüngliche 1024 Bytes durchgesickert!
    strcpy(buffer, "Neue Daten");

    free(buffer);  // Gibt nur zweite Allokation frei
}

// Verwundbar: Referenz in Schleife verloren
void vulnerable_loop(int count) {
    char* data;

    for (int i = 0; i < count; i++) {
        // Verwundbar: Vorherige Allokation bei jeder Iteration verloren
        data = malloc(100);
        processData(data);
        // Kein free vor nächster Iteration
    }

    free(data);  // Gibt nur letzte Allokation frei
}
// Verwundbar: Referenz aufgrund von Exception verloren
void vulnerable_exception() {
    int* array = new int[1000];

    riskyOperation();  // Kann Exception werfen

    delete[] array;  // Nie erreicht wenn Exception geworfen wird
}

// Verwundbar: Objekt überschreibt seine eigene Ressource
class VulnerableBuffer {
    char* data;
    size_t size;

public:
    VulnerableBuffer(size_t s) : size(s) {
        data = new char[size];
    }

    void resize(size_t newSize) {
        // Verwundbar: Alte Daten ohne delete verloren
        data = new char[newSize];  // Speicherleck!
        size = newSize;
    }

    ~VulnerableBuffer() {
        delete[] data;
    }
};

Gefixter Code

// Gefixt: Vor Neuzuweisung freigeben
void fixed_overwrite() {
    char* buffer = malloc(1024);
    strcpy(buffer, "Initiale Daten");

    // Gefixt: Alte Allokation zuerst freigeben
    free(buffer);
    buffer = malloc(2048);
    strcpy(buffer, "Neue Daten");

    free(buffer);
}

// Gefixt: In Schleife freigeben
void fixed_loop(int count) {
    for (int i = 0; i < count; i++) {
        char* data = malloc(100);
        processData(data);
        free(data);  // Jede Allokation freigeben
    }
}
// Gefixt: RAII mit Smart Pointern verwenden
#include <memory>

void fixed_exception() {
    std::unique_ptr<int[]> array(new int[1000]);

    riskyOperation();  // Exception-sicher - Array automatisch freigegeben

    // Kein manuelles delete nötig
}

// Gefixt: Ordnungsgemäße Ressourcenverwaltung in Klasse
class FixedBuffer {
    std::unique_ptr<char[]> data;
    size_t size;

public:
    FixedBuffer(size_t s) : size(s), data(std::make_unique<char[]>(s)) {}

    void resize(size_t newSize) {
        // unique_ptr gibt alte Daten automatisch frei
        data = std::make_unique<char[]>(newSize);
        size = newSize;
    }

    // Kein Destruktor nötig - unique_ptr kümmert sich um Bereinigung
};
// Gefixt: Verbindung vor Neuzuweisung schließen
public class FixedConnection implements AutoCloseable {
    private Connection conn;

    public void connect(String url) throws SQLException {
        // Gefixt: Bestehende Verbindung zuerst schließen
        if (conn != null && !conn.isClosed()) {
            conn.close();
        }
        conn = DriverManager.getConnection(url);
    }

    @Override
    public void close() throws SQLException {
        if (conn != null) {
            conn.close();
        }
    }
}

// Gefixt: try-with-resources verwenden
public void fixedStream(String filename) throws IOException {
    try (FileInputStream fis = new FileInputStream(filename)) {
        if (!validateFile(fis)) {
            return;  // Stream automatisch geschlossen
        }
        // ... Datei verarbeiten ...
    }  // Stream automatisch geschlossen
}

Erkennungsmethoden

  • Speicherleck-Erkennung: Tools wie Valgrind, AddressSanitizer oder Dr. Memory können durchgesickerte Allokationen erkennen.
  • Statische Analyse: SAST-Tools können Codepfade identifizieren, in denen Pointer ohne Freigabe überschrieben werden.
  • Ressourcenüberwachung: Ressourcennutzung über Zeit verfolgen, um allmähliche Lecks zu identifizieren.

Referenzen

  1. MITRE Corporation. "CWE-771: Missing Reference to Active Allocated Resource." https://cwe.mitre.org/data/definitions/771.html
  2. CERT C Coding Standard. "MEM31-C. Free dynamically allocated memory when no longer needed."
  3. C++ Core Guidelines. "R.11: Avoid calling new and delete explicitly."