Speicherallokation mit übermäßigem Größenwert
Beschreibung
Speicherallokation mit übermäßigem Größenwert ist eine Ressourcenverwaltungsschwachstelle, bei der Software Speicher basierend auf einem nicht vertrauenswürdigen oder ungeprüften Größenwert alloziert, ohne sicherzustellen, dass die Größe innerhalb akzeptabler Grenzen liegt. Wenn Anwendungen Größenparameter aus externen Quellen (Benutzereingabe, Netzwerkdaten, Dateiinhalt) akzeptieren und sie direkt in Allokationsfunktionen wie malloc(), calloc() oder new verwenden, können Angreifer extrem große Werte angeben. Dies kann sofortige Allokationsfehler, Out-of-Memory-Bedingungen oder systemweite Ressourcenerschöpfung verursachen, die zu Denial of Service führt.
Risiko
Übermäßige Speicherallokation hat mehrere Angriffsvektoren. Direkte Angriffe spezifizieren riesige Allokationsgrößen, um die Anwendung mit Out-of-Memory-Fehlern abstürzen zu lassen oder Systemspeicher zu erschöpfen, der andere Prozesse betrifft. Integer-Overflow-Angriffe verursachen, dass Größenberechnungen auf kleine Werte umbrechen, was zu unterdimensionierten Puffern führt, die zu Heap Overflows führen, wenn sie mit tatsächlichen Daten gefüllt werden. Größe Allokationen können auch Leistungsverschlechterung auslösen, wenn das System Speicher auf die Festplatte auslagert.
Lösung
Validieren Sie immer Allokations-Größenparameter vor der Verwendung. Definieren und erzwingen Sie maximal akzeptable Größen basierend auf Anwendungsanforderungen. Prüfen Sie auf Integer Overflow in Größenberechnungen vor der Allokation. Verwenden Sie sichere Integer-Arithmetik-Funktionen oder manuelle Overflow-Prüfungen. Behandeln Sie Allokationsfehler elegant - nehmen Sie nicht an, dass malloc immer erfolgreich ist. Verwenden Sie Ressourcenlimits (ulimit, setrlimit), um Schäden durch unkontrollierte Allokationen zu begrenzen. Erwägen Sie die Verwendung von Speicherpools mit festen Maximalgrößen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Ressourcenverbrauch (Speicher) - Übermäßige Allokationen erschöpfen verfügbaren Speicher und bringen Anwendung oder System zum Absturz. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Absturz - Out-of-Memory-Bedingungen bringen typischerweise die Anwendung zum Absturz. |
| Integrität | Bereich: Integrität Speicher ändern - Integer Overflow in Größenberechnung kann zu unterdimensionierter Allokation und anschließendem Buffer Overflow führen. |
Beispielcode
Verwundbarer Code
// Verwundbar: Ungeprüfter Allokationsgrößenwert aus Benutzereingabe
#include <stdlib.h>
#include <string.h>
void vulnerable_alloc_user_size(unsigned int size) {
// Verwundbar: Keine Validierung von size
char* buffer = (char*)malloc(size);
if (buffer == NULL) {
// Fehler behandeln, aber Schäden ist möglicherweise schon angerichtet
return;
}
// Puffer verwenden...
free(buffer);
}
// Angriff: size = 4294967295 (0xFFFFFFFF) übergeben um 4GB zu allozieren
// Verwundbar: Integer Overflow in Größenberechnung
void vulnerable_alloc_array(unsigned int count) {
// Verwundbar: Multiplikation kann überlaufen
unsigned int totalBytes = count * sizeof(int);
// Wenn count = 1073741824 (0x40000000), umbrechen totalBytes zu 0
int* buffer = (int*)malloc(totalBytes);
if (buffer == NULL) return;
// Schreibt weit über tatsächliche (kleine) Allokation hinaus
for (unsigned int i = 0; i < count; i++) {
buffer[i] = 0; // Heap Overflow!
}
free(buffer);
}
// Verwundbar: Java HashMap mit nicht vertrauenswürdiger Kapazität
import java.util.HashMap;
public class VulnerableHashMap {
public HashMap<String, String> createFromInput(int capacity) {
// Verwundbar: Keine Validierung von capacity
// Riesige Kapazität verursacht OutOfMemoryError
HashMap<String, String> map = new HashMap<>(capacity);
return map;
}
}
// Angriff: capacity = Integer.MAX_VALUE übergeben
Gefixter Code
// Gefixt: Allokationsgröße validieren
#include <stdlib.h>
#include <stdint.h>
#define MAX_ALLOC_SIZE (64 * 1024 * 1024) // 64 MB Maximum
void* fixed_alloc_user_size(size_t size) {
// Gefixt: Größe gegen Maximum validieren
if (size == 0 || size > MAX_ALLOC_SIZE) {
return NULL; // Ungültige Größen ablehnen
}
void* buffer = malloc(size);
return buffer; // Kann bei Allokationsfehler weiterhin NULL sein
}
// Gefixt: Auf Integer Overflow prüfen
#include <stdint.h>
void* fixed_alloc_array(size_t count, size_t element_size) {
// Gefixt: Auf Overflow vor Multiplikation prüfen
if (count == 0 || element_size == 0) {
return NULL;
}
if (count > SIZE_MAX / element_size) {
// Multiplikation würde überlaufen
return NULL;
}
size_t total_bytes = count * element_size;
// Zusätzliche Plausibilitätsprüfung
if (total_bytes > MAX_ALLOC_SIZE) {
return NULL;
}
return malloc(total_bytes);
}
// Alternative: calloc verwenden, das eingebautes Overflow-Checking hat
void* fixed_alloc_array_v2(size_t count, size_t element_size) {
if (count > MAX_ALLOC_SIZE / element_size) {
return NULL;
}
// calloc prüft intern auf Overflow
return calloc(count, element_size);
}
// Gefixt: Kapazität in Java validieren
import java.util.HashMap;
public class FixedHashMap {
private static final int MAX_CAPACITY = 1000000; // 1 Million Einträge max
public HashMap<String, String> createFromInput(int capacity)
throws IllegalArgumentException {
// Gefixt: Kapazität validieren
if (capacity < 0) {
throw new IllegalArgumentException("Kapazität darf nicht negativ sein");
}
if (capacity > MAX_CAPACITY) {
throw new IllegalArgumentException("Kapazität überschreitet Maximum: " + MAX_CAPACITY);
}
return new HashMap<>(capacity);
}
}
// Gefixt: Netzwerkdaten vor Allokation validieren
#include <arpa/inet.h>
#define MAX_DATA_LENGTH (1024 * 1024) // 1 MB max
#define MAX_ITEM_COUNT 10000
typedef struct {
uint32_t data_length;
uint32_t item_count;
} PacketHeader;
int fixed_process_packet(PacketHeader* header) {
// Gefixt: Von Network-Byte-Order konvertieren
uint32_t data_length = ntohl(header->data_length);
uint32_t item_count = ntohl(header->item_count);
// Gefixt: Vor Allokation validieren
if (data_length > MAX_DATA_LENGTH) {
return -1; // Übergroße Daten ablehnen
}
if (item_count > MAX_ITEM_COUNT) {
return -1; // Zu viele Elemente ablehnen
}
// Gefixt: Auf Overflow in Multiplikation prüfen
if (item_count > SIZE_MAX / sizeof(Item)) {
return -1;
}
char* data = malloc(data_length);
if (data == NULL && data_length > 0) {
return -1;
}
Item* items = malloc(item_count * sizeof(Item));
if (items == NULL && item_count > 0) {
free(data);
return -1;
}
// Daten verarbeiten...
free(items);
free(data);
return 0;
}
CVE-Beispiele
- CVE-2019-19911: Speicherallokation mit übermäßiger Größe bei Bildverarbeitung.
- CVE-2010-3701: Übermäßige Speicherallokation in Virtualisierungssoftware.
- CVE-2008-1708: Integer Overflow führt zu unterdimensionierter Allokation.
- CVE-2008-0977: Ungeprüfter Allokationsgrößenwert aus Netzwerkdaten.
Referenzen
- MITRE Corporation. "CWE-789: Memory Allocation with Excessive Size Value." https://cwe.mitre.org/data/definitions/789.html
- CERT C Coding Standard. "MEM35-C. Allocate sufficient memory for an object."
- CERT C Coding Standard. "INT30-C. Ensure that unsigned integer operations do not wrap."