]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Preserve GSS context on init/accept failure 677/head
authorGreg Hudson <ghudson@mit.edu>
Fri, 14 Jul 2017 17:02:46 +0000 (13:02 -0400)
committerGreg Hudson <ghudson@mit.edu>
Mon, 28 Aug 2017 15:50:30 +0000 (11:50 -0400)
After gss_init_sec_context() or gss_accept_sec_context() has created a
context, don't delete the mechglue context on failures from subsequent
calls, even if the mechanism deletes the mech-specific context (which
is allowed by RFC 2744 but not preferred).  Check for union contexts
with no mechanism context in each GSS function which accepts a
gss_ctx_id_t.

CVE-2017-11462:

RFC 2744 permits a GSS-API implementation to delete an existing
security context on a second or subsequent call to
gss_init_sec_context() or gss_accept_sec_context() if the call results
in an error.  This API behavior has been found to be dangerous,
leading to the possibility of memory errors in some callers.  For
safety, GSS-API implementations should instead preserve existing
security contexts on error until the caller deletes them.

All versions of MIT krb5 prior to this change may delete acceptor
contexts on error.  Versions 1.13.4 through 1.13.7, 1.14.1 through
1.14.5, and 1.15 through 1.15.1 may also delete initiator contexts on
error.

ticket: 8598 (new)
target_version: 1.15-next
target_version: 1.14-next
tags: pullup

17 files changed:
src/lib/gssapi/mechglue/g_accept_sec_context.c
src/lib/gssapi/mechglue/g_complete_auth_token.c
src/lib/gssapi/mechglue/g_context_time.c
src/lib/gssapi/mechglue/g_delete_sec_context.c
src/lib/gssapi/mechglue/g_exp_sec_context.c
src/lib/gssapi/mechglue/g_init_sec_context.c
src/lib/gssapi/mechglue/g_inq_context.c
src/lib/gssapi/mechglue/g_prf.c
src/lib/gssapi/mechglue/g_process_context.c
src/lib/gssapi/mechglue/g_seal.c
src/lib/gssapi/mechglue/g_sign.c
src/lib/gssapi/mechglue/g_unseal.c
src/lib/gssapi/mechglue/g_unwrap_aead.c
src/lib/gssapi/mechglue/g_unwrap_iov.c
src/lib/gssapi/mechglue/g_verify.c
src/lib/gssapi/mechglue/g_wrap_aead.c
src/lib/gssapi/mechglue/g_wrap_iov.c

index ddaf87412e9e3efdbb76377940e8dd8a40a1ca51..f28e2b14a9036d3d79470a55cfc5bde7b52be247 100644 (file)
@@ -216,6 +216,8 @@ gss_cred_id_t *             d_cred;
     } else {
        union_ctx_id = (gss_union_ctx_id_t)*context_handle;
        selected_mech = union_ctx_id->mech_type;
+       if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
+           return (GSS_S_NO_CONTEXT);
     }
 
     /* Now create a new context if we didn't get one. */
@@ -234,9 +236,6 @@ gss_cred_id_t *             d_cred;
            free(union_ctx_id);
            return (status);
        }
-
-       /* set the new context handle to caller's data */
-       *context_handle = (gss_ctx_id_t)union_ctx_id;
     }
 
     /*
@@ -277,8 +276,10 @@ gss_cred_id_t *            d_cred;
                                        d_cred ? &tmp_d_cred : NULL);
 
            /* If there's more work to do, keep going... */
-           if (status == GSS_S_CONTINUE_NEEDED)
+           if (status == GSS_S_CONTINUE_NEEDED) {
+               *context_handle = (gss_ctx_id_t)union_ctx_id;
                return GSS_S_CONTINUE_NEEDED;
+           }
 
            /* if the call failed, return with failure */
            if (status != GSS_S_COMPLETE) {
@@ -364,14 +365,22 @@ gss_cred_id_t *           d_cred;
                *mech_type = gssint_get_public_oid(actual_mech);
            if (ret_flags != NULL)
                *ret_flags = temp_ret_flags;
-           return      (status);
+           *context_handle = (gss_ctx_id_t)union_ctx_id;
+           return GSS_S_COMPLETE;
     } else {
 
        status = GSS_S_BAD_MECH;
     }
 
 error_out:
