diff options
| author | Simo Sorce <simo@redhat.com> | 2015-02-26 15:49:59 -0500 |
|---|---|---|
| committer | Simo Sorce <simo@redhat.com> | 2015-03-24 11:49:25 -0400 |
| commit | ab69b71fcf9187269058b4e1ff7b394cc37f19da (patch) | |
| tree | be7d8e110a179b59bf6895d27994df649ae32453 /proxy/src/mechglue | |
| parent | 8c09bbb82f3578401a0dbd0c64ca36c8483295fb (diff) | |
| download | gss-proxy-ab69b71fcf9187269058b4e1ff7b394cc37f19da.tar.gz gss-proxy-ab69b71fcf9187269058b4e1ff7b394cc37f19da.tar.xz gss-proxy-ab69b71fcf9187269058b4e1ff7b394cc37f19da.zip | |
Properly handle security contexts on error
On error we need to make sure we do not return a pointer to a
security context that may have been already freed.
So make sure to always unconditionally return the context that we've
been returned by our callees.
Also reorganize the code so we do not accidently wipe the context
and leak memoy on error.
This fixed a double-free bug found by NFS folks @ Red Hat
Fixes: https://fedorahosted.org/gss-proxy/ticket/137
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Nathaniel McCallum <npmccallum@redhat.com>
Diffstat (limited to 'proxy/src/mechglue')
| -rw-r--r-- | proxy/src/mechglue/gpp_accept_sec_context.c | 12 | ||||
| -rw-r--r-- | proxy/src/mechglue/gpp_context.c | 5 | ||||
| -rw-r--r-- | proxy/src/mechglue/gpp_init_sec_context.c | 57 |
3 files changed, 47 insertions, 27 deletions
diff --git a/proxy/src/mechglue/gpp_accept_sec_context.c b/proxy/src/mechglue/gpp_accept_sec_context.c index d91728e..a40f23b 100644 --- a/proxy/src/mechglue/gpp_accept_sec_context.c +++ b/proxy/src/mechglue/gpp_accept_sec_context.c @@ -138,7 +138,12 @@ OM_uint32 gssi_accept_sec_context(OM_uint32 *minor_status, done: *minor_status = gpp_map_error(min); if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) { - free(ctx_handle); + if (ctx_handle && + ctx_handle->local == GSS_C_NO_CONTEXT && + ctx_handle->remote == NULL) { + free(ctx_handle); + ctx_handle = NULL; + } free(deleg_cred); free(name); } else { @@ -148,8 +153,11 @@ done: if (delegated_cred_handle) { *delegated_cred_handle = (gss_cred_id_t)deleg_cred; } - *context_handle = (gss_ctx_id_t)ctx_handle; } + /* always replace the provided context handle to avoid + * dangling pointers when a context has been passed in */ + *context_handle = (gss_ctx_id_t)ctx_handle; + if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) { (void)gssi_release_cred(&min, (gss_cred_id_t *)&cred_handle); } diff --git a/proxy/src/mechglue/gpp_context.c b/proxy/src/mechglue/gpp_context.c index bb16a93..83272b3 100644 --- a/proxy/src/mechglue/gpp_context.c +++ b/proxy/src/mechglue/gpp_context.c @@ -364,6 +364,11 @@ OM_uint32 gssi_delete_sec_context(OM_uint32 *minor_status, *context_handle = GSS_C_NO_CONTEXT; + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_COMPLETE; + } + if (ctx->local) { maj = gss_delete_sec_context(&min, &ctx->local, output_token); if (maj != GSS_S_COMPLETE) { diff --git a/proxy/src/mechglue/gpp_init_sec_context.c b/proxy/src/mechglue/gpp_init_sec_context.c index e70e8fc..c80937c 100644 --- a/proxy/src/mechglue/gpp_init_sec_context.c +++ b/proxy/src/mechglue/gpp_init_sec_context.c @@ -91,35 +91,18 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, GSSI_TRACE(); + *minor_status = 0; + if (target_name == GSS_C_NO_NAME) { return GSS_S_CALL_INACCESSIBLE_READ; } - tmaj = GSS_S_COMPLETE; - tmin = 0; - if (mech_type == GSS_C_NO_OID || gpp_is_special_oid(mech_type)) { - maj = GSS_S_BAD_MECH; - min = 0; - goto done; + return GSS_S_BAD_MECH; } - if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { - cred_handle = (struct gpp_cred_handle *)claimant_cred_handle; - if (cred_handle->local) { - /* ok this means a previous call decided to short circuit to the - * local mech, so let's just re-enter the mechglue here, as we - * have no way to export creds yet. */ - behavior = GPP_LOCAL_ONLY; - } - } else { - cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); - if (!cred_handle) { - maj = GSS_S_FAILURE; - min = ENOMEM; - goto done; - } - } + tmaj = GSS_S_COMPLETE; + tmin = 0; if (*context_handle) { ctx_handle = (struct gpp_context_handle *)*context_handle; @@ -141,6 +124,23 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status, } } + if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { + cred_handle = (struct gpp_cred_handle *)claimant_cred_handle; + if (cred_handle->local) { + /* ok this means a previous call decided to short circuit to the + * local mech, so let's just re-enter the mechglue here, as we + * have no way to export creds yet. */ + behavior = GPP_LOCAL_ONLY; + } + } else { + cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); + if (!cred_handle) { + maj = GSS_S_FAILURE; + min = ENOMEM; + goto done; + } + } + name = (struct gpp_name_handle *)target_name; behavior = gpp_get_behavior(); @@ -205,11 +205,18 @@ done: min = tmin; } if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) { - free(ctx_handle); + if (ctx_handle && + ctx_handle->local == GSS_C_NO_CONTEXT && + ctx_handle->remote == NULL) { + free(ctx_handle); + ctx_handle = NULL; + } *minor_status = gpp_map_error(min); - } else { - *context_handle = (gss_ctx_id_t)ctx_handle; } + /* always replace the provided context handle to avoid + * dangling pointers when a context has been passed in */ + *context_handle = (gss_ctx_id_t)ctx_handle; + if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { free(cred_handle); } |
