Skip to content

Commit ab69b71

Browse files
committed
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 <[email protected]> Reviewed-by: Nathaniel McCallum <[email protected]>
1 parent 8c09bbb commit ab69b71

File tree

5 files changed

+62
-39
lines changed

5 files changed

+62
-39
lines changed

proxy/src/client/gpm_accept_sec_context.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,6 @@ OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status,
116116
goto done;
117117
}
118118

119-
/* replace old ctx handle if any */
120-
if (*context_handle) {
121-
xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle);
122-
free(*context_handle);
123-
}
124-
*context_handle = ctx;
125119
if (mech_type) {
126120
*mech_type = mech;
127121
}
@@ -157,6 +151,7 @@ OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status,
157151
arg->context_handle = NULL;
158152
arg->cred_handle = NULL;
159153
gpm_free_xdrs(GSSX_ACCEPT_SEC_CONTEXT, &uarg, &ures);
154+
160155
if (ret) {
161156
if (ctx) {
162157
xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)ctx);
@@ -178,6 +173,13 @@ OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status,
178173
return GSS_S_FAILURE;
179174
}
180175

176+
/* always replace old ctx handle and set new */
177+
if (*context_handle) {
178+
xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle);
179+
free(*context_handle);
180+
}
181+
*context_handle = ctx;
182+
181183
return ret_maj;
182184
}
183185

proxy/src/client/gpm_init_sec_context.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,6 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status,
137137
gpm_free_xdrs(GSSX_INIT_SEC_CONTEXT, &uarg, &ures);
138138

139139
if (ret_maj == GSS_S_COMPLETE || ret_maj == GSS_S_CONTINUE_NEEDED) {
140-
/* replace old ctx handle if any */
141-
if (*context_handle) {
142-
xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle);
143-
free(*context_handle);
144-
}
145-
*context_handle = ctx;
146140
if (actual_mech_type) {
147141
*actual_mech_type = mech;
148142
}
@@ -171,6 +165,13 @@ OM_uint32 gpm_init_sec_context(OM_uint32 *minor_status,
171165
}
172166
}
173167

168+
/* always replace old ctx handle and set new */
169+
if (*context_handle) {
170+
xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle);
171+
free(*context_handle);
172+
}
173+
*context_handle = ctx;
174+
174175
*minor_status = ret_min;
175176
return ret_maj;
176177
}

proxy/src/mechglue/gpp_accept_sec_context.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,12 @@ OM_uint32 gssi_accept_sec_context(OM_uint32 *minor_status,
138138
done:
139139
*minor_status = gpp_map_error(min);
140140
if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
141-
free(ctx_handle);
141+
if (ctx_handle &&
142+
ctx_handle->local == GSS_C_NO_CONTEXT &&
143+
ctx_handle->remote == NULL) {
144+
free(ctx_handle);
145+
ctx_handle = NULL;
146+
}
142147
free(deleg_cred);
143148
free(name);
144149
} else {
@@ -148,8 +153,11 @@ OM_uint32 gssi_accept_sec_context(OM_uint32 *minor_status,
148153
if (delegated_cred_handle) {
149154
*delegated_cred_handle = (gss_cred_id_t)deleg_cred;
150155
}
151-
*context_handle = (gss_ctx_id_t)ctx_handle;
152156
}
157+
/* always replace the provided context handle to avoid
158+
* dangling pointers when a context has been passed in */
159+
*context_handle = (gss_ctx_id_t)ctx_handle;
160+
153161
if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
154162
(void)gssi_release_cred(&min, (gss_cred_id_t *)&cred_handle);
155163
}

proxy/src/mechglue/gpp_context.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,11 @@ OM_uint32 gssi_delete_sec_context(OM_uint32 *minor_status,
364364

365365
*context_handle = GSS_C_NO_CONTEXT;
366366

367+
if (ctx == NULL) {
368+
*minor_status = 0;
369+
return GSS_S_COMPLETE;
370+
}
371+
367372
if (ctx->local) {
368373
maj = gss_delete_sec_context(&min, &ctx->local, output_token);
369374
if (maj != GSS_S_COMPLETE) {

proxy/src/mechglue/gpp_init_sec_context.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,35 +91,18 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status,
9191

9292
GSSI_TRACE();
9393

94+
*minor_status = 0;
95+
9496
if (target_name == GSS_C_NO_NAME) {
9597
return GSS_S_CALL_INACCESSIBLE_READ;
9698
}
9799

98-
tmaj = GSS_S_COMPLETE;
99-
tmin = 0;
100-
101100
if (mech_type == GSS_C_NO_OID || gpp_is_special_oid(mech_type)) {
102-
maj = GSS_S_BAD_MECH;
103-
min = 0;
104-
goto done;
101+
return GSS_S_BAD_MECH;
105102
}
106103

107-
if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
108-
cred_handle = (struct gpp_cred_handle *)claimant_cred_handle;
109-
if (cred_handle->local) {
110-
/* ok this means a previous call decided to short circuit to the
111-
* local mech, so let's just re-enter the mechglue here, as we
112-
* have no way to export creds yet. */
113-
behavior = GPP_LOCAL_ONLY;
114-
}
115-
} else {
116-
cred_handle = calloc(1, sizeof(struct gpp_cred_handle));
117-
if (!cred_handle) {
118-
maj = GSS_S_FAILURE;
119-
min = ENOMEM;
120-
goto done;
121-
}
122-
}
104+
tmaj = GSS_S_COMPLETE;
105+
tmin = 0;
123106

124107
if (*context_handle) {
125108
ctx_handle = (struct gpp_context_handle *)*context_handle;
@@ -141,6 +124,23 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status,
141124
}
142125
}
143126

127+
if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
128+
cred_handle = (struct gpp_cred_handle *)claimant_cred_handle;
129+
if (cred_handle->local) {
130+
/* ok this means a previous call decided to short circuit to the
131+
* local mech, so let's just re-enter the mechglue here, as we
132+
* have no way to export creds yet. */
133+
behavior = GPP_LOCAL_ONLY;
134+
}
135+
} else {
136+
cred_handle = calloc(1, sizeof(struct gpp_cred_handle));
137+
if (!cred_handle) {
138+
maj = GSS_S_FAILURE;
139+
min = ENOMEM;
140+
goto done;
141+
}
142+
}
143+
144144
name = (struct gpp_name_handle *)target_name;
145145
behavior = gpp_get_behavior();
146146

@@ -205,11 +205,18 @@ OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status,
205205
min = tmin;
206206
}
207207
if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
208-
free(ctx_handle);
208+
if (ctx_handle &&
209+
ctx_handle->local == GSS_C_NO_CONTEXT &&
210+
ctx_handle->remote == NULL) {
211+
free(ctx_handle);
212+
ctx_handle = NULL;
213+
}
209214
*minor_status = gpp_map_error(min);
210-
} else {
211-
*context_handle = (gss_ctx_id_t)ctx_handle;
212215
}
216+
/* always replace the provided context handle to avoid
217+
* dangling pointers when a context has been passed in */
218+
*context_handle = (gss_ctx_id_t)ctx_handle;
219+
213220
if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
214221
free(cred_handle);
215222
}

0 commit comments

Comments
 (0)