-    if (union_ctx_id) {
+       /*
+        * RFC 2744 5.1 requires that we not create a context on a failed first
+        * call to accept, and recommends that on a failed subsequent call we
+        * make the caller responsible for calling gss_delete_sec_context.
+        * Even if the mech deleted its context, keep the union context around
+        * for the caller to delete.
+        */
+    if (union_ctx_id && *context_handle == GSS_C_NO_CONTEXT) {
        if (union_ctx_id->mech_type) {
            if (union_ctx_id->mech_type->elements)
                free(union_ctx_id->mech_type->elements);
@@ -384,7 +393,6 @@ error_out:
                                         GSS_C_NO_BUFFER);
        }
        free(union_ctx_id);
-       *context_handle = GSS_C_NO_CONTEXT;
     }
 
     if (src_name)
index 91815513017fa661ae1a43213ef9d1bcea75fc3c..4bcb47e84b90e41218c82ae2ea698388f1373958 100644 (file)
@@ -52,6 +52,8 @@ gss_complete_auth_token (OM_uint32 *minor_status,
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech != NULL) {
index 2ff8d0996ef05a70e66e3fbd743d0b04b88ecb36..c947e7646c10e1853888236ef481b5ef3bc0e0cc 100644 (file)
@@ -58,6 +58,8 @@ OM_uint32 *           time_rec;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
index 4bf0dec5ce3389c75a52f3e7d89bb3997e3c817a..574ff02944b02c74b3ec55db89ed51ab56963d0c 100644 (file)
@@ -87,12 +87,14 @@ gss_buffer_t                output_token;
     if (GSSINT_CHK_LOOP(ctx))
        return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
 
-    status = gssint_delete_internal_sec_context(minor_status,
-                                               ctx->mech_type,
-                                               &ctx->internal_ctx_id,
-                                               output_token);
-    if (status)
-       return status;
+    if (ctx->internal_ctx_id != GSS_C_NO_CONTEXT) {
+       status = gssint_delete_internal_sec_context(minor_status,
+                                                   ctx->mech_type,
+                                                   &ctx->internal_ctx_id,
+                                                   output_token);
+       if (status)
+           return status;
+    }
 
     /* now free up the space for the union context structure */
     free(ctx->mech_type->elements);
index b63745299f64dc4a75fd945e16311fed550a18fb..1d7990b1ca2871af8482b3d7e33a0f34147a2542 100644 (file)
@@ -95,6 +95,8 @@ gss_buffer_t          interprocess_token;
      */
 
     ctx = (gss_union_ctx_id_t) *context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
     if (!mech)
        return GSS_S_BAD_MECH;
index 9f154b8936d0f734cae15a503d0ae69101afbabd..e2df1ce261d758e47950542e2127daaaf9bb1930 100644 (file)
@@ -192,8 +192,13 @@ OM_uint32 *                time_rec;
 
        /* copy the supplied context handle */
        union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
-    } else
+    } else {
        union_ctx_id = (gss_union_ctx_id_t)*context_handle;
+       if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) {
+           status = GSS_S_NO_CONTEXT;
+           goto end;
+       }
+    }
 
     /*
      * get the appropriate cred handle from the union cred struct.
@@ -224,15 +229,13 @@ OM_uint32 *               time_rec;
 
     if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
        /*
-        * The spec says the preferred method is to delete all context info on
-        * the first call to init, and on all subsequent calls make the caller
-        * responsible for calling gss_delete_sec_context.  However, if the
-        * mechanism decided to delete the internal context, we should also
-        * delete the union context.
+        * RFC 2744 5.19 requires that we not create a context on a failed
+        * first call to init, and recommends that on a failed subsequent call
+        * we make the caller responsible for calling gss_delete_sec_context.
+        * Even if the mech deleted its context, keep the union context around
+        * for the caller to delete.
         */
        map_error(minor_status, mech);
