CVE-2022-24786 (C, published 2022-04-06T14:15Z)
Description: value: PJSIP is a free and open source multimedia communication library written in C. PJSIP versions 2.12 and prior do not parse incoming RTCP feedback RPSI (Reference Picture Selection Indication) packet, but any app that directly uses pjmedia_rtcp_fb_parse_rpsi() will be affected. A patch is available in the `master` branch of the `pjsip/pjproject` GitHub repository. There are currently no known workarounds.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-125 \u2014 Out-of-bounds Read
The product reads data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/pjsip/pjproject
Files changed:
pjmedia/include/pjmedia/rtcp.h
pjmedia/src/pjmedia/rtcp.c
pjmedia/src/pjmedia/rtcp_fb.c
Commit message: Merge pull request from GHSA-vhxv-phmx-g52q

* Prevent OOB read/write when parsing RTCP FB RPSI

* Add log information

* Modification based on comments.

Vulnerable code:
    pjmedia_rtcp_common *hdr;
    hdr = (pjmedia_rtcp_common*)buf;
    pj_memcpy(hdr, &session->rtcp_rr_pkt.common,  sizeof(*hdr));
    hdr->pt = RTCP_RTPFB;
    hdr->count = 1; /* FMT = 1 */
    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_common *hdr;
    hdr = (pjmedia_rtcp_common*)buf;
    pj_memcpy(hdr, &session->rtcp_rr_pkt.common,  sizeof(*hdr));
    hdr->pt = RTCP_PSFB;
    hdr->count = 1; /* FMT = 1 */
    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_common *hdr;
    hdr = (pjmedia_rtcp_common*)buf;
    pj_memcpy(hdr, &session->rtcp_rr_pkt.common,  sizeof(*hdr));
    hdr->pt = RTCP_PSFB;
    hdr->count = 2; /* FMT = 2 */
    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_common *hdr;
    hdr = (pjmedia_rtcp_common*)buf;
    pj_memcpy(hdr, &session->rtcp_rr_pkt.common,  sizeof(*hdr));
    hdr->pt = RTCP_PSFB;
    hdr->count = 3; /* FMT = 3 */
    hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_common *hdr = (pjmedia_rtcp_common*) buf;
    PJ_ASSERT_RETURN(length >= sizeof(pjmedia_rtcp_common), PJ_ETOOSMALL);
    if (hdr->pt != RTCP_RTPFB || hdr->count != 1)
    cnt = pj_ntohs((pj_uint16_t)hdr->length);
    pjmedia_rtcp_common *hdr = (pjmedia_rtcp_common*) buf;
    if (hdr->pt != RTCP_PSFB || hdr->count != 1)
    pjmedia_rtcp_common *hdr = (pjmedia_rtcp_common*) buf;
    PJ_ASSERT_RETURN(length >= sizeof(pjmedia_rtcp_common), PJ_ETOOSMALL);
    if (hdr->pt != RTCP_PSFB || hdr->count != 2)
    cnt = pj_ntohs((pj_uint16_t)hdr->length) - 2;
    pjmedia_rtcp_common *hdr = (pjmedia_rtcp_common*) buf;
    PJ_ASSERT_RETURN(length >= sizeof(pjmedia_rtcp_common), PJ_ETOOSMALL);
    if (hdr->pt != RTCP_PSFB || hdr->count != 3)
    rpsi_len = (pj_ntohs((pj_uint16_t)hdr->length)-2) * 4;

Fixed code:
/**
 * RTCP feedback common header.
 */
