Skip to content

Commit

Permalink
Excessive allocation of memory in dtls1_preprocess_fragment()
Browse files Browse the repository at this point in the history
This issue is very similar to CVE-2016-6307 described in the previous
commit. The underlying defect is different but the security analysis and
impacts are the same except that it impacts DTLS.

A DTLS message includes 3 bytes for its length in the header for the
message.
This would allow for messages up to 16Mb in length. Messages of this length
are excessive and OpenSSL includes a check to ensure that a peer is sending
reasonably sized messages in order to avoid too much memory being consumed
to service a connection. A flaw in the logic of version 1.1.0 means that
memory for the message is allocated too early, prior to the excessive
message length check. Due to way memory is allocated in OpenSSL this could
mean an attacker could force up to 21Mb to be allocated to service a
connection. This could lead to a Denial of Service through memory
exhaustion. However, the excessive message length check still takes place,
and this would cause the connection to immediately fail. Assuming that the
application calls SSL_free() on the failed conneciton in a timely manner
then the 21Mb of allocated memory will then be immediately freed again.
Therefore the excessive memory allocation will be transitory in nature.
This then means that there is only a security impact if:

1) The application does not call SSL_free() in a timely manner in the
event that the connection fails
or
2) The application is working in a constrained environment where there
is very little free memory
or
3) The attacker initiates multiple connection attempts such that there
are multiple connections in a state where memory has been allocated for
the connection; SSL_free() has not yet been called; and there is
insufficient memory to service the multiple requests.

Except in the instance of (1) above any Denial Of Service is likely to
be transitory because as soon as the connection fails the memory is
subsequently freed again in the SSL_free() call. However there is an
increased risk during this period of application crashes due to the lack
of memory - which would then mean a more serious Denial of Service.

This issue does not affect TLS users.

Issue was reported by Shi Lei (Gear Team, Qihoo 360 Inc.).

CVE-2016-6308

Reviewed-by: Richard Levitte <levitte@openssl.org>
(cherry picked from commit 48c054f)
  • Loading branch information
mattcaswell committed Sep 21, 2016
1 parent 4b390b6 commit df6b5e2
Showing 1 changed file with 18 additions and 17 deletions.
35 changes: 18 additions & 17 deletions ssl/statem/statem_dtls.c
Expand Up @@ -388,6 +388,20 @@ int dtls_get_message(SSL *s, int *mt, unsigned long *len)
return 1; return 1;
} }


/*
* dtls1_max_handshake_message_len returns the maximum number of bytes
* permitted in a DTLS handshake message for |s|. The minimum is 16KB, but
* may be greater if the maximum certificate list size requires it.
*/
static unsigned long dtls1_max_handshake_message_len(const SSL *s)
{
unsigned long max_len =
DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
if (max_len < (unsigned long)s->max_cert_list)
return s->max_cert_list;
return max_len;
}

static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr) static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
{ {
size_t frag_off, frag_len, msg_len; size_t frag_off, frag_len, msg_len;
Expand All @@ -397,15 +411,16 @@ static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
frag_len = msg_hdr->frag_len; frag_len = msg_hdr->frag_len;


/* sanity checking */ /* sanity checking */
if ((frag_off + frag_len) > msg_len) { if ((frag_off + frag_len) > msg_len
|| msg_len > dtls1_max_handshake_message_len(s)) {
SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
return SSL_AD_ILLEGAL_PARAMETER; return SSL_AD_ILLEGAL_PARAMETER;
} }


if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */ if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */
/* /*
* msg_len is limited to 2^24, but is effectively checked against max * msg_len is limited to 2^24, but is effectively checked against
* above * dtls_max_handshake_message_len(s) above
*/ */
if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) {
SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB); SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB);
Expand Down Expand Up @@ -493,20 +508,6 @@ static int dtls1_retrieve_buffered_fragment(SSL *s, int *ok)
return 0; return 0;
} }


/*
* dtls1_max_handshake_message_len returns the maximum number of bytes
* permitted in a DTLS handshake message for |s|. The minimum is 16KB, but
* may be greater if the maximum certificate list size requires it.
*/
static unsigned long dtls1_max_handshake_message_len(const SSL *s)
{
unsigned long max_len =
DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
if (max_len < (unsigned long)s->max_cert_list)
return s->max_cert_list;
return max_len;
}

static int static int
dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok) dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok)
{ {
Expand Down

0 comments on commit df6b5e2

Please sign in to comment.