| From 56f7b1bc95a2a3eeb420e069e7655fb181ade5cf 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 |
| |
| Upstream-Status: Backport |
| CVE: CVE-2017-11462 |
| |
| Signed-off-by: Catalin Enache <catalin.enache@windriver.com> |
| --- |
| 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 ddaf874..f28e2b1 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 9181551..4bcb47e 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 2ff8d09..c947e76 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 4bf0dec..574ff02 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 b637452..1d7990b 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 9f154b8..e2df1ce 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 6f1c71e..6c0d98d 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 fcca3e4..9e168ad 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 bc260ae..3968b5d 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 f17241c..3db1ee0 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 86d641a..03fbd8c 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 3e8053c..c208635 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 e78bff2..0682bd8 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 c0dd314..599be2c 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 1578ae1..8996fce 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 96cdf3c..7fe3b7b 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 40cd98f..14447c4 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; |
| -- |
| 2.10.2 |
| |