typedef struct pjmedia_rtcp_fb_common
{
    pjmedia_rtcp_common rtcp_common;
    pj_uint32_t	    ssrc_src;	/**< SSRC media source	    */
} pjmedia_rtcp_fb_common;

    pjmedia_rtcp_fb_common  rtcp_fb_com;/**< Cached RTCP feedback common 
					     header packet.		    */
    /* Copy to RTCP FB common header */
    pj_memcpy(&sess->rtcp_fb_com, &sr_pkt->common, 
	      sizeof(pjmedia_rtcp_common));
    sess->rtcp_fb_com.ssrc_src = 0;

    pjmedia_rtcp_fb_common *hdr;
    hdr = (pjmedia_rtcp_fb_common*)buf;
    pj_memcpy(hdr, &session->rtcp_fb_com, sizeof(*hdr));
    hdr->rtcp_common.pt = RTCP_RTPFB;
    hdr->rtcp_common.count = 1; /* FMT = 1 */
    hdr->rtcp_common.length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_fb_common *hdr;
    hdr = (pjmedia_rtcp_fb_common*)buf;
    pj_memcpy(hdr, &session->rtcp_fb_com, sizeof(*hdr));
    hdr->rtcp_common.pt = RTCP_PSFB;
    hdr->rtcp_common.count = 1; /* FMT = 1 */
    hdr->rtcp_common.length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_fb_common *hdr;
    hdr = (pjmedia_rtcp_fb_common*)buf;
    pj_memcpy(hdr, &session->rtcp_fb_com, sizeof(*hdr));
    hdr->rtcp_common.pt = RTCP_PSFB;
    hdr->rtcp_common.count = 2; /* FMT = 2 */
    hdr->rtcp_common.length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_fb_common *hdr;
    hdr = (pjmedia_rtcp_fb_common*)buf;
    pj_memcpy(hdr, &session->rtcp_fb_com, sizeof(*hdr));
    hdr->rtcp_common.pt = RTCP_PSFB;
    hdr->rtcp_common.count = 3; /* FMT = 3 */
    hdr->rtcp_common.length = pj_htons((pj_uint16_t)(len/4 - 1));
    pjmedia_rtcp_fb_common *hdr = (pjmedia_rtcp_fb_common*) buf;
    PJ_ASSERT_RETURN(length >= sizeof(pjmedia_rtcp_fb_common), PJ_ETOOSMALL);
    if (hdr->rtcp_common.pt != RTCP_RTPFB || hdr->rtcp_common.count != 1)
    cnt = pj_ntohs((pj_uint16_t)hdr->rtcp_common.length);
    pjmedia_rtcp_fb_common *hdr = (pjmedia_rtcp_fb_common*) buf;
    if (hdr->rtcp_common.pt != RTCP_PSFB || hdr->rtcp_common.count != 1)
    pjmedia_rtcp_fb_common *hdr = (pjmedia_rtcp_fb_common*) buf;
    PJ_ASSERT_RETURN(length >= sizeof(pjmedia_rtcp_fb_common), PJ_ETOOSMALL);
    if (hdr->rtcp_common.pt != RTCP_PSFB || hdr->rtcp_common.count != 2)
    cnt = pj_ntohs((pj_uint16_t)hdr->rtcp_common.length) - 2;
    pjmedia_rtcp_fb_common *hdr = (pjmedia_rtcp_fb_common*) buf;
    PJ_ASSERT_RETURN(length >= sizeof(pjmedia_rtcp_fb_common), PJ_ETOOSMALL);
    if (hdr->rtcp_common.pt != RTCP_PSFB || hdr->rtcp_common.count != 3)
    if (hdr->rtcp_common.length < 3) {    
        PJ_PERROR(3, (THIS_FILE, PJ_ETOOSMALL,
                      "Failed parsing FB RPSI, invalid header length"));
	return PJ_ETOOSMALL;
    }

    rpsi_len = (pj_ntohs((pj_uint16_t)hdr->rtcp_common.length)-2) * 4;

    if (padlen >= 32) {
        PJ_PERROR(3, (THIS_FILE, PJ_ETOOBIG,
                      "Failed parsing FB RPSI, invalid RPSI padding len"));
	return PJ_ETOOBIG;
    }

    if ((rpsi_len * 8) < (unsigned)(16 + padlen)) {
        PJ_PERROR(3, (THIS_FILE, PJ_ETOOSMALL,
                      "Failed parsing FB RPSI, invalid RPSI bit len"));
	return PJ_ETOOSMALL;
    }