Sophie

Sophie

distrib > Mageia > 6 > armv7hl > media > core-updates-src > by-pkgid > 538713f8a1b3f8c75dbb10494ade1d5f > files > 8

krb5-1.15.1-2.4.mga6.src.rpm

From d730a62c2d3f6f75a0fa28b7a8c952fb29dd7aa0 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 14 Jul 2017 13:02:46 -0400
Subject: [PATCH] Preserve GSS context on init/accept failure

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

(cherry picked from commit 56f7b1bc95a2a3eeb420e069e7655fb181ade5cf)
---
 src/lib/gssapi/mechglue/g_accept_sec_context.c  | 22 +++++++++++++++-------
 src/lib/gssapi/mechglue/g_complete_auth_token.c |  2 ++
 src/lib/gssapi/mechglue/g_context_time.c        |  2 ++
 src/lib/gssapi/mechglue/g_delete_sec_context.c  | 14 ++++++++------
 src/lib/gssapi/mechglue/g_exp_sec_context.c     |  2 ++
 src/lib/gssapi/mechglue/g_init_sec_context.c    | 19 +++++++++++--------
 src/lib/gssapi/mechglue/g_inq_context.c         |  2 ++
 src/lib/gssapi/mechglue/g_prf.c                 |  2 ++
 src/lib/gssapi/mechglue/g_process_context.c     |  2 ++
 src/lib/gssapi/mechglue/g_seal.c                |  4 ++++
 src/lib/gssapi/mechglue/g_sign.c                |  2 ++
 src/lib/gssapi/mechglue/g_unseal.c              |  2 ++
 src/lib/gssapi/mechglue/g_unwrap_aead.c         |  2 ++
 src/lib/gssapi/mechglue/g_unwrap_iov.c          |  4 ++++
 src/lib/gssapi/mechglue/g_verify.c              |  2 ++
 src/lib/gssapi/mechglue/g_wrap_aead.c           |  2 ++
 src/lib/gssapi/mechglue/g_wrap_iov.c            |  8 ++++++++
 17 files changed, 72 insertions(+), 21 deletions(-)

diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c
index ddaf87412..f28e2b14a 100644
--- a/src/lib/gssapi/mechglue/g_accept_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c
@@ -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)
diff --git a/src/lib/gssapi/mechglue/g_complete_auth_token.c b/src/lib/gssapi/mechglue/g_complete_auth_token.c
index 918155130..4bcb47e84 100644
--- a/src/lib/gssapi/mechglue/g_complete_auth_token.c
+++ b/src/lib/gssapi/mechglue/g_complete_auth_token.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_context_time.c b/src/lib/gssapi/mechglue/g_context_time.c
index 2ff8d0996..c947e7646 100644
--- a/src/lib/gssapi/mechglue/g_context_time.c
+++ b/src/lib/gssapi/mechglue/g_context_time.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c
index 4bf0dec5c..574ff0294 100644
--- a/src/lib/gssapi/mechglue/g_delete_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c
@@ -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);
diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c
index b63745299..1d7990b1c 100644
--- a/src/lib/gssapi/mechglue/g_exp_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c
@@ -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;
diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c
index 9f154b893..e2df1ce26 100644
--- a/src/lib/gssapi/mechglue/g_init_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_init_sec_context.c
@@ -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);
diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c
index 6f1c71eed..6c0d98dd3 100644
--- a/src/lib/gssapi/mechglue/g_inq_context.c
+++ b/src/lib/gssapi/mechglue/g_inq_context.c
@@ -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 ||
diff --git a/src/lib/gssapi/mechglue/g_prf.c b/src/lib/gssapi/mechglue/g_prf.c
index fcca3e44c..9e168adfe 100644
--- a/src/lib/gssapi/mechglue/g_prf.c
+++ b/src/lib/gssapi/mechglue/g_prf.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c
index bc260aeb1..3968b5d9c 100644
--- a/src/lib/gssapi/mechglue/g_process_context.c
+++ b/src/lib/gssapi/mechglue/g_process_context.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c
index f17241c90..3db1ee095 100644
--- a/src/lib/gssapi/mechglue/g_seal.c
+++ b/src/lib/gssapi/mechglue/g_seal.c
@@ -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)
diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c
index 86d641aa2..03fbd8c01 100644
--- a/src/lib/gssapi/mechglue/g_sign.c
+++ b/src/lib/gssapi/mechglue/g_sign.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c
index 3e8053c6e..c208635b6 100644
--- a/src/lib/gssapi/mechglue/g_unseal.c
+++ b/src/lib/gssapi/mechglue/g_unseal.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_unwrap_aead.c b/src/lib/gssapi/mechglue/g_unwrap_aead.c
index e78bff2d3..0682bd899 100644
--- a/src/lib/gssapi/mechglue/g_unwrap_aead.c
+++ b/src/lib/gssapi/mechglue/g_unwrap_aead.c
@@ -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)
diff --git a/src/lib/gssapi/mechglue/g_unwrap_iov.c b/src/lib/gssapi/mechglue/g_unwrap_iov.c
index c0dd314b1..599be2c7b 100644
--- a/src/lib/gssapi/mechglue/g_unwrap_iov.c
+++ b/src/lib/gssapi/mechglue/g_unwrap_iov.c
@@ -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;
diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c
index 1578ae111..8996fce8d 100644
--- a/src/lib/gssapi/mechglue/g_verify.c
+++ b/src/lib/gssapi/mechglue/g_verify.c
@@ -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) {
diff --git a/src/lib/gssapi/mechglue/g_wrap_aead.c b/src/lib/gssapi/mechglue/g_wrap_aead.c
index 96cdf3ce6..7fe3b7b35 100644
--- a/src/lib/gssapi/mechglue/g_wrap_aead.c
+++ b/src/lib/gssapi/mechglue/g_wrap_aead.c
@@ -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);
diff --git a/src/lib/gssapi/mechglue/g_wrap_iov.c b/src/lib/gssapi/mechglue/g_wrap_iov.c
index 40cd98fc9..14447c4ee 100644
--- a/src/lib/gssapi/mechglue/g_wrap_iov.c
+++ b/src/lib/gssapi/mechglue/g_wrap_iov.c
@@ -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;