Signed-zu-Unsigned-Konvertierungsfehler
Beschreibung
Signed-zu-Unsigned-Konvertierungsfehler tritt auf, wenn ein vorzeichenbehafteter (signed) Integer-Wert in einen vorzeichenlosen (unsigned) Integer-Typ konvertiert wird. Wenn der signed Wert negativ ist, produziert die Konvertierung einen sehr großen positiven unsigned Wert (typischerweise nahe dem Maximalwert für diesen unsigned Typ). Zum Beispiel produziert die Konvertierung von -1 (signed int) zu einem unsigned 32-bit Integer den Wert 4294967295. Dies ist besonders gefährlich, wenn der konvertierte Wert für Speicherallokationsgrößen, Pufferlängen oder Schleifenzähler verwendet wird, da der unerwartet große Wert Buffer-Overflows oder Ressourcenerschöpfung verursachen kann.
Risiko
Signed-zu-Unsigned-Konvertierungsfehler sind extrem gefährlich, weil sie kleine negative Werte (oft Fehlercodes wie -1) in enorme positive Werte transformieren können. Funktionen, die bei Fehlern -1 zurückgeben, sind in C/C++-APIs üblich. Wenn diese Fehlerrückgabewerte nicht überprüft werden, bevor sie als Größen in malloc(), memcpy() oder Array-Zugriffen verwendet werden, ist das Ergebnis ein katastrophaler Buffer-Overflow oder Speichererschöpfung. Angreifer erstellen spezifisch Eingaben, um Fehlerbedingungen auszulösen, die negative Werte produzieren, wissend, dass die Konvertierung ausnutzbare Overflow-Bedingungen erzeugen wird.
Lösung
Prüfen Sie immer Rückgabewerte von Funktionen, die möglicherweise negative Fehlercodes zurückgeben, bevor Sie sie als unsigned Größen verwenden. Verwenden Sie size_t oder unsigned Typen für Variablen, die niemals negativ sein sollten. Fügen Sie explizite Bereichsvalidierung vor Typkonvertierungen hinzu. Aktivieren Sie Compiler-Warnungen für implizite signed/unsigned-Konvertierungen (-Wsign-conversion in GCC/Clang). Erwägen Sie die Verwendung separater Fehlerbehandlungsmechanismen anstelle von Sentinel-Werten. Wenden Sie statische Analyse an, um gefährliche Konvertierungsmuster zu identifizieren.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Speicherbeschädigung Negative Werte, die zu großen unsigned Werten konvertiert werden, verursachen massive Buffer-Overflows, wenn sie als Größen verwendet werden. |
| Verfügbarkeit | Bereich: Ressourcenerschöpfung Große konvertierte Werte können Speichererschöpfung durch enorme Allokationen verursachen. |
| Zugriffskontrolle | Bereich: Code-Ausführung Buffer-Overflows, die aus Konvertierungsfehlern resultieren, ermöglichen beliebige Code-Ausführung. |
Beispielcode + Lösungscode
Anfälliger Code
#include <stdlib.h>
#include <string.h>
// ANFÄLLIG: Funktion gibt -1 bei Fehler zurück
int get_data_size(int fd) {
int size = read_header(fd);
if (size < 0) return -1; // Fehlerrückgabe
return size;
}
void process_file(int fd) {
int size = get_data_size(fd);
// Fehlende Fehlerprüfung!
// size (-1) zu size_t konvertiert wird riesig positiv
char *buffer = malloc(size); // Allokiert 4GB oder schlägt fehl
read(fd, buffer, size); // Overflow!
}
// ANFÄLLIG: memcpy mit signed Größe
void copy_data(char *dest, char *src, int count) {
// Wenn count von vorgelagertem Fehler negativ ist...
memcpy(dest, src, count); // count zu size_t konvertiert, riesiger Wert
}
// ANFÄLLIG: Array-Index mit Fehlerwert
#define ERROR_VALUE -1
int data_array[1000];
void store_result(int index, int value) {
// index könnte ERROR_VALUE von fehlgeschlagener Operation sein
data_array[index] = value; // Underflow: greift vor Array zu
}
Korrigierter Code
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
// SICHER: Fehlerrückgabe vor Verwendung prüfen
int get_data_size(int fd) {
int size = read_header(fd);
if (size < 0) return -1;
return size;
}
bool process_file_safe(int fd) {
int size = get_data_size(fd);
// Auf Fehlerrückgabe prüfen!
if (size < 0) {
return false; // Fehler behandeln
}
// Zusätzliche Plausibilitätsprüfung
if (size > MAX_BUFFER_SIZE) {
return false;
}
// Jetzt sicher als Größe verwendbar
char *buffer = malloc((size_t)size);
if (!buffer) return false;
ssize_t bytes_read = read(fd, buffer, (size_t)size);
free(buffer);
return (bytes_read == size);
}
// SICHER: Signed Wert vor Konvertierung validieren
bool copy_data_safe(char *dest, size_t dest_size,
const char *src, int count) {
// Negativen count ablehnen
if (count < 0) {
return false;
}
// Gegen Zielgröße prüfen
if ((size_t)count > dest_size) {
return false;
}
memcpy(dest, src, (size_t)count);
return true;
}
// SICHER: Separate Fehlerbehandlung verwenden
typedef struct {
bool success;
size_t value;
} SizeResult;
SizeResult get_size_safe(int fd) {
SizeResult result = {false, 0};
int size = read_header(fd);
if (size >= 0) {
result.success = true;
result.value = (size_t)size;
}
return result;
}
Ausgenutzt in der Praxis
Okio GzipSource Denial-of-Service (Okio, 2023)
CVE-2023-3635 in der Okio-Bibliothek, bei der GzipSource Ausnahmen beim Parsen von fehlerhaften gzip-Puffern nicht ordnungsgemäß behandelt, was zu Signed-zu-Unsigned-Konvertierungsfehlern führt, die Denial-of-Service verursachen.
Juniper Layer 2 Control Protocol (Juniper, 2025)
CVE-2025-30646 ist ein Signed-zu-Unsigned-Konvertierungsfehler in Junipers Layer 2 Control Protocol (L2CP)-Implementierung, der Netzwerkinfrastruktur betrifft.
Mehrere Systembibliotheken (Verschiedene, Historisch)
Viele historische Schwachstellen in libc-Implementierungen, OpenSSL und anderen Systembibliotheken stammten von ungeprüften Konvertierungen von Fehlerrückgabewerten zu unsigned Größen.
Tools zum Testen/Ausnutzen
-
UBSan — erkennt implizite Typkonvertierungen, die den Wert ändern.
-
Coverity — statische Analyse zur Identifikation gefährlicher signed/unsigned-Konvertierungen.
-
PVS-Studio — erkennt verdächtige Typkonvertierungen.
CVE-Beispiele
-
CVE-2023-3635 — Okio GzipSource Signed-zu-Unsigned-Konvertierung DoS.
-
CVE-2025-30646 — Juniper L2CP Signed-zu-Unsigned-Konvertierungsfehler.
-
CVE-2021-21220 — Chrome V8 Typverwechslung mit Integer-Konvertierung.
Referenzen
-
MITRE. "CWE-195: Signed to Unsigned Conversion Error." https://cwe.mitre.org/data/definitions/195.html
-
CERT. "INT31-C. Ensure that integer conversions do not result in löst or misinterpreted data." https://wiki.sei.cmu.edu/confluence/display/c/INT31-C