Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
greghudson committed Aug 28, 2017
1 parent a96ac7f commit 56f7b1b
Show file tree
Hide file tree
Showing 17 changed files with 72 additions and 21 deletions.
22 changes: 15 additions & 7 deletions src/lib/gssapi/mechglue/g_accept_sec_context.c
Expand Up @@ -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. */
Expand All @@ -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;
}

/*
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -384,7 +393,6 @@ gss_cred_id_t * d_cred;
GSS_C_NO_BUFFER);
}
free(union_ctx_id);
*context_handle = GSS_C_NO_CONTEXT;
}

if (src_name)
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_complete_auth_token.c
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_context_time.c
Expand Up @@ -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) {
Expand Down
14 changes: 8 additions & 6 deletions src/lib/gssapi/mechglue/g_delete_sec_context.c
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_exp_sec_context.c
Expand Up @@ -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;
Expand Down
19 changes: 11 additions & 8 deletions src/lib/gssapi/mechglue/g_init_sec_context.c
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_inq_context.c
Expand Up @@ -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 ||
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_prf.c
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_process_context.c
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/gssapi/mechglue/g_seal.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_sign.c
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_unseal.c
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_unwrap_aead.c
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions src/lib/gssapi/mechglue/g_unwrap_iov.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_verify.c
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/gssapi/mechglue/g_wrap_aead.c
Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions src/lib/gssapi/mechglue/g_wrap_iov.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 56f7b1b

Please sign in to comment.