krb5 commit [krb5-1.11]: Fix gss_process_context_token() [CVE-2014-5352]

Tom Yu tlyu at mit.edu
Fri Feb 6 18:58:50 EST 2015


https://github.com/krb5/krb5/commit/3cb9368472ba824bbaefad5e88006769fbc097e8
commit 3cb9368472ba824bbaefad5e88006769fbc097e8
Author: Tom Yu <tlyu at mit.edu>
Date:   Fri Feb 6 15:46:52 2015 -0500

    Fix gss_process_context_token() [CVE-2014-5352]
    
    [MITKRB5-SA-2015-001] The krb5 gss_process_context_token() should not
    actually delete the context; that leaves the caller with a dangling
    pointer and no way to know that it is invalid.  Instead, mark the
    context as terminated, and check for terminated contexts in the GSS
    functions which expect established contexts.  Also add checks in
    export_sec_context and pseudo_random, and adjust t_prf.c for the
    pseudo_random check.
    
    (back ported from commit 82dc33da50338ac84c7b4102dc6513d897d0506a)
    
    ticket: 8073 (new)
    version_fixed: 1.11.6
    status: resolved

 src/lib/gssapi/krb5/context_time.c          |    2 +-
 src/lib/gssapi/krb5/export_sec_context.c    |    5 +++++
 src/lib/gssapi/krb5/gssapiP_krb5.h          |    1 +
 src/lib/gssapi/krb5/gssapi_krb5.c           |    2 +-
 src/lib/gssapi/krb5/inq_context.c           |    2 +-
 src/lib/gssapi/krb5/k5seal.c                |    2 +-
 src/lib/gssapi/krb5/k5sealiov.c             |    2 +-
 src/lib/gssapi/krb5/k5unseal.c              |    2 +-
 src/lib/gssapi/krb5/k5unsealiov.c           |    2 +-
 src/lib/gssapi/krb5/lucid_context.c         |    5 +++++
 src/lib/gssapi/krb5/prf.c                   |    4 ++++
 src/lib/gssapi/krb5/process_context_token.c |   17 ++++++++++++-----
 src/lib/gssapi/krb5/wrap_size_limit.c       |    2 +-
 13 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c
index b3d1db0..a18cfb0 100644
--- a/src/lib/gssapi/krb5/context_time.c
+++ b/src/lib/gssapi/krb5/context_time.c
@@ -40,7 +40,7 @@ krb5_gss_context_time(minor_status, context_handle, time_rec)
 
     ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-    if (! ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return(GSS_S_NO_CONTEXT);
     }
diff --git a/src/lib/gssapi/krb5/export_sec_context.c b/src/lib/gssapi/krb5/export_sec_context.c
index 18a3a34..1b3de68 100644
--- a/src/lib/gssapi/krb5/export_sec_context.c
+++ b/src/lib/gssapi/krb5/export_sec_context.c
@@ -45,6 +45,11 @@ krb5_gss_export_sec_context(minor_status, context_handle, interprocess_token)
     *minor_status = 0;
 
     ctx = (krb5_gss_ctx_id_t) *context_handle;
