Unerwartete Vorzeichenerweiterung
Beschreibung
Unerwartete Vorzeichenerweiterung tritt auf, wenn ein vorzeichenbehafteter (signed) Integer-Wert in einen größeren Integer-Typ konvertiert wird und das Vorzeichenbit erweitert wird, um die zusätzlichen Bits zu füllen. Wenn ein negativer signed Wert (mit gesetztem höchstem Bit) auf einen größeren Typ erweitert wird, wird er zu einer sehr großen positiven Zahl, wenn er anschließend als unsigned interpretiert wird, oder bleibt eine große negative Zahl. Dies kann unerwartete Werte produzieren, die Sicherheitsprüfungen umgehen, Buffer Overflows verursachen oder zu anderen Speicherbeschädigungsproblemen führen, wenn der erweiterte Wert für Größen, Indizes oder Schleifenzähler verwendet wird.
Risiko
Vorzeichenerweiterung-Schwachstellen sind besonders gefährlich, weil sie stillschweigend kleine negative Werte in enorme positive Werte transformieren können. Wenn ein negativer char (-1) zu einem int vorzeichenerweitert und dann zu size_t gecastet wird, wird er zu einem Wert nahe SIZE_MAX. Wenn dieser Wert für Pufferallokation oder als Schleifengrenze verwendet wird, resultieren katastrophale Buffer-Overflows. Diese Schwachstellen sind subtil und leicht während der Code-Review zu übersehen. Reale Exploits haben demonstriert, dass Vorzeichenerweiterungs-Bugs in Dokumentenparsern, Protokoll-Handlern und Medienbibliotheken beliebige Code-Ausführung ermöglichen können.
Lösung
Vermeiden Sie die Verwendung von signed Integers für Werte, die niemals negativ sein sollten, wie Größen, Längen und Indizes. Prüfen Sie bei der Konvertierung zwischen Integer-Typen unterschiedlicher Größen explizit Wertebereiche vor der Konvertierung. Verwenden Sie explizite Casts, die die Absicht klar machen. Validieren Sie, dass signed Werte nicht-negativ sind, bevor Sie sie in Größenberechnungen verwenden. Seien Sie besonders vorsichtig, wenn char-Werte (die standardmäßig signed sein können) für Array-Indizierung verwendet werden. Verwenden Sie unsigned char oder casten Sie explizit zu unsigned bei der Verarbeitung von Byte-Daten. Aktivieren Sie Compiler-Warnungen für implizite Konvertierungen zwischen signed und unsigned Typen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Speicherbeschädigung Vorzeichenerweiterte Werte, die als Größen oder Indizes verwendet werden, verursachen massive Buffer-Overflows. |
| Zugriffskontrolle | Bereich: Sicherheitsumgehung Vorzeichenerweiterung kann dazu führen, dass negative Werte Längenprüfungen passieren, wenn sie als große positive unsigned Werte interpretiert werden. |
| Verfügbarkeit | Bereich: Denial-of-Service Massive Speicherallokationen durch vorzeichenerweiterte Größen verursachen Ressourcenerschöpfung. |
Beispielcode + Lösungscode
Anfälliger Code
#include <stdlib.h>
#include <string.h>
// ANFÄLLIG: Vorzeichenerweiterung von char zu int zu size_t
void process_byte(char len_byte) {
// Wenn len_byte -1 (0xFF) ist, macht Vorzeichenerweiterung es
// zu 0xFFFFFFFF (riesig positiv) bei Cast zu size_t
size_t length = len_byte;
char *buffer = malloc(length); // Enorme Allokation
// ...
}
// ANFÄLLIG: Vorzeichenerweiterung umgeht Längenprüfung
int copy_data(char *dest, char *src, short src_len) {
// src_len könnte negativ sein
if (src_len > MAX_SIZE) { // Negativ passiert diese Prüfung!
return -1;
}
// Zu size_t vorzeichenerweitert, wird riesig positiv
memcpy(dest, src, src_len); // Massiver Overflow
return 0;
}
// ANFÄLLIG: Signed char als Array-Index
char lookup_table[256];
char get_lookup(char index) {
// Wenn index negativ ist (z.B. -50), liest dies vor dem Array
// Bei Konvertierung zu int für Indizierung wird negativer Offset
return lookup_table[index]; // Under-Read!
}
// ANFÄLLIG: Pascal-Style String-Länge
void copy_pascal_string(char *dest, char *src) {
// Erstes Byte ist Länge (signed char)
char len = *src; // Könnte negativ sein
// Vorzeichenerweiterung: len = -1 wird zu 0xFFFFFFFF
memcpy(dest, src + 1, len); // Massiver Overflow
}
Korrigierter Code
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// SICHER: Unsigned Typ verwenden, Bereich validieren
void process_byte_safe(unsigned char len_byte) {
// unsigned char: 0-255, keine Vorzeichenerweiterung
size_t length = len_byte;
if (length == 0 || length > MAX_LENGTH) {
return;
}
char *buffer = malloc(length);
// ...
}
// SICHER: Signed Wert vor Verwendung validieren
int copy_data_safe(char *dest, size_t dest_size,
const char *src, int16_t src_len) {
// Auf negativ UND Obergrenze prüfen
if (src_len < 0 || (size_t)src_len > MAX_SIZE) {
return -1;
}
// Nach Validierung ist Cast sicher
size_t copy_len = (size_t)src_len;
if (copy_len > dest_size) {
return -1;
}
memcpy(dest, src, copy_len);
return 0;
}
// SICHER: Unsigned char für Byte-Indizierung verwenden
char lookup_table[256];
char get_lookup_safe(unsigned char index) {
// unsigned char: immer 0-255, gültiger Index
return lookup_table[index];
}
// Alternative: explizites Maskieren
char get_lookup_masked(char index) {
// Maskieren um positiven Index sicherzustellen
unsigned char safe_index = (unsigned char)index;
return lookup_table[safe_index];
}
// SICHER: Pascal-String-Länge validieren
int copy_pascal_string_safe(char *dest, size_t dest_size,
const unsigned char *src, size_t src_size) {
if (src_size == 0) return -1;
// Länge als unsigned lesen
unsigned char len = src[0];
// Länge gegen Quelle und Ziel validieren
if (len > src_size - 1 || len > dest_size) {
return -1;
}
memcpy(dest, src + 1, len);
dest[len] = '\0';
return 0;
}
Ausgenutzt in der Praxis
SoftMaker Office TextMaker (SoftMaker, 2021)
CVE-2021-40411 ist eine Vorzeichenerweiterungs-Schwachstelle in SoftMaker Office 2021's TextMaker-Dokumentenparsing. Ein speziell gestaltetes Dokument veranlasst den Parser, eine Schleifenterminierungslänge zu vorzeichenerweitern, was dazu führt, dass der Schleifenindex zum Schreiben außerhalb der Heap-Puffergrenzen verwendet wird.
CODESYS Industriesteuerung (CODESYS, Mehrfach)
Mehrere CODESYS-Produkte enthielten Vorzeichenerweiterungs-Schwachstellen, bei denen Remote-Angreifer Anfragen erstellen könnten, die unerwartete Vorzeichenerweiterung verursachten, was zu Denial-of-Service oder Speicherüberschreibung in industriellen Steuerungssystemen führte.
Historisch: BSD Netzwerk-Stack (BSD, 1990er)
Klassische Vorzeichenerweiterungs-Schwachstellen in BSD-Netzwerk-Stack-Implementierungen betrafen TCP/IP-Verarbeitung und Socket-Operationen und demonstrierten die lange Geschichte dieser Schwachstellenklasse.
Tools zum Testen/Ausnutzen
-
UBSan — erkennt implizite Konvertierungen, die den Wert ändern.
-
Coverity — statische Analyse zur Identifikation von Vorzeichenerweiterungsproblemen.
-
PVS-Studio — erkennt verdächtige Typkonvertierungen und Vorzeichenerweiterung.
CVE-Beispiele
-
CVE-2021-40411 — SoftMaker Office Vorzeichenerweiterung führt zu Heap-Overflow.
-
CVE-2022-33260 — CODESYS Vorzeichenerweiterung verursacht Speicherbeschädigung.
-
CVE-2017-7308 — Linux-Kernel Packet-Socket Vorzeichenerweiterung.
Referenzen
-
MITRE. "CWE-194: Unexpected Sign Extension." https://cwe.mitre.org/data/definitions/194.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