CVE-2022-21722 (published 2022-01-27T00:15Z)

PJSIP is a free and open source multimedia communication library written in C language implementing standard based protocols such as SIP, SDP, RTP, STUN, TURN, and ICE. In version 2.11.1 and prior, there are various cases where it is possible that certain incoming RTP/RTCP packets can potentially cause out-of-bound read access. This issue affects all users that use PJMEDIA and accept incoming RTP/RTCP. A patch is available as a commit in the `master` branch. There are no known workarounds.

Severity: MEDIUM
CVSS v2 base score: 6.4 (AV:N/AC:L/Au:N/C:P/I:N/A:P)
CVSS v3 base score: 9.1, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H)

Weakness information:
cwe_id: CWE-125
cwe_name: Out-of-bounds Read
description: The product reads data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/pjsip/pjproject
commit_details: repo_url: https://github.com/pjsip/pjproject
author: sauwming
author_date: 2022-01-26 08:03:48+08:00
msg: Merge pull request from GHSA-m66q-q64c-hv36

* Prevent OOB read during RTP/RTCP parsing

* Add log

* Add more logs
repository: repo_url: https://github.com/pjsip/pjproject
repo_name: pjsip/pjproject
description: PJSIP project
repo_language: C
owner: pjsip
file_changes: filename: rtcp.c
change_type: ModificationType.MODIFY
diff: @@ -502,12 +502,22 @@ static void parse_rtcp_report( pjmedia_rtcp_session *sess,
 
     /* Parse RTCP */
     if (common->pt == RTCP_SR) {
+        if (sizeof (pjmedia_rtcp_common) + sizeof (pjmedia_rtcp_sr) > size) {
+	    TRACE_((sess->name, "Discarding RTCP SR due to truncated size "
+	    			"%d bytes", size));
+            return;
+        }
 	sr = (pjmedia_rtcp_sr*) (((char*)pkt) + sizeof(pjmedia_rtcp_common));
 	if (common->count > 0 && size >= (sizeof(pjmedia_rtcp_sr_pkt))) {
 	    rr = (pjmedia_rtcp_rr*)(((char*)pkt) + (sizeof(pjmedia_rtcp_common)
 				    + sizeof(pjmedia_rtcp_sr)));
 	}
     } else if (common->pt == RTCP_RR && common->count > 0) {
+	if (sizeof (pjmedia_rtcp_common) + sizeof (pjmedia_rtcp_rr) > size) {
+	    TRACE_((sess->name, "Discarding RTCP RR due to truncated size "
+	    			"%d bytes", size));
+	    return;
+	}
 	rr = (pjmedia_rtcp_rr*)(((char*)pkt) + sizeof(pjmedia_rtcp_common));
 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
     } else if (common->pt == RTCP_XR) {
@@ -826,12 +836,20 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
     p = (pj_uint8_t*)pkt;
     p_end = p + size;
     while (p < p_end) {
-	pjmedia_rtcp_common *common = (pjmedia_rtcp_common*)p;
+	pjmedia_rtcp_common *common;
 	unsigned len;
 
+	if (p + sizeof(pjmedia_rtcp_common) > p_end) {
+	    TRACE_((sess->name, "Receiving truncated RTCP packet (1)"));
+	    break;
+	}
+	common = (pjmedia_rtcp_common*)p;
+
 	len = (pj_ntohs((pj_uint16_t)common->length)+1) * 4;
-	if (p + len > p_end)
+	if (p + len > p_end) {
+	    TRACE_((sess->name, "Receiving truncated RTCP packet (2)"));
 	    break;
+	}
 
 	switch(common->pt) {
 	case RTCP_SR:

programming_language: C
filename: rtcp_fb.c
change_type: ModificationType.MODIFY
diff: @@ -631,7 +631,8 @@ PJ_DEF(pj_status_t) pjmedia_rtcp_fb_parse_nack(
     if (hdr->pt != RTCP_RTPFB || hdr->count != 1)
 	return PJ_ENOTFOUND;
 
-    cnt = pj_ntohs((pj_uint16_t)hdr->length) - 2;
+    cnt = pj_ntohs((pj_uint16_t)hdr->length);
+    if (cnt > 2) cnt -= 2; else cnt = 0;
     if (length < (cnt+3)*4)
 	return PJ_ETOOSMALL;
 
@@ -663,7 +664,9 @@ PJ_DEF(pj_status_t) pjmedia_rtcp_fb_parse_pli(
     pjmedia_rtcp_common *hdr = (pjmedia_rtcp_common*) buf;
 
     PJ_ASSERT_RETURN(buf, PJ_EINVAL);
-    PJ_ASSERT_RETURN(length >= 12, PJ_ETOOSMALL);
+
+    if (length < 12)
+    	return PJ_ETOOSMALL;
 
     /* PLI uses pt==RTCP_PSFB and FMT==1 */
     if (hdr->pt != RTCP_PSFB || hdr->count != 1)

programming_language: C
filename: rtp.c
change_type: ModificationType.MODIFY
diff: @@ -190,6 +190,8 @@ PJ_DEF(pj_status_t) pjmedia_rtp_decode_rtp2(
 
     /* Decode RTP extension. */
     if ((*hdr)->x) {
+        if (offset + sizeof (pjmedia_rtp_ext_hdr) > pkt_len)
+            return PJMEDIA_RTP_EINLEN;
         dec_hdr->ext_hdr = (pjmedia_rtp_ext_hdr*)(((pj_uint8_t*)pkt) + offset);
         dec_hdr->ext = (pj_uint32_t*)(dec_hdr->ext_hdr + 1);
         dec_hdr->ext_len = pj_ntohs((dec_hdr->ext_hdr)->length);

programming_language: C