summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordoug <>2015-01-21 00:15:50 +0000
committerdoug <>2015-01-21 00:15:50 +0000
commite1dc98b778f8f1ba2eda4462bba9385d0b739e6b (patch)
treeb1b48bed26b2d878fed317d5626c19339eb0c97b /src
parent0835a59c494c05b0ecd8a1b7db78136fd9bb897f (diff)
downloadopenbsd-e1dc98b778f8f1ba2eda4462bba9385d0b739e6b.tar.gz
openbsd-e1dc98b778f8f1ba2eda4462bba9385d0b739e6b.tar.bz2
openbsd-e1dc98b778f8f1ba2eda4462bba9385d0b739e6b.zip
Fix DTLS memory leak (CVE-2015-0206).libressl-v2.1.3
There were four bugs fixed by this patch: * dtls1_buffer_record() now frees rdata->rbuf.buf on error. Since s->s3->rbuf was memset, rdata->rbuf is the only pointer left which points to the old rbuf. On error, rdata is freed so there will not be any way of freeing this memory unless we do it here. * Changed the return code of dtls1_buffer_record() to differentiate between queue full (0) and error (-1). See below as this differs from upstream. * Handle errors if calls to dtls1_buffer_record() fail with -1. Previously, it did not check the return value. * Changed the way receipts are recorded. Previously, it was recorded when processed successfully (whether buffered or not) in dtls1_process_record(). Now, it records when it is handled in dtls1_get_record(): either when it is entered into the queue to buffer for the next epoch or when it is processed directly. Processing buffered records does not add a receipt because it needed one in order to get into the queue. The above bugs combined contributed to an eventual DoS through memory exhaustion. The memory leak came from dtls1_buffer_record()'s error handling. The error handling can be triggered by a duplicate record or malloc failure. It was possible to add duplicate records because they were not being dropped. The faulty receipts logic did not detect replays when dealing with records for the next epoch. Additionally, dtls1_buffer_record()'s return value was not checked so an attacker could send repeated replay records for the next epoch. Reported to OpenSSL by Chris Mueller. Patch based on OpenSSL commit 103b171d8fc282ef435f8de9afbf7782e312961f and BoringSSL commit 44e2709cd65fbd2172b9516c79e56f1875f60300. Our patch matches BoringSSL's commit. OpenSSL returns 0 when the queue is full or when malloc() or pitem_new() fails. They return -1 on error including !ssl3_setup_buffers() which is another failure to allocate memory. BoringSSL and LibreSSL changed the return code for dtls1_buffer_record() to be 1 on success, 0 when the queue is full and -1 on error. input + ok bcook@, jsing@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libssl/d1_pkt.c32
-rw-r--r--src/lib/libssl/src/ssl/d1_pkt.c32
2 files changed, 46 insertions, 18 deletions
diff --git a/src/lib/libssl/d1_pkt.c b/src/lib/libssl/d1_pkt.c
index 7bdf245e84..91e9c146ac 100644
--- a/src/lib/libssl/d1_pkt.c
+++ b/src/lib/libssl/d1_pkt.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: d1_pkt.c,v 1.38 2014/12/14 15:30:50 jsing Exp $ */ 1/* $OpenBSD: d1_pkt.c,v 1.39 2015/01/21 00:15:50 doug Exp $ */
2/* 2/*
3 * DTLS implementation written by Nagendra Modadugu 3 * DTLS implementation written by Nagendra Modadugu
4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -222,7 +222,7 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
222 rdata = malloc(sizeof(DTLS1_RECORD_DATA)); 222 rdata = malloc(sizeof(DTLS1_RECORD_DATA));
223 item = pitem_new(priority, rdata); 223 item = pitem_new(priority, rdata);
224 if (rdata == NULL || item == NULL) 224 if (rdata == NULL || item == NULL)
225 goto err; 225 goto init_err;
226 226
227 rdata->packet = s->packet; 227 rdata->packet = s->packet;
228 rdata->packet_length = s->packet_length; 228 rdata->packet_length = s->packet_length;
@@ -254,10 +254,13 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
254 return (1); 254 return (1);
255 255
256err: 256err:
257 free(rdata->rbuf.buf);
258
259init_err:
257 SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); 260 SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
258 free(rdata); 261 free(rdata);
259 pitem_free(item); 262 pitem_free(item);
260 return (0); 263 return (-1);
261} 264}
262 265
263 266
@@ -308,8 +311,9 @@ dtls1_process_buffered_records(SSL *s)
308 dtls1_get_unprocessed_record(s); 311 dtls1_get_unprocessed_record(s);
309 if (! dtls1_process_record(s)) 312 if (! dtls1_process_record(s))
310 return (0); 313 return (0);
311 dtls1_buffer_record(s, &(s->d1->processed_rcds), 314 if (dtls1_buffer_record(s, &(s->d1->processed_rcds),
312 s->s3->rrec.seq_num); 315 s->s3->rrec.seq_num) < 0)
316 return (-1);
313 } 317 }
314 } 318 }
315 319
@@ -446,7 +450,6 @@ dtls1_process_record(SSL *s)
446 450
447 /* we have pulled in a full packet so zero things */ 451 /* we have pulled in a full packet so zero things */
448 s->packet_length = 0; 452 s->packet_length = 0;
449 dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
450 return (1); 453 return (1);
451 454
452f_err: 455f_err:
@@ -480,7 +483,8 @@ dtls1_get_record(SSL *s)
480 483
481 /* The epoch may have changed. If so, process all the 484 /* The epoch may have changed. If so, process all the
482 * pending records. This is a non-blocking operation. */ 485 * pending records. This is a non-blocking operation. */
483 dtls1_process_buffered_records(s); 486 if (dtls1_process_buffered_records(s) < 0)
487 return (-1);
484 488
485 /* if we're renegotiating, then there may be buffered records */ 489 /* if we're renegotiating, then there may be buffered records */
486 if (dtls1_get_processed_record(s)) 490 if (dtls1_get_processed_record(s))
@@ -611,7 +615,11 @@ again:
611 */ 615 */
612 if (is_next_epoch) { 616 if (is_next_epoch) {
613 if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) { 617 if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) {
614 dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num); 618 if (dtls1_buffer_record(s, &(s->d1->unprocessed_rcds),
619 rr->seq_num) < 0)
620 return (-1);
621 /* Mark receipt of record. */
622 dtls1_record_bitmap_update(s, bitmap);
615 } 623 }
616 rr->length = 0; 624 rr->length = 0;
617 s->packet_length = 0; 625 s->packet_length = 0;
@@ -625,6 +633,8 @@ again:
625 goto again; 633 goto again;
626 /* get another record */ 634 /* get another record */
627 } 635 }
636 /* Mark receipt of record. */
637 dtls1_record_bitmap_update(s, bitmap);
628 638
629 return (1); 639 return (1);
630 640
@@ -769,7 +779,11 @@ start:
769 * buffer the application data for later processing rather 779 * buffer the application data for later processing rather
770 * than dropping the connection. 780 * than dropping the connection.
771 */ 781 */
772 dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num); 782 if (dtls1_buffer_record(s, &(s->d1->buffered_app_data),
783 rr->seq_num) < 0) {
784 SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
785 return (-1);
786 }
773 rr->length = 0; 787 rr->length = 0;
774 goto start; 788 goto start;
775 } 789 }
diff --git a/src/lib/libssl/src/ssl/d1_pkt.c b/src/lib/libssl/src/ssl/d1_pkt.c
index 7bdf245e84..91e9c146ac 100644
--- a/src/lib/libssl/src/ssl/d1_pkt.c
+++ b/src/lib/libssl/src/ssl/d1_pkt.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: d1_pkt.c,v 1.38 2014/12/14 15:30:50 jsing Exp $ */ 1/* $OpenBSD: d1_pkt.c,v 1.39 2015/01/21 00:15:50 doug Exp $ */
2/* 2/*
3 * DTLS implementation written by Nagendra Modadugu 3 * DTLS implementation written by Nagendra Modadugu
4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. 4 * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -222,7 +222,7 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
222 rdata = malloc(sizeof(DTLS1_RECORD_DATA)); 222 rdata = malloc(sizeof(DTLS1_RECORD_DATA));
223 item = pitem_new(priority, rdata); 223 item = pitem_new(priority, rdata);
224 if (rdata == NULL || item == NULL) 224 if (rdata == NULL || item == NULL)
225 goto err; 225 goto init_err;
226 226
227 rdata->packet = s->packet; 227 rdata->packet = s->packet;
228 rdata->packet_length = s->packet_length; 228 rdata->packet_length = s->packet_length;
@@ -254,10 +254,13 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
254 return (1); 254 return (1);
255 255
256err: 256err:
257 free(rdata->rbuf.buf);
258
259init_err:
257 SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); 260 SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR);
258 free(rdata); 261 free(rdata);
259 pitem_free(item); 262 pitem_free(item);
260 return (0); 263 return (-1);
261} 264}
262 265
263 266
@@ -308,8 +311,9 @@ dtls1_process_buffered_records(SSL *s)
308 dtls1_get_unprocessed_record(s); 311 dtls1_get_unprocessed_record(s);
309 if (! dtls1_process_record(s)) 312 if (! dtls1_process_record(s))
310 return (0); 313 return (0);
311 dtls1_buffer_record(s, &(s->d1->processed_rcds), 314 if (dtls1_buffer_record(s, &(s->d1->processed_rcds),
312 s->s3->rrec.seq_num); 315 s->s3->rrec.seq_num) < 0)
316 return (-1);
313 } 317 }
314 } 318 }
315 319
@@ -446,7 +450,6 @@ dtls1_process_record(SSL *s)
446 450
447 /* we have pulled in a full packet so zero things */ 451 /* we have pulled in a full packet so zero things */
448 s->packet_length = 0; 452 s->packet_length = 0;
449 dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
450 return (1); 453 return (1);
451 454
452f_err: 455f_err:
@@ -480,7 +483,8 @@ dtls1_get_record(SSL *s)
480 483
481 /* The epoch may have changed. If so, process all the 484 /* The epoch may have changed. If so, process all the
482 * pending records. This is a non-blocking operation. */ 485 * pending records. This is a non-blocking operation. */
483 dtls1_process_buffered_records(s); 486 if (dtls1_process_buffered_records(s) < 0)
487 return (-1);
484 488
485 /* if we're renegotiating, then there may be buffered records */ 489 /* if we're renegotiating, then there may be buffered records */
486 if (dtls1_get_processed_record(s)) 490 if (dtls1_get_processed_record(s))
@@ -611,7 +615,11 @@ again:
611 */ 615 */
612 if (is_next_epoch) { 616 if (is_next_epoch) {
613 if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) { 617 if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) {
614 dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num); 618 if (dtls1_buffer_record(s, &(s->d1->unprocessed_rcds),
619 rr->seq_num) < 0)
620 return (-1);
621 /* Mark receipt of record. */
622 dtls1_record_bitmap_update(s, bitmap);
615 } 623 }
616 rr->length = 0; 624 rr->length = 0;
617 s->packet_length = 0; 625 s->packet_length = 0;
@@ -625,6 +633,8 @@ again:
625 goto again; 633 goto again;
626 /* get another record */ 634 /* get another record */
627 } 635 }
636 /* Mark receipt of record. */
637 dtls1_record_bitmap_update(s, bitmap);
628 638
629 return (1); 639 return (1);
630 640
@@ -769,7 +779,11 @@ start:
769 * buffer the application data for later processing rather 779 * buffer the application data for later processing rather
770 * than dropping the connection. 780 * than dropping the connection.
771 */ 781 */
772 dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num); 782 if (dtls1_buffer_record(s, &(s->d1->buffered_app_data),
783 rr->seq_num) < 0) {
784 SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
785 return (-1);
786 }
773 rr->length = 0; 787 rr->length = 0;
774 goto start; 788 goto start;
775 } 789 }