]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Fix gss_process_context_token() [CVE-2014-5352]
authorTom Yu <tlyu@mit.edu>
Fri, 6 Feb 2015 20:46:52 +0000 (15:46 -0500)
committerTom Yu <tlyu@mit.edu>
Fri, 6 Feb 2015 23:34:55 +0000 (18:34 -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.

(back ported from commit 82dc33da50338ac84c7b4102dc6513d897d0506a)

ticket: 8073 (new)
version_fixed: 1.11.6
status: resolved

13 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

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 8215b10f00912a72bda851c171d00ff7bf8eab8a..2b932334a24d7436f3a19f5fe3d2360630fe3bc5 100644 (file)
@@ -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;
index 31f705d8249afc554add8c27523cd85fffb0de58..3238108cf4db980466e19e5009d808b210f794c5 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 bd1e2a6d0628e14eed551ab8b2333e5ea55f1ad7..b11b6150f72807022b845afeef12fe94c6d5f4c1 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 3dafd1f5f9b98b828863c8f1097e3459c7fcfd6a..86f6e2f5651fbb716e5144da6c5cef6c69476db0 100644 (file)
@@ -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;
     }
index a6d456d4339e32c8f0d647702bc5ee8b8b8b6011..8c37f8016e0fa15a0b539e449265179862af6467 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 9f7f8804847b2287334df9c7a012754315c25615..d0aa64602f8a4ccae86d5c1d5f19405d97695584 100644 (file)
@@ -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;
     }
index dc129e15e7cd6d2c8ae687de19c2bbe2be7c8103..50d8cc91505efd7b904a9b3eaf161be144e304ae 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 a0fbcdab0fa67db3180f8d65187d12a1f4a96813..4831f9f36eae8f3914f0a43ff439eb26c484aeca 100644 (file)
@@ -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:
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);
     }