Fragen? Antworten! Siehe auch: Alternativlos
Diesmal geht es um Abschneiden von Integer-Werten. Das ist ein seltener Bug, aber es wäre trivial für gcc, in dem Fall eine Warnung rauszuschmeißen. Ich habe schon Produktionscode auditiert, der den Bug hatte, das ist also nicht theoretisch. Die Idee ist folgende:
int needed=0;Wenn die Liste nicht aus tatsächlich allozierten Dingen besteht (oder auf einer 64-bit Plattform läuft), sondern sagen wir aus Regionen in einer in den Speicher gemappten Datei, oder einer virtuellen Sache wie bei einem Webserver in einer HTTP-Anfrage die Ranges, dann ist das ein Integer Overflow. Bug 1 ist, dass hier int benutzt wird, das ist vorzeichenbehaftet, das gibt nur Ärger. Bei einem Overflow kommt am Ende ein negativer Wert raus, und dann hat man Code wie diesen:
struct node* l;
for (l=listhead; l; l=l->next) {
needed+=l->chunksize;
}
if (needed < MAX_ALLOC) {Wenn needed negativ ist, läuft der Check durch, aber malloc nimmt size_t, der Compiler konvertiert das implizit, und dabei wird das dann ein sehr großer Wert und je nach System klappt womöglich sogar die Allokation.
buf=malloc(needed);
Bug 2 ist, dass der Overflow nicht abgefangen wird. Wenn ihr euch an das hier erinnert, ist das der 2. Grund, keine vorzeichenbehafteten Werte für Längen oder Größen zu nehmen. Gut, nun nehmen wir mal an, jemand konvertiert das nach unsigned long long, um den Overflow loszuwerden. Haben wir alles schon gehabt. Er checkt auch ordentlich, dass es bei der Addition keinen Überlauf gibt. Aber auf einem 32-bit System ist size_t normalerweise 32-bit breit, und unsigned long long ist 64-bit breit. Bei der Übergabe des Arguments schneidet gcc daher den oberen Teil ab. Ein schlauer Angreifer kann dann den Wert so zurecht fummeln, dass die Summe nach Abschneiden 1 ergibt, aber in der Reinkopier-Schleife dann mehr reinkopiert wird. Ein klassischer Heap-Overflow.
Daher mein Vorschlag, dass man bei Allokations-Längen dem Compiler mitteilen kann, dass hier ein Abschneiden ein echtes Problem wäre.
Wenn die gcc-Leute sich weigern, werde ich bei der dietlibc wahrscheinlich so etwas wie das hier machen:
#define malloc(x) ({typeof(x) y=x; (y<0 || (size_t)(y)!=y ? 0 : malloc(y));})Kommentare? Übrigens möchte ich bei der Gelegenheit auch noch mal meine Integer Overflow Seite pluggen.