Unsigned-zu-Signed-Konvertierungsfehler
Beschreibung
Unsigned-zu-Signed-Konvertierungsfehler tritt auf, wenn ein größer vorzeichenloser (unsigned) Integer-Wert in einen vorzeichenbehafteten (signed) Integer-Typ konvertiert wird. Wenn der unsigned Wert den maximal darstellbaren positiven Wert des signed Typs überschreitet, ist das Ergebnis eine negative Zahl aufgrund der Interpretation des höchstwertigen Bits als Vorzeichenbit. Zum Beispiel produziert die Konvertierung von unsigned 0xFFFFFFFF zu einem signed 32-bit Integer den Wert -1. Dies ist besonders gefährlich, wenn das negative Ergebnis dann in Vergleichen, Array-Indizierung oder als Größenparameter verwendet wird, was potenziell Sicherheitsumgehungen oder Buffer-Underwrites ermöglicht.
Risiko
Unsigned-zu-Signed-Konvertierungsfehler sind besonders heimtückisch, weil große unsigned Werte stillschweigend zu negativen Werten werden können, die Sicherheitsprüfungen umgehen. Wenn ein größer Größenwert nach der Konvertierung negativ wird, kann er Prüfungen wie "if (size > MAX_SIZE)" passieren, während er später als riesiger Wert für Speicheroperationen neu interpretiert wird. Diese Schwachstellen sind perfekte Vorläufer für Buffer-Underwrite-Bedingungen, bei denen negative Indizes Angreifern den Zugriff auf Speicher vor dem beabsichtigten Puffer ermöglichen – ein Bereich, der oft Funktionszeiger, Rücksprungadressen oder andere kritische Kontrolldaten enthält, die über traditionelle Overflows nicht erreichbar sind.
Lösung
Vermeiden Sie das Mischen von signed und unsigned Integers in derselben Berechnung oder demselben Vergleich. Verwenden Sie konsistente Typen während verwandter Operationen. Wenn eine Konvertierung notwendig ist, validieren Sie, dass der unsigned Wert im Bereich des Ziel-signed-Typs liegt, bevor Sie konvertieren. Verwenden Sie explizite Bereichsprüfungen: für 32-bit stellen Sie sicher, dass value <= INT_MAX ist, bevor Sie zu signed casten. Aktivieren Sie Compiler-Warnungen für implizite Konvertierungen (-Wconversion). Wenden Sie statische Analyse an, um gefährliche Konvertierungsmuster zu identifizieren.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Sicherheitsumgehung Große unsigned Werte, die zu negativen signed Werten konvertiert werden, können Größen- oder Bereichsprüfungen umgehen. |
| Integrität | Bereich: Buffer-Underwrite Negative Werte, die als Indizes verwendet werden, greifen auf Speicher vor dem beabsichtigten Puffer zu und beschädigen kritische Daten. |
| Zugriffskontrolle | Bereich: Code-Ausführung Buffer-Underwrites können Rücksprungadressen und Funktionszeiger für Code-Ausführung beschädigen. |
Beispielcode + Lösungscode
Anfälliger Code
#include <stdlib.h>
#include <string.h>
// ANFÄLLIG: Großer unsigned wird negativer signed
void process_packet(unsigned int packet_size) {
int size = packet_size; // Große Werte werden negativ
// Größenprüfung passiert für negative Werte!
if (size > MAX_BUFFER) {
return; // Negativ -1 ist nicht > MAX_BUFFER
}
char buffer[1024];
// memcpy interpretiert negative Größe als riesigen unsigned
memcpy(buffer, data, size); // Overflow!
}
// ANFÄLLIG: Buffer-Underwrite über negativen Index
void write_at_offset(char *buffer, unsigned int offset) {
int index = offset; // 0xFFFFFFFF wird zu -1
// Negativer Index greift vor Puffer zu
buffer[index] = 'X'; // Underwrite!
}
// ANFÄLLIG: Vergleichsumgehung
#define MAX_ITEMS 1000
unsigned int items[MAX_ITEMS];
void add_item(unsigned int index, unsigned int value) {
int idx = index;
// Negativer idx passiert diese Prüfung!
if (idx < MAX_ITEMS) {
items[idx] = value; // Underwrite wenn idx negativ
}
}
// ANFÄLLIG: Iteration mit konvertiertem Zähler
void process_items(unsigned int count) {
int i = count;
// Wenn count > INT_MAX, ist i negativ - Schleife wird nicht ausgeführt
// Oder schlimmer: wickelt falsch um
for (int j = 0; j < i; j++) {
process_item(j);
}
}
Korrigierter Code
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
// SICHER: Bereich vor Konvertierung validieren
int process_packet_safe(unsigned int packet_size) {
// Prüfen, dass Wert in signed Typ passt
if (packet_size > INT_MAX) {
return -1; // Zu große Werte ablehnen
}
int size = (int)packet_size; // Jetzt sicher
if (size > MAX_BUFFER || size <= 0) {
return -1;
}
char buffer[MAX_BUFFER];
memcpy(buffer, data, (size_t)size);
return 0;
}
// SICHER: Durchgehend unsigned verwenden
void write_at_offset_safe(char *buffer, size_t buffer_size,
size_t offset) {
// Als unsigned behalten - keine Konvertierung
if (offset >= buffer_size) {
return; // Grenzenprüfung
}
buffer[offset] = 'X';
}
// SICHER: Korrekter unsigned Vergleich
#define MAX_ITEMS 1000
unsigned int items[MAX_ITEMS];
void add_item_safe(size_t index, unsigned int value) {
// Unsigned Vergleich verwenden
if (index >= MAX_ITEMS) {
return;
}
items[index] = value;
}
// SICHER: Konsistente unsigned Typen verwenden
void process_items_safe(size_t count) {
// Durchgehend als unsigned behalten
if (count > MAX_REASONABLE_COUNT) {
return;
}
for (size_t i = 0; i < count; i++) {
process_item(i);
}
}
// Alternative: Explizite Bereichsprüfung vor Konvertierung
bool safe_to_signed(unsigned int value, int *result) {
if (value > (unsigned int)INT_MAX) {
return false;
}
*result = (int)value;
return true;
}
Ausgenutzt in der Praxis
SoftMaker Office TextMaker (SoftMaker, 2021)
Mehrere Schwachstellen in SoftMaker Office TextMaker mit Unsigned-zu-Signed-Konvertierungsfehlern, die Code-Ausführung durch gestaltete Dokumente ermöglichen könnten.
Hyperledger Besu (Hyperledger, 2022)
Denial-of-Service-Schwachstelle im Hyperledger Besu Blockchain-Client, verursacht durch Unsigned-zu-Signed-Konvertierungsfehler bei der Transaktionsverarbeitung.
Historische BSD/UNIX-Schwachstellen (Verschiedene, 1990er-2000er)
Mehrere klassische UNIX-Schwachstellen stammten von Unsigned-zu-Signed-Konvertierungsfehlern in Systemaufrufen und Bibliotheksfunktionen, besonders in Socket- und Dateibehandlungscode.
Tools zum Testen/Ausnutzen
-
UBSan — erkennt implizite Konvertierungen, die den Wert ändern.
-
Coverity — statische Analyse für Typkonvertierungsprobleme.
-
Clang Static Analyzer — erkennt verdächtige Integer-Konvertierungen.
CVE-Beispiele
-
CVE-2022-39399 — Hyperledger Besu Unsigned-zu-Signed-Konvertierung.
-
CVE-2021-40411 — SoftMaker TextMaker Konvertierungsfehler.
-
CVE-2006-3747 — Apache mod_rewrite Off-by-one mit Konvertierung.
Referenzen
-
MITRE. "CWE-196: Unsigned to Signed Conversion Error." https://cwe.mitre.org/data/definitions/196.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