dtls1_read_bytes() uses dtls1_get_record() to get a record from the
wire. There's an agreement between those two functions that says that
ssl->s3->rrec.length contains the length of the record just read. If
ssl->s3->rrec.length equals 0 then there's no record in the buffer.
dtls1_get_record() fails to set ssl->s3->rrec.length to 0 if it drops a
record for various reasons. Therefore dtls1_read_bytes() wrongly
interprets this bogus piece of data which should have been ignored.
This patch aims to fix this bug by assigning 0 to rrec->length in those
places.
Version affected: HEAD
Index: ssl/d1_pkt.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/d1_pkt.c,v
retrieving revision 1.33
diff -u -8 -p -r1.33 d1_pkt.c
--- ssl/d1_pkt.c 5 Jun 2009 14:59:26 -0000 1.33
+++ ssl/d1_pkt.c 29 Jun 2009 18:46:39 -0000
@@ -618,29 +618,31 @@ again:
/* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
i=rr->length;
n=ssl3_read_n(s,i,i,1);
if (n <= 0) return(n); /* error or non-blocking io */
/* this packet contained a partial record, dump it */
if ( n != i)
{
+ rr->length = 0;
s->packet_length = 0;
goto again;
}
/* now n == rr->length,
* and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length
*/
}
s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
/* match epochs. NULL means the packet is dropped on the floor */
bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
if ( bitmap == NULL)
{
+ rr->length = 0;
s->packet_length = 0; /* dump this record */
goto again; /* get another record */
}
/* check whether this is a repeat, or aged record */
if ( ! dtls1_record_replay_check(s, bitmap))
{
rr->length = 0;
@@ -655,16 +657,17 @@ again:
* buffer it since it cannot be processed at this time. Records
* from the next epoch are marked as received even though they
* are not processed, so as to prevent any potential resource
* DoS attack */
if (is_next_epoch)
{
dtls1_record_bitmap_update(s, bitmap);
dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+ rr->length = 0;
s->packet_length = 0;
goto again;
}
if ( ! dtls1_process_record(s))
return(0);
dtls1_clear_timeouts(s); /* done waiting */