Analyse des HeartBleed Bugs
Die beste bisher aufgetauchte Beschreibung des Fehlers habe ich hier gefunden https://news.ycombinator.com/item?id=7549943 von drv und darin die interessanten Stellen fett markiert : TLS heartbeat consists of a request packet including a payload; the other side reads and sends a response containing the same payload (plus some other padding). In the code that handles TLS heartbeat requests, the payload size is read from the packet controlled by the attacker:
1: 2: |
n2s(p, payload); pl = p; |
1: 2: 3: 4: |
/* Enter response type, length and copy payload */ *bp++ = TLS1_HB_RESPONSE; s2n(payload, bp); memcpy(bp, pl, payload); |
Vorkehrung
Die genannte Vorkehrung wäre eine einfache Datenstruktur, ein Tupel (pointer, length), um die zusammengehörenden Daten zu vereinen, damit es nicht zu Verwechslungen kommen kann. In F# Syntax sähe das so aus
1:
|
let buffer = (pointer, length) |
1:
|
type Buffer = { pointer : int64; length : int64 } |
length
und pointer
nicht aus versehen vertauscht zugewiesen werden?
1: 2: |
let buffer = { l; p } // Vertauscht! Compiler reklamiert nicht 🙁 let buffer = { p; l } // pointer, length |
long
! Was kann man dagegen tun? F# hat dazu die sogenannten Units of Measures, also Maßeinheiten, wie Kilogramm und Meter, die ganzen SI-Einheiten sind schon vordefiniert, das nur am Rande, denn wir brauchen hier was anderes. Wie wäre es mit den Einheiten Pointer
und Length
? Diese kann man sich wie folgt definieren
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: |
// Units of Measures type [<Measure>] Pointer type [<Measure>] Length // Record Type type Buffer = { pointer : int64<Pointer> length : int64<Length> } let p = 123456L<Pointer> let l = 512L<Length> let buf = { pointer = p; length = l } // val buf : Buffer = {pointer = 123456L; // length = 512L;} // Verwechslung bei der Zuweisung let buf = { pointer = l; length = p } // error FS0001: Type mismatch. Expecting a // int64<Pointer> // but given a // int64<Length> // The unit of measure 'Pointer' does not match the unit of measure 'Length' |
Pointer
keine Length
zugewiesen werden kann.
Noch mehr Bugs?
Interessant ist auch, dass genau da wo der HeartBleed Bug die Ursache hat, schon einmal etwas gefixt wurde am 27 Feb 2012,“This patch fixes two padding related bugs for the Heartbeat Response messages. For DTLS, the wrong pointer was used, which may overwrite the payload with the random padding. For TLS, there was no random padding at all.” http://marc.info/?l=openssl-dev&m=133035562503173Das gibt der alten ungeschriebenen Regel wiedereinmal mehr recht:
Da wo ein Bug ist, sind noch mehr.
Fazit
Wichtig war es mir hier anhand aktueller echter Probleme aufzuzeigen, wie man dies elegant und besser lösen kann. Und mit dem Potential das F# mitbringt ist es bestens geeignet um komplexe Probleme einfach und korrekt zu lösen. Man denke dabei auch daran, wie viele Unit-Tests man einsparen kann, wenn der Compiler so strikt prüfen kann.Multiple items
val int64 : value:’T -> int64 (requires member op_Explicit)Full name: Microsoft.FSharp.Core.Operators.int64——————–
type int64 = System.Int64Full name: Microsoft.FSharp.Core.int64——————–
type int64<‘Measure> = int64
Full name: Microsoft.FSharp.Core.int64<_>
Multiple items
type MeasureAttribute =
inherit Attribute
new : unit -> MeasureAttributeFull name: Microsoft.FSharp.Core.MeasureAttribute——————–
new : unit -> MeasureAttribute