Vulnerability: 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 PJSIP version 2.10 and earlier, after an initial INVITE has been sent, when two 183 responses are received, with the first one causing negotiation failure, a crash will occur. This results in a denial of service.
Vulnerability ID: CVE-2021-21375
CWE: CWE-400
Severity score: 2.9
Project: https://github.com/pjsip/pjproject
Published: 2021-03-10
File: pjmedia/src/pjmedia/sdp_neg.c
Commit message: Merge pull request from GHSA-hvq6-f89p-frvp
Commit author: Nanang Izzuddin

Vulnerable version (before fix):
 PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2( {     pjmedia_sdp_session *new_offer;     pjmedia_sdp_session *old_offer;     char media_used[PJMEDIA_MAX_SDP_MEDIA];     unsigned oi; /* old offer media index */     pj_status_t status;  PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(     /* Change state to STATE_LOCAL_OFFER */     neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;      /* Init vars */     pj_bzero(media_used, sizeof(media_used));     old_offer = neg->active_local_sdp;     new_offer = pjmedia_sdp_session_clone(pool, local); 

Fixed version (after fix):
 PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2( {     pjmedia_sdp_session *new_offer;     pjmedia_sdp_session *old_offer;     unsigned oi; /* old offer media index */     pj_status_t status;  PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(     /* Change state to STATE_LOCAL_OFFER */     neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;      /* When there is no active local SDP in state PJMEDIA_SDP_NEG_STATE_DONE,      * it means that the previous initial SDP nego must have been failed,      * so we'll just set the local SDP offer here.      */     if (!neg->active_local_sdp) { 	neg->initial_sdp_tmp = NULL; 	neg->initial_sdp = pjmedia_sdp_session_clone(pool, local); 	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);  	return PJ_SUCCESS;     }      /* Init vars */     old_offer = neg->active_local_sdp;     new_offer = pjmedia_sdp_session_clone(pool, local); 

Patch:
patch: @@ -304,7 +304,6 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
 {
     pjmedia_sdp_session *new_offer;
     pjmedia_sdp_session *old_offer;
-    char media_used[PJMEDIA_MAX_SDP_MEDIA];
     unsigned oi; /* old offer media index */
     pj_status_t status;
 
@@ -323,8 +322,19 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
     /* Change state to STATE_LOCAL_OFFER */
     neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;
 
+    /* When there is no active local SDP in state PJMEDIA_SDP_NEG_STATE_DONE,
+     * it means that the previous initial SDP nego must have been failed,
+     * so we'll just set the local SDP offer here.
+     */
+    if (!neg->active_local_sdp) {
+	neg->initial_sdp_tmp = NULL;
+	neg->initial_sdp = pjmedia_sdp_session_clone(pool, local);
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);
+
+	return PJ_SUCCESS;
+    }
+
     /* Init vars */
-    pj_bzero(media_used, sizeof(media_used));
     old_offer = neg->active_local_sdp;
     new_offer = pjmedia_sdp_session_clone(pool, local);
path: pjmedia/src/pjmedia/sdp_neg.c