CVE-2015-2698: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: The iakerb_gss_export_sec_context function in lib/gssapi/krb5/iakerb.c in MIT Kerberos 5 (aka krb5) 1.14 pre-release 2015-09-14 improperly accesses a certain pointer, which allows remote authenticated users to cause a denial of service (memory corruption) or possibly have unspecified other impact by interacting with an application that calls the gss_export_sec_context function.  NOTE: this vulnerability exists because of an incorrect fix for CVE-2015-2696.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Published: 2015-11-13T03:59Z
Repository: https://github.com/krb5/krb5
Language: C
Files changed: src/lib/gssapi/krb5/gssapiP_krb5.h, src/lib/gssapi/krb5/gssapi_krb5.c, src/lib/gssapi/krb5/iakerb.c
Commit date: 2015-11-05 12:11:33 -0500
Commit message: Fix IAKERB context export/import [CVE-2015-2698]

The patches for CVE-2015-2696 contained a regression in the newly
added IAKERB iakerb_gss_export_sec_context() function, which could
cause it to corrupt memory.  Fix the regression by properly
dereferencing the context_handle pointer before casting it.

Also, the patches did not implement an IAKERB gss_import_sec_context()
function, under the erroneous belief that an exported IAKERB context
would be tagged as a krb5 context.  Implement it now to allow IAKERB
contexts to be successfully exported and imported after establishment.

CVE-2015-2698:

In any MIT krb5 release with the patches for CVE-2015-2696 applied, an
application which calls gss_export_sec_context() may experience memory
corruption if the context was established using the IAKERB mechanism.
Historically, some vulnerabilities of this nature can be translated
into remote code execution, though the necessary exploits must be
tailored to the individual application and are usually quite
complicated.

    CVSSv2 Vector: AV:N/AC:H/Au:S/C:C/I:C/A:C/E:POC/RL:OF/RC:C

ticket: 8273 (new)
target_version: 1.14
tags: pullup

Diff: diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 97e090d099f..16635006db1 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -1395,10 +1395,15 @@ iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
 #ifndef LEAN_CLIENT
 OM_uint32 KRB5_CALLCONV
 iakerb_gss_export_sec_context(OM_uint32 *minor_status,
                               gss_ctx_id_t *context_handle,
                               gss_buffer_t interprocess_token);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_import_sec_context(OM_uint32 *minor_status,
+                              const gss_buffer_t interprocess_token,
+                              gss_ctx_id_t *context_handle);
 #endif /* LEAN_CLIENT */
 
 OM_uint32 KRB5_CALLCONV
 iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
                                       const gss_ctx_id_t context_handle,
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index c4dfdd6fbd1..aea60dc09fd 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -968,11 +968,11 @@ static struct gss_config iakerb_mechanism = {
 #ifdef LEAN_CLIENT
     NULL,
     NULL,
 #else
     iakerb_gss_export_sec_context,
-    NULL,
+    iakerb_gss_import_sec_context,
 #endif
     krb5_gss_inquire_cred_by_mech,
     krb5_gss_inquire_names_for_mech,
     iakerb_gss_inquire_context,
     krb5_gss_internal_release_oid,
diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
index e25862df47d..32a341ec58d 100644
--- a/src/lib/gssapi/krb5/iakerb.c
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -1055,11 +1055,11 @@ OM_uint32 KRB5_CALLCONV
 iakerb_gss_export_sec_context(OM_uint32 *minor_status,
                               gss_ctx_id_t *context_handle,
                               gss_buffer_t interprocess_token)
 {
     OM_uint32 maj;
-    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
 
     /* We don't currently support exporting partially established contexts. */
     if (!ctx->established)
         return GSS_S_UNAVAILABLE;
 
@@ -1070,17 +1070,45 @@ iakerb_gss_export_sec_context(OM_uint32 *minor_status,
         *context_handle = GSS_C_NO_CONTEXT;
     }
     return maj;
 }
 
-/*
- * Until we implement partial context exports, there are no IAKERB exported
- * context tokens, only tokens for the underlying krb5 context.  So we do not
- * need to implement an iakerb_gss_import_sec_context() yet; it would be
- * unreachable except via a manually constructed token.
- */
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_import_sec_context(OM_uint32 *minor_status,
+                              gss_buffer_t interprocess_token,
+                              gss_ctx_id_t *context_handle)
+{
+    OM_uint32 maj, tmpmin;
+    krb5_error_code code;
+    gss_ctx_id_t gssc;
+    krb5_gss_ctx_id_t kctx;
+    iakerb_ctx_id_t ctx;
+
+    maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc);
+    if (maj != GSS_S_COMPLETE)
+        return maj;
+    kctx = (krb5_gss_ctx_id_t)gssc;
+
+    if (!kctx->established) {
+        /* We don't currently support importing partially established
+         * contexts. */
+        krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
+        return GSS_S_FAILURE;
+    }
 
+    code = iakerb_alloc_context(&ctx, kctx->initiate);
+    if (code != 0) {
+        krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
+        *minor_status = code;
+        return GSS_S_FAILURE;
+    }
+
+    ctx->gssc = gssc;
+    ctx->established = 1;
+    *context_handle = (gss_ctx_id_t)ctx;
+    return GSS_S_COMPLETE;
+}
 #endif /* LEAN_CLIENT */
 
 OM_uint32 KRB5_CALLCONV
 iakerb_gss_inquire_context(OM_uint32 *minor_status,
                            gss_ctx_id_t context_handle, gss_name_t *src_name,

Vulnerable code:     NULL,
    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
/*
 * Until we implement partial context exports, there are no IAKERB exported
 * context tokens, only tokens for the underlying krb5 context.  So we do not
 * need to implement an iakerb_gss_import_sec_context() yet; it would be
 * unreachable except via a manually constructed token.
 */
Fixed code: 
OM_uint32 KRB5_CALLCONV
iakerb_gss_import_sec_context(OM_uint32 *minor_status,
                              const gss_buffer_t interprocess_token,
                              gss_ctx_id_t *context_handle);
    iakerb_gss_import_sec_context,
    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
OM_uint32 KRB5_CALLCONV
iakerb_gss_import_sec_context(OM_uint32 *minor_status,
                              gss_buffer_t interprocess_token,
                              gss_ctx_id_t *context_handle)
{
    OM_uint32 maj, tmpmin;
    krb5_error_code code;
    gss_ctx_id_t gssc;
    krb5_gss_ctx_id_t kctx;
    iakerb_ctx_id_t ctx;

    maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc);
    if (maj != GSS_S_COMPLETE)
        return maj;
    kctx = (krb5_gss_ctx_id_t)gssc;

    if (!kctx->established) {
        /* We don't currently support importing partially established
         * contexts. */
        krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
        return GSS_S_FAILURE;
    }
    code = iakerb_alloc_context(&ctx, kctx->initiate);
    if (code != 0) {
        krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
        *minor_status = code;
        return GSS_S_FAILURE;
    }

    ctx->gssc = gssc;
    ctx->established = 1;
    *context_handle = (gss_ctx_id_t)ctx;
    return GSS_S_COMPLETE;
}