CVE-2023-25566: Missing Release of Memory after Effective Lifetime (CWE-401)
value: GSS-NTLMSSP is a mechglue plugin for the GSSAPI library that implements NTLM authentication. Prior to version 1.2.0, a memory leak can be triggered when parsing usernames which can trigger a denial-of-service. The domain portion of a username may be overridden causing an allocated memory area the size of the domain name to be leaked. An attacker can leak memory via the main `gss_accept_sec_context` entry point, potentially causing a denial-of-service. This issue is fixed in version 1.2.0.


CWE description: The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory.
CVSS v3 base score: 7.5
Published: 2023-02-14T18:15Z
Repository: https://github.com/gssapi/gss-ntlmssp
Language: C
Files changed: src/gss_names.c
Commit date: 2023-02-12 11:07:18 -0500
Commit message: GHSL-2023-010: Memory leak when parsing usernames

Memory leak when parsing usernames (GHSL-2023-010)

Fixes defect GHSL-2023-010 found by the GitHub Security Lab team via
oss-fuzz.

The domain portion may be overridden causing an allocated memory area
the size of the domain name to be lost. This could be used to mount a
DoS by depleeting the server memory.

Signed-off-by: Simo Sorce <simo@redhat.com>

Diff: diff --git a/src/gss_names.c b/src/gss_names.c
index 1d3756d..21413d2 100644
--- a/src/gss_names.c
+++ b/src/gss_names.c
@@ -134,11 +134,10 @@ static uint32_t parse_user_name(uint32_t *minor_status,
     /* Check if enterprise name first */
     if (at && sep) {
         /* we may have an enterprise name here */
         char strbuf[len + 1];
         char *buf = strbuf;
-        bool domain_handled = false;
 
         /* copy buf to manipulate it */
         memcpy(buf, str, len);
         buf[len] = '\0';
 
@@ -158,13 +157,10 @@ static uint32_t parse_user_name(uint32_t *minor_status,
             /* no leading domain */
             sep = NULL;
         }
 
         if (sep) {
-            /* leading domain, copy if domain name is not empty */
-            domain_handled = true;
-
             /* terminate and copy domain, even if empty */
             /* NOTE: this is important for the Windbind integration case
              * where we need to tell the machinery to *not* add the default
              * domain name, it happens when the domain is NULL. */
             *sep = '\0';
@@ -178,20 +174,20 @@ static uint32_t parse_user_name(uint32_t *minor_status,
             buf = sep + 1;
         }
 
         for (at = strchr(buf, '@'); at != NULL; at = strchr(at, '@')) {
             if (*(at - 1) == '\\') {
-                if (domain_handled) {
+                if (*domain) {
                     /* Invalid forms like DOM\foo\@bar or foo@bar\@baz */
                     free(*domain);
                     *domain = NULL;
                     set_GSSERR(EINVAL);
                     goto done;
                 }
                 /* remove escape, moving all including terminating '\0' */
                 memmove(at - 1, at, len - (at - buf) + 1);
-            } else if (!domain_handled) {
+            } else if (!*domain) {
                 /* an '@' without escape and no previous
                  * domain was split out.
                  * the rest of the string is the domain */
                 *at = '\0';
                 *domain = strdup(at + 1);

Vulnerable code:         bool domain_handled = false;
            /* leading domain, copy if domain name is not empty */
            domain_handled = true;

                if (domain_handled) {
            } else if (!domain_handled) {
Fixed code:                 if (*domain) {
            } else if (!*domain) {