CVE-2023-25563: Out-of-bounds Read (CWE-125)
value: GSS-NTLMSSP is a mechglue plugin for the GSSAPI library that implements NTLM authentication. Prior to version 1.2.0, multiple out-of-bounds reads when decoding NTLM fields can trigger a denial of service. A 32-bit integer overflow condition can lead to incorrect checks of consistency of length of internal buffers. Although most applications will error out before accepting a singe input buffer of 4GB in length this could theoretically happen. This vulnerability can be triggered via the main `gss_accept_sec_context` entry point if the application allows tokens greater than 4GB in length. This can lead to a large, up to 65KB, out-of-bounds read which could cause a denial-of-service if it reads from unmapped memory. Version 1.2.0 contains a patch for the out-of-bounds reads.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.5
Published: 2023-02-14T18:15Z
Repository: https://github.com/gssapi/gss-ntlmssp
Language: C
Files changed: src/ntlm.c
Commit date: 2023-02-12 10:59:30 -0500
Commit message: Out-of-bounds read in multiple decode functions

These were reported as:
- Out-of-bounds read in ntlm_decode_oem_str (GHSL-2023-019)
- Out-of-bounds read in ntlm_decode_u16l_str_hdr (GHSL-2023-020)
- Out-of-bounds read in ntlm_decode_field (GHSL-2023-021)

These are lall basically the same identical error replicated in 3
separate functions.

Fixes defects GHSL-2023-019, GHSL-2023-020, GHSL-2023-021 found by
the GitHub Security Lab team via oss-fuzz.

A 32-bit integer overflow condition can lead to incorrect checks of
consistency of length of internal buffers. This leads to a DoS
as the service may end up reading from unmapped memory and crashing.

Although most applications will error out before accepting a singe input
buffer of 4GB in lenght this could theoretically happen, and therefore
we fix it.

Fixes CVE-2023-25563

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

Diff: diff --git a/src/ntlm.c b/src/ntlm.c
index b2d84a2..df2458a 100644
--- a/src/ntlm.c
+++ b/src/ntlm.c
@@ -203,11 +203,10 @@ static int ntlm_str_convert(iconv_t cd,
         *outlen = baselen * 2 - outleft;
     }
     return 0;
 }
 
-
 uint8_t ntlmssp_sig[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
 
 static void ntlm_encode_header(struct wire_msg_hdr *hdr, uint32_t msg_type)
 {
     memcpy(hdr->signature, ntlmssp_sig, 8);
@@ -254,10 +253,11 @@ static int ntlm_decode_oem_str(struct wire_field_hdr *str_hdr,
     if (str_len == 0) goto done;
 
     str_offs = le32toh(str_hdr->offset);
     if ((str_offs < payload_offs) ||
         (str_offs > buffer->length) ||
+        (UINT32_MAX - str_offs < str_len) ||
         (str_offs + str_len > buffer->length)) {
         return ERR_DECODE;
     }
 
     str = strndup((const char *)&buffer->data[str_offs], str_len);
@@ -306,10 +306,11 @@ static int ntlm_decode_u16l_str_hdr(struct ntlm_ctx *ctx,
     if (str_len == 0) goto done;
 
     str_offs = le32toh(str_hdr->offset);
     if ((str_offs < payload_offs) ||
         (str_offs > buffer->length) ||
+        (UINT32_MAX - str_offs < str_len) ||
         (str_offs + str_len > buffer->length)) {
         return ERR_DECODE;
     }
 
     in = (char *)&buffer->data[str_offs];
@@ -391,10 +392,11 @@ static int ntlm_decode_field(struct wire_field_hdr *hdr,
     if (len == 0) goto done;
 
     offs = le32toh(hdr->offset);
     if ((offs < payload_offs) ||
         (offs > buffer->length) ||
+        (UINT32_MAX - offs < len) ||
         (offs + len > buffer->length)) {
         return ERR_DECODE;
     }
 
     b.data = malloc(len);

Fixed code:         (UINT32_MAX - str_offs < str_len) ||
        (UINT32_MAX - str_offs < str_len) ||
        (UINT32_MAX - offs < len) ||