CVE-2010-0740: Record of death vulnerability in OpenSSL
A new vulnerability (CVE-2010-0740) was found in OpenSSL, affectionately called “Record of death” (in reference to the ping of death vulnerability back in 1996) was fixed by the patch below:
--- ssl/s3_pkt.c 24 Jan 2010 13:52:38 -0000 1.57.2.9
+++ ssl/s3_pkt.c 24 Mar 2010 00:00:00 -0000
@@ -291,9 +291,9 @@
if (version != s->version)
{
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
- /* Send back error using their
- * version number :-) */
- s->version=version;
+ if ((s->version & 0xFF00) == (version & 0xFF00))
+ /* Send back error using their minor version number :-) */
+ s->version = (unsigned short)version;
al=SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
Arno and myself had a look on this vuln, but at a glance, it’s hard to understand the consequences of these two modifications:
- Comparison of the server version and the packet version
- Use of cast for the assignment.
The latter is the interesting part. s->version
is declared as a int
(32 bits signed value on x86
) and version
is a short
(16 bits
signed value on x86
).
When doing the following assignment:
int i_version;
short s_version;
i_version = s_version;
What are the problems? On x86
, i_version
is big enough to store
s_version
so there is no truncation or overflow issues. However,
these two variables are signed and the C has the following rule:
Conversion of an operand value to a compatible type causes no change to the value or the representation.
In other words:
short s;
int i;
s = -1;
i = s; /* i must be equal to -1 */
To do this, the compiler has to perform a sign extension, which means that if the short value was negative, its integer value must stays negative.
Internally, the most significant bit (msb) of the short variable will be propagated in the integer variable for the “upper bits”. Examples:
|--------+-----+--------------|
| short | msb | integer |
|--------+-----+--------------|
| 0x0000 | 0 | 0x00000000 |
| 0x7000 | 0 | 0x00070000 |
| 0x8000 | 1 | 0xffff0000 |
| 0xffff | 1 | 0xffffffff |
|--------+-----+--------------|
So if version >= 0x8000
, s->version
will have a value
>= 0xffff0000
(a big negative value).
According to the advisory, this bug can cause a crash of an OpenSSL
end-point due to a read attempt at NULL.
The OpenSSL code uses extensively indirect function pointers for
callbacks so it is hard to follow the code path without spending some
time, so I cannot confirm neither my hypothesis nor the impact of the
bug.