+    if (ctx->terminated) {
+        *minor_status = KG_CTX_INCOMPLETE;
+        return (GSS_S_NO_CONTEXT);
+    }
+
     context = ctx->k5_context;
     kret = krb5_gss_ser_init(context);
     if (kret)
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 8215b10..2b93233 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -204,6 +204,7 @@ typedef struct _krb5_gss_ctx_id_rec {
     unsigned int established : 1;
     unsigned int have_acceptor_subkey : 1;
     unsigned int seed_init : 1;  /* XXX tested but never actually set */
+    unsigned int terminated : 1;
     OM_uint32 gss_flags;
     unsigned char seed[16];
     krb5_gss_name_t here;
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 31f705d..3238108 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -369,7 +369,7 @@ krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
 
     ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-    if (!ctx->established)
+    if (ctx->terminated || !ctx->established)
         return GSS_S_NO_CONTEXT;
 
     for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
index eacb0fd..096df2a 100644
--- a/src/lib/gssapi/krb5/inq_context.c
+++ b/src/lib/gssapi/krb5/inq_context.c
@@ -105,7 +105,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name,
 
     ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-    if (! ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return(GSS_S_NO_CONTEXT);
     }
diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c
index bd1e2a6..b11b615 100644
--- a/src/lib/gssapi/krb5/k5seal.c
+++ b/src/lib/gssapi/krb5/k5seal.c
@@ -342,7 +342,7 @@ kg_seal(minor_status, context_handle, conf_req_flag, qop_req,
 
     ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-    if (! ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return(GSS_S_NO_CONTEXT);
     }
diff --git a/src/lib/gssapi/krb5/k5sealiov.c b/src/lib/gssapi/krb5/k5sealiov.c
index 3dafd1f..86f6e2f 100644
--- a/src/lib/gssapi/krb5/k5sealiov.c
+++ b/src/lib/gssapi/krb5/k5sealiov.c
@@ -285,7 +285,7 @@ kg_seal_iov(OM_uint32 *minor_status,
     }
 
     ctx = (krb5_gss_ctx_id_rec *)context_handle;
-    if (!ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return GSS_S_NO_CONTEXT;
     }
diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c
index a6d456d..8c37f80 100644
--- a/src/lib/gssapi/krb5/k5unseal.c
+++ b/src/lib/gssapi/krb5/k5unseal.c
@@ -492,7 +492,7 @@ kg_unseal(minor_status, context_handle, input_token_buffer,
 
     ctx = (krb5_gss_ctx_id_rec *) context_handle;
 
-    if (! ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return(GSS_S_NO_CONTEXT);
     }
diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
index 9f7f880..d0aa646 100644
--- a/src/lib/gssapi/krb5/k5unsealiov.c
+++ b/src/lib/gssapi/krb5/k5unsealiov.c
@@ -633,7 +633,7 @@ kg_unseal_iov(OM_uint32 *minor_status,
     OM_uint32 code;
 
     ctx = (krb5_gss_ctx_id_rec *)context_handle;
-    if (!ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return GSS_S_NO_CONTEXT;
     }
diff --git a/src/lib/gssapi/krb5/lucid_context.c b/src/lib/gssapi/krb5/lucid_context.c
index dc129e1..50d8cc9 100644
--- a/src/lib/gssapi/krb5/lucid_context.c
+++ b/src/lib/gssapi/krb5/lucid_context.c
@@ -75,6 +75,11 @@ gss_krb5int_export_lucid_sec_context(
     *minor_status = 0;
     *data_set = GSS_C_NO_BUFFER_SET;
 
+    if (ctx->terminated || !ctx->established) {
+        *minor_status = KG_CTX_INCOMPLETE;
+        return GSS_S_NO_CONTEXT;
+    }
+
     retval = generic_gss_oid_decompose(minor_status,
                                        GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID,
                                        GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH,
diff --git a/src/lib/gssapi/krb5/prf.c b/src/lib/gssapi/krb5/prf.c
index a0fbcda..4831f9f 100644
--- a/src/lib/gssapi/krb5/prf.c
+++ b/src/lib/gssapi/krb5/prf.c
@@ -60,6 +60,10 @@ krb5_gss_pseudo_random(OM_uint32 *minor_status,
     ns.data = NULL;
 
     ctx = (krb5_gss_ctx_id_t)context;
+    if (ctx->terminated || !ctx->established) {
+        *minor_status = KG_CTX_INCOMPLETE;
+        return GSS_S_NO_CONTEXT;
+    }
 
     switch (prf_key) {
     case GSS_C_PRF_KEY_FULL:
diff --git a/src/lib/gssapi/krb5/process_context_token.c b/src/lib/gssapi/krb5/process_context_token.c
index ae33180..a672f48 100644
--- a/src/lib/gssapi/krb5/process_context_token.c
+++ b/src/lib/gssapi/krb5/process_context_token.c
@@ -39,11 +39,18 @@ krb5_gss_process_context_token(minor_status, context_handle,
 
     ctx = (krb5_gss_ctx_id_t) context_handle;
 
-    if (! ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return(GSS_S_NO_CONTEXT);
     }
 
+    /* We only support context deletion tokens for now, and RFC 4121 does not
+     * define a context deletion token. */
+    if (ctx->proto) {
+        *minor_status = 0;
+        return(GSS_S_DEFECTIVE_TOKEN);
+    }
+
     /* "unseal" the token */
 
     if (GSS_ERROR(majerr = kg_unseal(minor_status, context_handle,
@@ -52,8 +59,8 @@ krb5_gss_process_context_token(minor_status, context_handle,
                                      KG_TOK_DEL_CTX)))
         return(majerr);
 
-    /* that's it.  delete the context */
-
-    return(krb5_gss_delete_sec_context(minor_status, &context_handle,
-                                       GSS_C_NO_BUFFER));
+    /* Mark the context as terminated, but do not delete it (as that would
+     * leave the caller with a dangling context handle). */
+    ctx->terminated = 1;
+    return(GSS_S_COMPLETE);
 }
diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c
index 7bc4221..ed5c599 100644
--- a/src/lib/gssapi/krb5/wrap_size_limit.c
+++ b/src/lib/gssapi/krb5/wrap_size_limit.c
@@ -95,7 +95,7 @@ krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
     }
 
     ctx = (krb5_gss_ctx_id_rec *) context_handle;
-    if (! ctx->established) {
+    if (ctx->terminated || !ctx->established) {
         *minor_status = KG_CTX_INCOMPLETE;
         return(GSS_S_NO_CONTEXT);
     }


More information about the cvs-krb5 mailing list