]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Fix gss_process_context_token() [CVE-2014-5352]
authorGreg Hudson <ghudson@mit.edu>
Wed, 5 Nov 2014 16:58:04 +0000 (11:58 -0500)
committerGreg Hudson <ghudson@mit.edu>
Wed, 4 Feb 2015 19:26:15 +0000 (14:26 -0500)
[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.

ticket: 8055 (new)
target_version: 1.13.1
tags: pullup

14 files changed:
src/lib/gssapi/krb5/context_time.c
src/lib/gssapi/krb5/export_sec_context.c
src/lib/gssapi/krb5/gssapiP_krb5.h
src/lib/gssapi/krb5/gssapi_krb5.c
src/lib/gssapi/krb5/inq_context.c
src/lib/gssapi/krb5/k5seal.c
src/lib/gssapi/krb5/k5sealiov.c
src/lib/gssapi/krb5/k5unseal.c
src/lib/gssapi/krb5/k5unsealiov.c
src/lib/gssapi/krb5/lucid_context.c
src/lib/gssapi/krb5/prf.c
src/lib/gssapi/krb5/process_context_token.c
src/lib/gssapi/krb5/wrap_size_limit.c
src/tests/gssapi/t_prf.c

index b3d1db00759939fb5305deaf3775f9dad4512ca4..a18cfb05b743fbccf68dc52e203ebc050c7e6509 100644 (file)
@@ -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);
     }
index 18a3a34cf6be43d5accb4eae8db6632567986fda..1b3de6818867808218236666b5f1f6c63f3f8e62 100644 (file)
@@ -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)
index 7e807cc059835baa61373ca8d590cdfa576b4232..a0e8625d05b6de7e37ba5f4c9adbb15ef352d400 100644 (file)
@@ -206,6 +206,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;
index 6456b238e4e366131cd1bdc60fc947ab1791c7d1..77b7fff026a2d9f0602cd73b2cdf4f53929da999 100644 (file)
@@ -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)/
index eacb0fd378aea2cbec7849f7c38b98418662102b..096df2a895540ce07fa6f5bc5d9a9484fe616fc4 100644 (file)
@@ -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);
     }
index 7665cbae98ecd1ef757dc3f6ff9dd6926d6e8723..f1c74dd52239a6216b4eb67eaf7ac58021b99abf 100644 (file)
@@ -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);
     }
index a1296700ec28b2e22095c54198496c436d584729..b53e348f09e5d7b0b2013c6deafacd1f57f44c67 100644 (file)
@@ -281,7 +281,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;
     }
index 057395878763b735ee555501e579ddcd1652affc..673c883e633ec557220009b37b9fae910ea14a7f 100644 (file)
@@ -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);
     }
index f34d802bd93cefd6a98766a6755c9f49b8f7b8df..8b6704274db847c8e7a7f26b798ea721e10eeb73 100644 (file)
@@ -625,7 +625,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;
     }
index 85df7fda594bb889f0c0a5a6daeea4f9e9dff101..449e71fed4c71813ab15fe2442ddefc91b1cc78e 100644 (file)
@@ -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,
index e19291f3486993411080188761f13bcd9f6f543b..e897074fc1936643bee2f2a21f5c2b507e696769 100644 (file)
@@ -58,6 +58,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:
index ae33180a7508e45c6e2d0ea1b20ff4319f4cd2b0..a672f48c859b9f87b275e54523e161a482997cdc 100644 (file)
@@ -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);
 }
index 7bc4221daf4c20ed0e3c1a67e37f2e0d4a33bea9..ed5c599951d49b42602052190a99e3841d120bb5 100644 (file)
@@ -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);
     }
index 254f8fb5ebe61644b07aec2deb5163a4e0c4601c..7f0489995ed5bd4dc574fb1a8a95cc874df1c0af 100644 (file)
@@ -127,6 +127,7 @@ main(int argc, char *argv[])
     uctx.mech_type = &mech_krb5;
     uctx.internal_ctx_id = (gss_ctx_id_t)&kgctx;
     kgctx.k5_context = NULL;
+    kgctx.established = 1;
     kgctx.have_acceptor_subkey = 1;
     kb1.contents = k1buf;
     kb2.contents = k2buf;