-       if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
-           *context_handle = GSS_C_NO_CONTEXT;
        if (*context_handle == GSS_C_NO_CONTEXT) {
            free(union_ctx_id->mech_type->elements);
            free(union_ctx_id->mech_type);
index 6f1c71eede9d5f3fae041e9e0cafafd27bdd4c67..6c0d98dd3348dac76978694676cd70430e6c0a0b 100644 (file)
@@ -104,6 +104,8 @@ gss_inquire_context(
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech || !mech->gss_inquire_context || !mech->gss_display_name ||
index fcca3e44c4c0edac06e406128188d3219654a5e9..9e168adfe0d620bb6deb4454b5f699677b08f593 100644 (file)
@@ -59,6 +59,8 @@ gss_pseudo_random (OM_uint32 *minor_status,
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech != NULL) {
index bc260aeb10b2a5ebf2617bdcd7d293c14af32e9f..3968b5d9c675a72ec240be811ed8a2615055c4ef 100644 (file)
@@ -61,6 +61,8 @@ gss_buffer_t          token_buffer;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
index f17241c908915da3c7038a00acc50eb26a24823a..3db1ee095b394b56d6d7b3c2475ef66f8ff8bb72 100644 (file)
@@ -92,6 +92,8 @@ gss_wrap( OM_uint32 *minor_status,
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+        return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
@@ -226,6 +228,8 @@ gss_wrap_size_limit(OM_uint32  *minor_status,
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+        return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech)
index 86d641aa2e283b6af6ff26d2ebf5c3615014482a..03fbd8c01f3617b1ddd98b39a876e711ef9a0819 100644 (file)
@@ -94,6 +94,8 @@ gss_buffer_t          msg_token;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
index 3e8053c6e9afe317ac42b90d1e59c68f9fb71c65..c208635b676a8e410c805d8ead9ac991e7a69b13 100644 (file)
@@ -76,6 +76,8 @@ gss_qop_t *           qop_state;
      * call it.
      */
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
index e78bff2d3289bf09430a0a722f1415d0ba201ce7..0682bd8998203266386c054ae3d3c4338d91e99a 100644 (file)
@@ -186,6 +186,8 @@ gss_qop_t           *qop_state;
      * call it.
      */
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech)
index c0dd314b1be8b7325fc06a9bb9cb25f7759c848c..599be2c7b2fcd27324a1015f92de2eb9b70b4361 100644 (file)
@@ -89,6 +89,8 @@ int                   iov_count;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
@@ -128,6 +130,8 @@ gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
 
     /* Select the approprate underlying mechanism routine and call it. */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism(ctx->mech_type);
     if (mech == NULL)
        return GSS_S_BAD_MECH;
index 1578ae111092dd14569f7b53eb10fef6460ac519..8996fce8d59639acee59938b64288fc40f498120 100644 (file)
@@ -65,6 +65,8 @@ gss_qop_t *           qop_state;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
index 96cdf3ce6ab86242b3f70b6e3208e2cfc45e9c7c..7fe3b7b35bda5add95efe79c0e42075e8898bf67 100644 (file)
@@ -256,6 +256,8 @@ gss_buffer_t                output_message_buffer;
      * call it.
      */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
     if (!mech)
        return (GSS_S_BAD_MECH);
index 40cd98fc91cdf8c7acb23b9c9ef79c9b3269f177..14447c4ee1ada5810e9f841d440db1dd539a6e36 100644 (file)
@@ -93,6 +93,8 @@ int                   iov_count;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
@@ -151,6 +153,8 @@ int                 iov_count;
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
@@ -190,6 +194,8 @@ gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
 
     /* Select the approprate underlying mechanism routine and call it. */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism(ctx->mech_type);
     if (mech == NULL)
        return GSS_S_BAD_MECH;
@@ -218,6 +224,8 @@ gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
 
     /* Select the approprate underlying mechanism routine and call it. */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+       return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism(ctx->mech_type);
     if (mech == NULL)
        return GSS_S_BAD_MECH;