]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Fix gss_process_context_token() [CVE-2014-5352]
authorTom Yu <tlyu@mit.edu>
Wed, 4 Feb 2015 21:09:16 +0000 (16:09 -0500)
committerTom Yu <tlyu@mit.edu>
Wed, 4 Feb 2015 22:21:14 +0000 (17:21 -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: 8067 (new)
version_fixed: 1.12.3
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 01678168f020203ccc98910c93a301b1404a3b0c..42d16ad4bf21e69dd24e7b9a03c269cfe5ec2e47 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 a408259cfbbe8f313335a78b8e0ac5cc76b4f2f1..088219a5c9cb9f4924dc5b646d9ebdf36307d1cb 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 0b99a77e954fd0a0a592a5ced401afc0dae46ea0..0f80095d04c0a64df658907590911e0c7861046a 100644 (file)
@@ -284,7 +284,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 b65c83ca7ca60c6befe9af990f2b72c4c70eea42..9e785500b74a76c668f3b2830d7c8969c655ca1e 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 8d6a2dacffb1f9aaf0dd66abf2932e724a2c9084..191de2cff1e0fec5c973a079ed216d841161b7c3 100644 (file)
@@ -628,7 +628,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);
     }