From bfe7b5f6a92129e238eae0ef5a41ff19b063f0b9 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Wed, 8 Apr 2009 01:22:51 +0000 Subject: [PATCH] CVE-2009-0844 (1.6.x) SPNEGO can read beyond buffer end pull up rxxxxx from trunk SPNEGO can read beyond the end of a buffer if the claimed DER length exceeds the number of bytes in the input buffer. This can lead to crash or information disclosure. Thanks to Apple for reporting this vulnerability and providing patches. ticket: 6446 tags: pullup target_version: 1.6.4 version_fixd: 1.6.4 git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-6@22179 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/gssapi/spnego/spnego_mech.c | 47 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c index 630c73ac1..4384708b1 100644 --- a/src/lib/gssapi/spnego/spnego_mech.c +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -54,8 +54,8 @@ typedef const gss_OID_desc *gss_OID_const; /* der routines defined in libgss */ extern unsigned int gssint_der_length_size(OM_uint32); -extern int gssint_get_der_length(unsigned char **, OM_uint32, OM_uint32*); -extern int gssint_put_der_length(OM_uint32, unsigned char **, OM_uint32); +extern int gssint_get_der_length(unsigned char **, OM_uint32, unsigned int*); +extern int gssint_put_der_length(OM_uint32, unsigned char **, unsigned int); /* private routines for spnego_mechanism */ @@ -1803,22 +1803,16 @@ static gss_buffer_t get_input_token(unsigned char **buff_in, unsigned int buff_length) { gss_buffer_t input_token; - unsigned int bytes; + unsigned int len; - if (**buff_in != OCTET_STRING) + if (g_get_tag_and_length(buff_in, OCTET_STRING, buff_length, &len) < 0) return (NULL); - (*buff_in)++; input_token = (gss_buffer_t)malloc(sizeof (gss_buffer_desc)); - if (input_token == NULL) return (NULL); - input_token->length = gssint_get_der_length(buff_in, buff_length, &bytes); - if ((int)input_token->length == -1) { - free(input_token); - return (NULL); - } + input_token->length = len; input_token->value = malloc(input_token->length); if (input_token->value == NULL) { @@ -1870,8 +1864,8 @@ get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in, { gss_OID_set returned_mechSet; OM_uint32 major_status; - OM_uint32 length; - OM_uint32 bytes; + int length; + unsigned int bytes; OM_uint32 set_length; unsigned char *start; int i; @@ -1883,22 +1877,25 @@ get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in, (*buff_in)++; length = gssint_get_der_length(buff_in, buff_length, &bytes); + if (length < 0 || buff_length - bytes < (unsigned int)length) + return NULL; major_status = gss_create_empty_oid_set(minor_status, &returned_mechSet); if (major_status != GSS_S_COMPLETE) return (NULL); - for (set_length = 0, i = 0; set_length < length; i++) { + for (set_length = 0, i = 0; set_length < (unsigned int)length; i++) { gss_OID_desc *temp = get_mech_oid(minor_status, buff_in, buff_length - (*buff_in - start)); - if (temp != NULL) { - major_status = gss_add_oid_set_member(minor_status, - temp, &returned_mechSet); - if (major_status == GSS_S_COMPLETE) { + if (temp == NULL) + break; + + major_status = gss_add_oid_set_member(minor_status, + temp, &returned_mechSet); + if (major_status == GSS_S_COMPLETE) { set_length += returned_mechSet->elements[i].length +2; generic_gss_release_oid(minor_status, &temp); - } } } @@ -2098,7 +2095,7 @@ get_negTokenResp(OM_uint32 *minor_status, return GSS_S_DEFECTIVE_TOKEN; if (*ptr++ == SEQUENCE) { tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes); - if (tmplen < 0) + if (tmplen < 0 || REMAIN < (unsigned int)tmplen) return GSS_S_DEFECTIVE_TOKEN; } if (REMAIN < 1) @@ -2108,7 +2105,7 @@ get_negTokenResp(OM_uint32 *minor_status, if (tag == CONTEXT) { tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes); - if (tmplen < 0) + if (tmplen < 0 || REMAIN < (unsigned int)tmplen) return GSS_S_DEFECTIVE_TOKEN; if (g_get_tag_and_length(&ptr, ENUMERATED, @@ -2129,7 +2126,7 @@ get_negTokenResp(OM_uint32 *minor_status, } if (tag == (CONTEXT | 0x01)) { tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes); - if (tmplen < 0) + if (tmplen < 0 || REMAIN < (unsigned int)tmplen) return GSS_S_DEFECTIVE_TOKEN; *supportedMech = get_mech_oid(minor_status, &ptr, REMAIN); @@ -2143,7 +2140,7 @@ get_negTokenResp(OM_uint32 *minor_status, } if (tag == (CONTEXT | 0x02)) { tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes); - if (tmplen < 0) + if (tmplen < 0 || REMAIN < (unsigned int)tmplen) return GSS_S_DEFECTIVE_TOKEN; *responseToken = get_input_token(&ptr, REMAIN); @@ -2157,7 +2154,7 @@ get_negTokenResp(OM_uint32 *minor_status, } if (tag == (CONTEXT | 0x03)) { tmplen = gssint_get_der_length(&ptr, REMAIN, &bytes); - if (tmplen < 0) + if (tmplen < 0 || REMAIN < (unsigned int)tmplen) return GSS_S_DEFECTIVE_TOKEN; *mechListMIC = get_input_token(&ptr, REMAIN); @@ -2718,7 +2715,7 @@ g_get_tag_and_length(unsigned char **buf, int tag, &encoded_len); if (tmplen < 0) { ret = -1; - } else if (tmplen > buflen - (ptr - *buf)) { + } else if ((unsigned int)tmplen > buflen - (ptr - *buf)) { ret = -1; } else ret = 0; -- 2.26.2