Commit d0a4b7d1 authored by Adam Langley's avatar Adam Langley Committed by Matt Caswell
Browse files

Fix memory leak from zero-length DTLS fragments.



The |pqueue_insert| function can fail if one attempts to insert a
duplicate sequence number. When handling a fragment of an out of
sequence message, |dtls1_process_out_of_seq_message| would not call
|dtls1_reassemble_fragment| if the fragment's length was zero. It would
then allocate a fresh fragment and attempt to insert it, but ignore the
return value, leaking the fragment.

This allows an attacker to exhaust the memory of a DTLS peer.

Fixes CVE-2014-3507

Reviewed-by: default avatarMatt Caswell <matt@openssl.org>
Reviewed-by: default avatarEmilia Käsper <emilia@openssl.org>
parent 1250f126
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -616,6 +616,9 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
	    msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
		goto err;

	if (frag_len == 0)
		return DTLS1_HM_FRAGMENT_RETRY;

	/* Try to find item in queue */
	memset(seq64be,0,sizeof(seq64be));
	seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
@@ -693,7 +696,12 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
			goto err;
			}

		pqueue_insert(s->d1->buffered_messages, item);
		item = pqueue_insert(s->d1->buffered_messages, item);
		/* pqueue_insert fails iff a duplicate item is inserted.
		 * However, |item| cannot be a duplicate. If it were,
		 * |pqueue_find|, above, would have returned it and control
		 * would never have reached this branch. */
		OPENSSL_assert(item != NULL);
		}

	return DTLS1_HM_FRAGMENT_RETRY;
@@ -751,7 +759,7 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
		}
	else
		{
		if (frag_len && frag_len < msg_hdr->msg_len)
		if (frag_len < msg_hdr->msg_len)
			return dtls1_reassemble_fragment(s, msg_hdr, ok);

		if (frag_len > dtls1_max_handshake_message_len(s))
@@ -780,7 +788,15 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
		if ( item == NULL)
			goto err;

		pqueue_insert(s->d1->buffered_messages, item);
		item = pqueue_insert(s->d1->buffered_messages, item);
		/* pqueue_insert fails iff a duplicate item is inserted.
		 * However, |item| cannot be a duplicate. If it were,
		 * |pqueue_find|, above, would have returned it. Then, either
		 * |frag_len| != |msg_hdr->msg_len| in which case |item| is set
		 * to NULL and it will have been processed with
		 * |dtls1_reassemble_fragment|, above, or the record will have
		 * been discarded. */
		OPENSSL_assert(item != NULL);
		}

	return DTLS1_HM_FRAGMENT_RETRY;