CVE-2022-24793 (published 2022-04-06T14:15Z)

PJSIP is a free and open source multimedia communication library written in C. A buffer overflow vulnerability in versions 2.12 and prior affects applications that use PJSIP DNS resolution. It doesn't affect PJSIP users who utilize an external resolver. This vulnerability is related to CVE-2023-27585. The difference is that this issue is in parsing the query record `parse_rr()`, while the issue in CVE-2023-27585 is in `parse_query()`. A patch is available in the `master` branch of the `pjsip/pjproject` GitHub repository. A workaround is to disable DNS resolution in PJSIP config (by setting `nameserver_count` to zero) or use an external resolver instead.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-120
cwe_name: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
extended_description: A buffer overflow condition exists when a product attempts to put more data in a buffer than it can hold, or when it attempts to put data in a memory area outside of the boundaries of a buffer. The simplest type of error, and the most common cause of buffer overflows, is the "classic" case in which the product copies the buffer without restricting how much is copied. Other variants exist, but the existence of a classic overflow strongly suggests that the programmer is not considering even the most basic of security protections.
         

Fix information:
repo_url: https://github.com/pjsip/pjproject
commit_details: repo_url: https://github.com/pjsip/pjproject
author: Riza Sulistyo
author_date: 2022-04-06 10:49:47+07:00
msg: Merge pull request from GHSA-p6g5-v97c-w5q4

* Prevent heap buffer overflow when parsing DNS packets

* Make sure packet parsing doesn't advance beyond max/end

* Update checks

* Remove  check

Co-authored-by: sauwming <ming@teluu.com>
repository: repo_url: https://github.com/pjsip/pjproject
repo_name: pjsip/pjproject
description: PJSIP project
repo_language: C
owner: pjsip
file_changes: filename: dns.c
change_type: ModificationType.MODIFY
diff: @@ -159,8 +159,13 @@ static pj_status_t get_name_len(int rec_counter, const pj_uint8_t *pkt,
 	} else {
 	    unsigned label_len = *p;
 
-	    /* Check that label length is valid */
-	    if (pkt+label_len > max)
+	    /* Check that label length is valid.
+	     * Each label consists of an octet length (of size 1) followed
+	     * by the octet of the specified length (label_len). Then it
+	     * must be followed by either another label's octet length or
+	     * a zero length octet (that terminates the sequence).
+	     */
+	    if (p+1+label_len+1 > max)
 		return PJLIB_UTIL_EDNSINNAMEPTR;
 
 	    p += (label_len + 1);
@@ -170,9 +175,6 @@ static pj_status_t get_name_len(int rec_counter, const pj_uint8_t *pkt,
 		++label_len;
 	    
 	    *name_len += label_len;
-
-	    if (p >= max)
-		return PJLIB_UTIL_EDNSINSIZE;
 	}
     }
     ++p;
@@ -222,8 +224,13 @@ static pj_status_t get_name(int rec_counter, const pj_uint8_t *pkt,
 	} else {
 	    unsigned label_len = *p;
 
-	    /* Check that label length is valid */
-	    if (pkt+label_len > max)
+	    /* Check that label length is valid.
+	     * Each label consists of an octet length (of size 1) followed
+	     * by the octet of the specified length (label_len). Then it
+	     * must be followed by either another label's octet length or
+	     * a zero length octet (that terminates the sequence).
+	     */
+	    if (p+1+label_len+1 > max)
 		return PJLIB_UTIL_EDNSINNAMEPTR;
 
 	    pj_memcpy(name->ptr + name->slen, p+1, label_len);
@@ -234,9 +241,6 @@ static pj_status_t get_name(int rec_counter, const pj_uint8_t *pkt,
 		*(name->ptr + name->slen) = '.';
 		++name->slen;
 	    }
-
-	    if (p >= max)
-		return PJLIB_UTIL_EDNSINSIZE;
 	}
     }
 
@@ -269,6 +273,10 @@ static pj_status_t parse_query(pj_dns_parsed_query *q, pj_pool_t *pool,
 
     p = (start + name_part_len);
 
+    /* Check the size can accomodate next few fields. */
+    if (p + 4 > max)
+    	return PJLIB_UTIL_EDNSINSIZE;
+
     /* Get the type */
     pj_memcpy(&q->type, p, 2);
     q->type = pj_ntohs(q->type);

programming_language: C