Code: acc_ctx_cont(OM_uint32 *minstat,
	     gss_buffer_t buf,
	     gss_ctx_id_t *ctx,
	     gss_buffer_t *responseToken,
	     gss_buffer_t *mechListMIC,
	     OM_uint32 *negState,
	     send_token_flag *return_token)
{
	OM_uint32 ret, tmpmin;
	gss_OID supportedMech;
	spnego_gss_ctx_id_t sc;
	unsigned int len;
	unsigned char *ptr, *bufstart;

	sc = (spnego_gss_ctx_id_t)*ctx;
	ret = GSS_S_DEFECTIVE_TOKEN;
	*negState = REJECT;
	*minstat = 0;
	supportedMech = GSS_C_NO_OID;
	*return_token = ERROR_TOKEN_SEND;
	*responseToken = *mechListMIC = GSS_C_NO_BUFFER;
 
 	ptr = bufstart = buf->value;
 #define REMAIN (buf->length - (ptr - bufstart))
	if (REMAIN > INT_MAX)
 		return GSS_S_DEFECTIVE_TOKEN;
 
 	/*
	 * Attempt to work with old Sun SPNEGO.
	 */
	if (*ptr == HEADER_ID) {
		ret = g_verify_token_header(gss_mech_spnego,
					    &len, &ptr, 0, REMAIN);
		if (ret) {
			*minstat = ret;
			return GSS_S_DEFECTIVE_TOKEN;
		}
	}
	if (*ptr != (CONTEXT | 0x01)) {
		return GSS_S_DEFECTIVE_TOKEN;
	}
	ret = get_negTokenResp(minstat, ptr, REMAIN,
			       negState, &supportedMech,
			       responseToken, mechListMIC);
	if (ret != GSS_S_COMPLETE)
		goto cleanup;

	if (*responseToken == GSS_C_NO_BUFFER &&
	    *mechListMIC == GSS_C_NO_BUFFER) {

		ret = GSS_S_DEFECTIVE_TOKEN;
		goto cleanup;
	}
	if (supportedMech != GSS_C_NO_OID) {
		ret = GSS_S_DEFECTIVE_TOKEN;
		goto cleanup;
	}
	sc->firstpass = 0;
	*negState = ACCEPT_INCOMPLETE;
	*return_token = CONT_TOKEN_SEND;
cleanup:
	if (supportedMech != GSS_C_NO_OID) {
		generic_gss_release_oid(&tmpmin, &supportedMech);
	}
	return ret;
#undef REMAIN
}

Commit Message: Fix null deref in SPNEGO acceptor [CVE-2014-4344]

When processing a continuation token, acc_ctx_cont was dereferencing
the initial byte of the token without checking the length.  This could
result in a null dereference.

CVE-2014-4344:

In MIT krb5 1.5 and newer, an unauthenticated or partially
authenticated remote attacker can cause a NULL dereference and
application crash during a SPNEGO negotiation by sending an empty
token as the second or later context token from initiator to acceptor.
The attacker must provide at least one valid context token in the
security context negotiation before sending the empty token.  This can
be done by an unauthenticated attacker by forcing SPNEGO to
renegotiate the underlying mechanism, or by using IAKERB to wrap an
unauthenticated AS-REQ as the first token.

    CVSSv2 Vector: AV:N/AC:L/Au:N/C:N/I:N/A:C/E:POC/RL:OF/RC:C

[kaduk@mit.edu: CVE summary, CVSSv2 vector]

(cherry picked from commit 524688ce87a15fc75f87efc8c039ba4c7d5c197b)

ticket: 7970
version_fixed: 1.12.2
status: resolved
CWE ID: CWE-476
acc_ctx_cont(OM_uint32 *minstat,
	     gss_buffer_t buf,
	     gss_ctx_id_t *ctx,
	     gss_buffer_t *responseToken,
	     gss_buffer_t *mechListMIC,
	     OM_uint32 *negState,
	     send_token_flag *return_token)
{
	OM_uint32 ret, tmpmin;
	gss_OID supportedMech;
	spnego_gss_ctx_id_t sc;
	unsigned int len;
	unsigned char *ptr, *bufstart;

	sc = (spnego_gss_ctx_id_t)*ctx;
	ret = GSS_S_DEFECTIVE_TOKEN;
	*negState = REJECT;
	*minstat = 0;
	supportedMech = GSS_C_NO_OID;
	*return_token = ERROR_TOKEN_SEND;
	*responseToken = *mechListMIC = GSS_C_NO_BUFFER;
 
 	ptr = bufstart = buf->value;
 #define REMAIN (buf->length - (ptr - bufstart))
	if (REMAIN == 0 || REMAIN > INT_MAX)
 		return GSS_S_DEFECTIVE_TOKEN;
 
 	/*
	 * Attempt to work with old Sun SPNEGO.
	 */
	if (*ptr == HEADER_ID) {
		ret = g_verify_token_header(gss_mech_spnego,
					    &len, &ptr, 0, REMAIN);
		if (ret) {
			*minstat = ret;
			return GSS_S_DEFECTIVE_TOKEN;
		}
	}
	if (*ptr != (CONTEXT | 0x01)) {
		return GSS_S_DEFECTIVE_TOKEN;
	}
	ret = get_negTokenResp(minstat, ptr, REMAIN,
			       negState, &supportedMech,
			       responseToken, mechListMIC);
	if (ret != GSS_S_COMPLETE)
		goto cleanup;

	if (*responseToken == GSS_C_NO_BUFFER &&
	    *mechListMIC == GSS_C_NO_BUFFER) {

		ret = GSS_S_DEFECTIVE_TOKEN;
		goto cleanup;
	}
	if (supportedMech != GSS_C_NO_OID) {
		ret = GSS_S_DEFECTIVE_TOKEN;
		goto cleanup;
	}
	sc->firstpass = 0;
	*negState = ACCEPT_INCOMPLETE;
	*return_token = CONT_TOKEN_SEND;
cleanup:
	if (supportedMech != GSS_C_NO_OID) {
		generic_gss_release_oid(&tmpmin, &supportedMech);
	}
	return ret;
#undef REMAIN
}
