Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 10 Apr 2014 05:39:55 -0700
From:      "Ronald F. Guilmette" <rfg@tristatelogic.com>
To:        freebsd-security@freebsd.org
Subject:   Re: Heartbleed, a few naive questions
Message-ID:  <43981.1397133595@server1.tristatelogic.com>
In-Reply-To: <867g6x5u2r.fsf@nine.des.no>

next in thread | previous in thread | raw e-mail | index | archive | help

In message <867g6x5u2r.fsf@nine.des.no>, 
=?utf-8?Q?Dag-Erling_Sm=C3=B8rgrav?= <des@des.no> wrote:

>"Ronald F. Guilmette" <rfg@tristatelogic.com> writes:
>> Xin Li <delphij@delphij.net> writes:
>> > For this bug, doing calloc() makes no difference.
>> I would very much like to know how you reached that conclusion.
>
>It's very simple.  The explpoit relies on reading past the end of the
>allocated buffer.

You're right, of course, and I missed that.  My apologies.

My other points still stand however, the most important of which is
that the protocol definition itself seems to be asking for trouble,
and that this bug was/is the almost inevitable outgrowth of an entirely
poorly considered bit of the SSL protocol specification.

Hummm...

In fact, now that I look at the code some more I'm not even sure if my
suggestion for using calloc() in place of malloc() throughout OpenSSL
was even entirely off the mark... although the exact _place_ where that
suggestion might have been most profitably applied is *not* within the
dtls1_process_heartbeat() function itself, but rather is wherever the
original receive buffer was allocated, i.e.  the buffer that is pointed
to by s->s3->rrec.data upon entry to the dtls1_process_heartbeat() function.

I have not searched the code to find the place where this original
packet receive buffer is allocated, however regardless of whereever
this allocation takes place I think that it is safe to say that if
such buffers were always allocated to the maximum possible size needed
(1+2+65536+16) _and_ if they were always obtained via calls to calloc()
or its functional equivalent, then there would never have been such a
thing as the Heartbleed bug and this conversation would not now be taking
place.

Does anyone happen to have a copy of the complete original (unpatched)
source code lying around?  I have a sudden urge to look and see where
exactly the buffer corresponding to s->s3->rrec.data is allocated, with
an eye to trying to understand why on earth it was ever made shorter
than 1+2+65536+16 bytes long.  (Well, actually, it appears that these
buffers could all have reasonably be allocated to the rather smaller
fixed size of 2^14+16 if the OpenSSL authors had actually followed the
RFC.  See below.)


Regards,
rfg


P.S.  Public reports regarding this bug assert that an attacker can
gulp down up to 64KB long chunks of one's private data at a time.  I
have no reason at present to disbelieve those assertions, however if
those assertions are true, then that would seem to suggest that in addition
to creating a rather awful bug, the implementors of OpenSSL may have also
failed to perform range checking on the payload_length values provided
within received HeartbeatRequest packets... range checking that is
apparently *MANDITORY* in order to simply meet the requirements of the
relevant RFC (6520):

     "The total length of a HeartbeatMessage MUST NOT exceed 2^14 or
     max_fragment_length when negotiated as defined in [RFC6066]."

     ...

     "If the payload_length of a received HeartbeatMessage is too large,
     the received HeartbeatMessage MUST be discarded silently.
                                   ^^^^

If the OpenSSL authors had simply bothered to implement the requirements
of RFC6520, then it would appear that the worst case data leakage would
have been on the order of 16KB(-3) per gulp... still quite an awful bug,
but not quite as bad as the one currently making headlines.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?43981.1397133595>