CVE-2023-27585: Heap-based Buffer Overflow (CWE-122)
value: PJSIP is a free and open source multimedia communication library written in C. A buffer overflow vulnerability in versions 2.13 and prior affects applications that use PJSIP DNS resolver. It doesn't affect PJSIP users who do not utilise PJSIP DNS resolver. This vulnerability is related to CVE-2022-24793. The difference is that this issue is in parsing the query record `parse_query()`, while the issue in CVE-2022-24793 is in `parse_rr()`. A patch is available as commit `d1c5e4d` in the `master` branch. A workaround is to disable DNS resolution in PJSIP config (by setting `nameserver_count` to zero) or use an external resolver implementation instead.
CWE description: A heap overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc().
CVSS v3 base score: 7.5
Published: 2023-03-14T17:15Z
Repository: https://github.com/pjsip/pjproject
Language: C
Files changed: pjlib-util/src/pjlib-util/dns.c
Commit date: 2023-03-14 09:45:23 +0800
Commit message: Merge pull request from GHSA-q9cp-8wcq-7pfr

* Prevent heap buffer overflow when parsing DNS packet

* Fixed incorrect check in get_name*()
Diff: diff --git a/pjlib-util/src/pjlib-util/dns.c b/pjlib-util/src/pjlib-util/dns.c
index fc96632587..56a54c9973 100644
--- a/pjlib-util/src/pjlib-util/dns.c
+++ b/pjlib-util/src/pjlib-util/dns.c
@@ -125,10 +125,13 @@ static pj_status_t get_name_len(int rec_counter, const pj_uint8_t *pkt,
     if (rec_counter > 10) {
         /* Too many name recursion */
         return PJLIB_UTIL_EDNSINNAMEPTR;
     }
 
+    if (start >= max)
+        return PJLIB_UTIL_EDNSINNAMEPTR;
+
     *name_len = *parsed_len = 0;
     p = start;
     while (*p) {
         if ((*p & 0xc0) == 0xc0) {
             /* Compression is found! */
@@ -197,10 +200,13 @@ static pj_status_t get_name(int rec_counter, const pj_uint8_t *pkt,
     if (rec_counter > 10) {
         /* Too many name recursion */
         return PJLIB_UTIL_EDNSINNAMEPTR;
     }
 
+    if (start >= max)
+        return PJLIB_UTIL_EDNSINNAMEPTR;
+
     p = start;
     while (*p) {
         if ((*p & 0xc0) == 0xc0) {
             /* Compression is found! */
             pj_uint16_t offset;
@@ -357,14 +363,18 @@ static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
     if (p + rr->rdlength > max)
         return PJLIB_UTIL_EDNSINSIZE;
 
     /* Parse some well known records */
     if (rr->type == PJ_DNS_TYPE_A) {
+        if (p + 4 > max)
+            return PJLIB_UTIL_EDNSINSIZE;
         pj_memcpy(&rr->rdata.a.ip_addr, p, 4);
         p += 4;
 
     } else if (rr->type == PJ_DNS_TYPE_AAAA) {
+        if (p + 16 > max)
+            return PJLIB_UTIL_EDNSINSIZE;
         pj_memcpy(&rr->rdata.aaaa.ip_addr, p, 16);
         p += 16;
 
     } else if (rr->type == PJ_DNS_TYPE_CNAME ||
                rr->type == PJ_DNS_TYPE_NS ||
@@ -386,10 +396,12 @@ static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
             return status;
 
         p += name_part_len;
 
     } else if (rr->type == PJ_DNS_TYPE_SRV) {
+        if (p + 6 > max)
+            return PJLIB_UTIL_EDNSINSIZE;
 
         /* Priority */
         pj_memcpy(&rr->rdata.srv.prio, p, 2);
         rr->rdata.srv.prio = pj_ntohs(rr->rdata.srv.prio);
         p += 2;

Fixed code:     if (start >= max)
        return PJLIB_UTIL_EDNSINNAMEPTR;

    if (start >= max)
        return PJLIB_UTIL_EDNSINNAMEPTR;

        if (p + 4 > max)
            return PJLIB_UTIL_EDNSINSIZE;
        if (p + 16 > max)
            return PJLIB_UTIL_EDNSINSIZE;
        if (p + 6 > max)
            return PJLIB_UTIL_EDNSINSIZE;