From f06b4eaae325224259009e7c7c64333ff1988e54 Mon Sep 17 00:00:00 2001
From: Nicolas Williams <nico@twosigma.com>
Date: Wed, 9 Mar 2022 10:18:52 -0600
Subject: [PATCH] spnego: CVE-2021-44758 send_reject when no mech selected

This fixes a DoS where an initial SPNEGO token that has no acceptable
mechanisms causes a NULL dereference in acceptors.

send_accept() when called with a non-zero 'initial_response' did
not handle the case of gssspnego_ctx.preferred_mech_type equal
to GSS_C_NO_OID.

The failure to handle GSS_C_NO_OID has been present since the
initial revision of gssapi/spnego,
2baa7e7d613c26b2b037b368931519a84baec53d but might not have
been exercised until later revisions.

The introduction of opportunistic token handling in
gss_accept_sec_context(), 3c9d3266f47f594a29068c9d629908e7000ac663,
introduced two bugs:

 1. The optional mechToken field is used unconditionally
    possibly resulting in a segmentation fault.

 2. If use of the opportunistic token is unsuccessful and the
    mech type list length is one, send_accept() can be called
    with 'initial_response' true and preferred mech set to
    GSS_C_NO_OID.

b53c90da0890a9cce6f95c552f094ff6d69027bf ("Make error reporting
somewhat more correct for SPNEGO") attempted to fix the first
issue and increased the likelihood of the second.

This change alters the behavior of acceptor_start() so it calls
send_reject() when no mechanism was selected.
---
 lib/gssapi/spnego/accept_sec_context.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/lib/gssapi/spnego/accept_sec_context.c b/lib/gssapi/spnego/accept_sec_context.c
index 48b786c29ed1..5fe1a1a649a4 100644
--- a/lib/gssapi/spnego/accept_sec_context.c
+++ b/lib/gssapi/spnego/accept_sec_context.c
@@ -619,13 +619,15 @@ acceptor_start
 	    if (ret == 0)
 		break;
 	}
-	if (preferred_mech_type == GSS_C_NO_OID) {
-	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
-	    free_NegotiationToken(&nt);
-	    return ret;
-	}
+    }
+
+    ctx->preferred_mech_type = preferred_mech_type;
 
-	ctx->preferred_mech_type = preferred_mech_type;
+    if (preferred_mech_type == GSS_C_NO_OID) {
+        send_reject(minor_status, output_token);
+        HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+        free_NegotiationToken(&nt);
+        return ret;
     }
 
     /*
-- 
2.38.1

