L'explication détaillée du bug :
http://blog.existentialize.com/diagnosis-of-the-openssl-heartbleed-bug.htmlRecords have a type, a length, and data. Back to dtls1_process_heartbeat:
/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;
The first byte of the SSLv3 record is the heartbeat type. The macro n2s takes two bytes from p, and puts them in payload. This is actually the length of the payload. Note that the actual length in the SSLv3 record is not checked.
The variable pl is then the resulting heartbeat data, supplied by the requester.
Later in the function, it does this:
unsigned char *buffer, *bp;
int r;
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
So we're allocating as much memory as the requester asked for: up to 65535+1+2+16, to be precise. The variable bp is going to be the pointer used for accessing this memory. Then:
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
The macro s2n does the inverse of n2s: it takes a 16-bit value and puts it into two bytes. So it puts the same payload length requested.
Then it copies payload bytes from pl, the user supplied data, to the newly allocated bp array. After this, it sends this all back to the user. So where's the bug?Vous le voyez le problème? (Les problèmes d'ailleurs.)
Ce code ne correspond pas du tout à ce qu'on s'attend à voir! Quand on a lu quelques codes sources de traitement de données venant du réseau, les problèmes sont évidents : il n'y a aucune validation des valeurs et de la taille des données.
Comme toujours, la proposition standard "d'écrire des tests unitaires" ne sert que si quelqu'un pense à tester le cas où le message est mal formé.
Si la personne pense à cette éventualité, elle peut aussi bien lire le code source et voir que ce cas n'est pas traité. Pour moi "écrire des tests unitaires" ne résout rien dans ce genre de cas (par contre cela aurait détecté une autre faille dans un composant TLS, où un cas était géré spécialement par ce code mais pas traité correctement).
Ce genre de bugs est "code qui traite identiquement deux situations foncièrement différentes" :
- message bien formé
- message mal formé
Tout message est ici supposé bien formé.
C'est une erreur de débutant (comme beaucoup de failles d'ailleurs).
Comme toujours, c'est plus facile à voir quand on nous dit "voici le bug". Cependant, je pense que si j'avais lu ce code, comme ça, sans me méfier spécialement, j'aurais tiqué sur l'absence de validation. J'en suis quasiment sûr.