Aufrufbares Steuerelement mit variadischen Parametern
Beschreibung
Aufrufbares Steuerelement mit variadischen Parametern tritt auf, wenn eine Funktion, Methode oder ein aufrufbares Steuerelement eine Signatur hat, die eine variable Anzahl von Parametern oder Argumenten (variadische Parameter) unterstützt. Während variadische Funktionen Flexibilität bieten, erschweren sie statische Analyse und manuelle Code-Reviews, da die tatsächlich übergebenen Parameter an jeder Aufrufstelle variieren können. Dies macht es schwierig, korrekte Verwendung zu verifizieren, Datenflüsse zu verfolgen und Sicherheitsschwachstellen wie Format-String-Fehler oder Typverwirrung zu identifizieren.
Risiko
Obwohl hauptsächlich ein Code-Komplexitätsproblem, haben variadische Parameter Sicherheitsimplikationen. Format-String-Schwachstellen (CWE-134) treten häufig in variadischen Funktionen wie printf auf, wo Benutzereingaben Format-Spezifizierer angeben können. Typsicherheit ist reduziert, da variadische Funktionen Parametertypen zur Kompilierzeit nicht erzwingen können. Statische Analysetools haben Schwierigkeiten, den Datenfluss durch variadische Funktionen zu verfolgen. Code-Reviewer können Sicherheitsprobleme übersehen, weil die tatsächlichen Parameter pro Aufrufstelle variieren. Variadische Funktionen in C/C++ können zu undefiniertem Verhalten führen, wenn Argumente nicht den erwarteten Typen entsprechen.
Lösung
Minimieren Sie die Verwendung variadischer Funktionen, insbesondere in sicherheitskritischem Code. Verwenden Sie typsichere Alternativen, wo verfügbar (z.B. variadische Templates in C++ oder überladene Methoden). Wenn variadische Funktionen notwendig sind, validieren Sie Argumentanzahl und -typen zur Laufzeit. Verwenden Sie statische Analysetools, die speziell variadische Funktionsaufrufe prüfen. Für Logging und Formatierung verwenden Sie typsichere Logging-Frameworks. Übergeben Sie niemals Benutzereingaben als Format-Strings an variadische Funktionen. Erwägen Sie Builder-Muster oder Options-Objekte als Alternativen zu langen Parameterlisten.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Andere | Bereich: Ändere Reduzierte Zuverlässigkeit - Variadische Funktionen erschweren die Verifizierung korrekter Verwendung und führen möglicherweise zu Laufzeitfehlern. |
| Andere | Bereich: Ändere Qualitätsverschlechterung - Die Flexibilität variadischer Parameter erschwert statische Analyse und Code-Review. |
| Vertraulichkeit | Bereich: Vertraulichkeit, Integrität Sicherheitsschwachstellen - Missbrauch variadischer Funktionen kann zu Format-String-Angriffen oder Typverwirrung führen. |
Beispielcode
Anfälliger Code
// Anfällig: Klassische variadische Funktion mit Sicherheitsproblemen
#include <stdio.h>
#include <stdarg.h>
// Anfällig: Benutzerdefiniertes Logging mit variadischen Parametern
void vulnerable_log(const char *format, ...) {
va_list args;
va_start(args, format);
// Anfällig: Keine Validierung der Format/Args-Korrespondenz
// Wenn Format mehr Spezifizierer als Args hat, undefiniertes Verhalten
vprintf(format, args);
va_end(args);
}
// Anfällige Verwendung
void process_user_input(const char *user_input) {
// KRITISCHE SCHWACHSTELLE: Benutzereingabe als Format-String!
vulnerable_log(user_input); // Format-String-Angriffsvektor
// Angreifereingabe: "%s%s%s%s%s" -> Absturz
// Angreifereingabe: "%x%x%x%x" -> leckt Stack-Daten
// Angreifereingabe: "%n" -> schreibt in Speicher!
}
// Anfällig: Variadische Funktion ohne Typsicherheit
void vulnerable_sum(int count, ...) {
va_list args;
va_start(args, count);
int sum = 0;
for (int i = 0; i < count; i++) {
// Nimmt an, alle Args sind int - keine Typprüfung!
sum += va_arg(args, int);
}
va_end(args);
printf("Summe: %d\n", sum);
}
// Aufruf mit falschen Typen verursacht undefiniertes Verhalten
void bad_usage() {
vulnerable_sum(3, 1, 2.5, "drei"); // Typen stimmen nicht überein!
}
# Anfällig: Python variadische Funktionen mit Sicherheitsproblemen
def vulnerable_query(*args, **kwargs):
"""Variadische Funktion, die SQL-Abfragen erstellt"""
table = args[0] if args else kwargs.get('table')
columns = args[1:] if len(args) > 1 else kwargs.get('columns', ['*'])
# Anfällig: Schwer zu verfolgen, was übergeben wird
# Jede Aufrufstelle kann andere Argumente übergeben
query = f"SELECT {', '.join(columns)} FROM {table}"
# Wenn ein Arg SQL-Injection-Payload enthält, wird es ausgeführt
return execute_query(query)
# Unterschiedliche Aufrufmuster erschweren Sicherheits-Review
def usage_examples():
vulnerable_query("users", "id", "name", "email") # Positional
vulnerable_query(table="users", columns=["id", "name"]) # Keyword
vulnerable_query("users") # Nur Tabelle
vulnerable_query(user_input, *user_columns) # Dynamisch - gefährlich!
Korrigierter Code
// Korrigiert: Typsichere Alternativen zu variadischen Funktionen
// Korrigiert: Strukturiertes Logging anstelle von variadischem printf
typedef struct {
const char *message;
const char *level;
const char *source;
int line;
} LogEntry;
void fixed_log(const LogEntry *entry) {
// Typsicher: alle Felder haben bekannte Typen
printf("[%s] %s:%d - %s\n",
entry->level,
entry->source,
entry->line,
entry->message);
}
// Korrigiert: Array-Parameter anstelle von variadisch
void fixed_sum(const int *values, size_t count) {
int sum = 0;
for (size_t i = 0; i < count; i++) {
sum += values[i]; // Typsicher: alle Elemente sind int
}
printf("Summe: %d\n", sum);
}
// Korrigierte Verwendung: Format-String ist nie benutzergesteuert
void fixed_process_user_input(const char *user_input) {
// Korrigiert: Benutzereingabe ist Daten, nicht Format
safe_log("Benutzereingabe empfangen: %s", user_input);
}
// Korrigiert: C++ variadische Templates für Typsicherheit
#include <iostream>
#include <sstream>
// Korrigiert: Variadisches Template mit Typsicherheit
template<typename T>
void safe_log_impl(std::ostringstream& ss, T value) {
ss << value;
}
template<typename T, typename... Args>
void safe_log_impl(std::ostringstream& ss, T first, Args... rest) {
ss << first << " ";
safe_log_impl(ss, rest...);
}
template<typename... Args>
void safe_log(Args... args) {
// Typsicher: jeder Argumenttyp ist zur Kompilierzeit bekannt
std::ostringstream ss;
safe_log_impl(ss, args...);
std::cout << ss.str() << std::endl;
}
// Korrigiert: Typsichere Summe mit Fold-Expressions (C++17)
template<typename... Args>
auto safe_sum(Args... args) {
// Kompilierzeit-Typprüfung
return (args + ...);
}
// Verwendung - Compiler fängt Typfehler ab
void fixed_usage() {
safe_log("Wert:", 42, "Status:", "OK"); // Typsicher
auto sum = safe_sum(1, 2, 3, 4, 5); // Gleicher Typ erzwungen
// safe_sum(1, "zwei", 3); // Kompilierfehler!
}
# Korrigiert: Typsichere Alternativen zu variadischen Funktionen
from typing import List, Dict, Any, Optional
from dataclasses import dataclass
# Korrigiert: Explizite Parametertypen anstelle von *args
@dataclass
class QueryParams:
table: str
columns: List[str]
conditions: Optional[Dict[str, Any]] = None
def fixed_query(params: QueryParams) -> str:
"""Typsicherer Query-Builder"""
# Klare, typisierte Parameter
# Einfach zu validieren und zu prüfen
# Eingaben validieren
if not params.table.isidentifier():
raise ValueError("Ungültiger Tabellenname")
safe_columns = [c for c in params.columns if c.isidentifier()]
query = f"SELECT {', '.join(safe_columns)} FROM {params.table}"
return query
# Korrigiert: Builder-Muster für komplexe Konfigurationen
class QueryBuilder:
def __init__(self, table: str):
self._table = table
self._columns: List[str] = []
self._conditions: List[str] = []
def select(self, *columns: str) -> 'QueryBuilder':
# Varargs aber jeder Aufruf ist explizit und prüfbar
self._columns.extend(columns)
return self
def where(self, condition: str) -> 'QueryBuilder':
self._conditions.append(condition)
return self
def build(self) -> str:
# Alle Komponenten sind nun validiert
return f"SELECT {', '.join(self._columns)} FROM {self._table}"
# Verwendung ist klar und auditierbar
query = (QueryBuilder("users")
.select("id", "name", "email")
.where("active = true")
.build())
CVE-Beispiele
Diese CWE ist für direkte CVE-Zuordnung als VERBOTEN markiert. Variadische Funktionen sind jedoch eng mit Format-String-Schwachstellen (CWE-134) verbunden, die zahlreiche CVEs haben, darunter CVE-2000-0573 und viele ändere.
Verwandte CWEs
- CWE-1120: Excessive Code Complexity (Eltern)
- CWE-1226: Complexity Issues (Kategoriemitglied)
- CWE-134: Use of Externally-Controlled Format String (verwandtes Sicherheitsproblem)
Referenzen
-
MITRE Corporation. "CWE-1056: Invokable Control Element with Variadic Parameters." https://cwe.mitre.org/data/definitions/1056.html
-
CISQ. "Automated Source Code Quality Measures."
-
CERT C Coding Standard. "FIO30-C. Exclude user input from format strings."