CVE-2021-41141 (published 2022-01-04T19:15Z)

PJSIP is a free and open source multimedia communication library written in the C language implementing standard based protocols such as SIP, SDP, RTP, STUN, TURN, and ICE. In various parts of PJSIP, when error/failure occurs, it is found that the function returns without releasing the currently held locks. This could result in a system deadlock, which cause a denial of service for the users. No release has yet been made which contains the linked fix commit. All versions up to an including 2.11.1 are affected. Users may need to manually apply the patch.

Severity: HIGH
CVSS v2 base score: 7.8 (AV:N/AC:L/Au:N/C:N/I:N/A:C)
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-667
cwe_name: Improper Locking
description: The product does not properly acquire or release a lock on a resource, leading to unexpected resource state changes and behaviors.
extended_description: 
	   Locking is a type of synchronization behavior that ensures that multiple independently-operating processes or threads do not interfere with each other when accessing the same resource. All processes/threads are expected to follow the same steps for locking. If these steps are not followed precisely - or if no locking is done at all - then another process/thread could modify the shared resource in a way that is not visible or predictable to the original process.  This can lead to data or memory corruption, denial of service, etc.
         

Fix information:
repo_url: https://github.com/pjsip/pjproject
commit_details: repo_url: https://github.com/pjsip/pjproject
author: Riza Sulistyo
author_date: 2022-01-04 15:58:02+07:00
msg: Merge pull request from GHSA-8fmx-hqw7-6gmc
repository: repo_url: https://github.com/pjsip/pjproject
repo_name: pjsip/pjproject
description: PJSIP project
repo_language: C
owner: pjsip
file_changes: filename: and_aud_mediacodec.cpp
change_type: ModificationType.MODIFY
diff: @@ -754,6 +754,7 @@ static pj_status_t and_media_alloc_codec(pjmedia_codec_factory *factory,
     }
     if (idx == -1) {
 	*p_codec = NULL;
+	pj_mutex_unlock(and_media_factory.mutex);
 	return PJMEDIA_CODEC_EFAILED;
     }
 

programming_language: C
filename: ipp_codecs.c
change_type: ModificationType.MODIFY
diff: @@ -939,6 +939,7 @@ static pj_status_t ipp_alloc_codec( pjmedia_codec_factory *factory,
     }
     if (idx == -1) {
 	*p_codec = NULL;
+	pj_mutex_unlock(ipp_factory.mutex);
 	return PJMEDIA_CODEC_EFAILED;
     }
 

programming_language: C
filename: opus.c
change_type: ModificationType.MODIFY
diff: @@ -723,6 +723,7 @@ static pj_status_t  codec_open( pjmedia_codec *codec,
 			    OPUS_APPLICATION_VOIP);
     if (err != OPUS_OK) {
 	PJ_LOG(2, (THIS_FILE, "Unable to create encoder"));
+	pj_mutex_unlock (opus_data->mutex);
 	return PJMEDIA_CODEC_EFAILED;
     }
     
@@ -767,6 +768,7 @@ static pj_status_t  codec_open( pjmedia_codec *codec,
 			     attr->info.channel_cnt);
     if (err != OPUS_OK) {
 	PJ_LOG(2, (THIS_FILE, "Unable to initialize decoder"));
+	pj_mutex_unlock (opus_data->mutex);
 	return PJMEDIA_CODEC_EFAILED;
     }
 

programming_language: C
filename: passthrough.c
change_type: ModificationType.MODIFY
diff: @@ -625,6 +625,7 @@ static pj_status_t alloc_codec( pjmedia_codec_factory *factory,
     }
     if (idx == -1) {
 	*p_codec = NULL;
+	pj_mutex_unlock(codec_factory.mutex);
 	return PJMEDIA_CODEC_EUNSUP;
     }
 

programming_language: C
filename: speex_codec.c
change_type: ModificationType.MODIFY
diff: @@ -379,6 +379,7 @@ PJ_DEF(pj_status_t) pjmedia_codec_speex_deinit(void)
     if (!codec_mgr) {
 	pj_pool_release(spx_factory.pool);
 	spx_factory.pool = NULL;
+	pj_mutex_unlock(spx_factory.mutex);
 	return PJ_EINVALIDOP;
     }
 

programming_language: C
filename: vid_conf.c
change_type: ModificationType.MODIFY
diff: @@ -304,6 +304,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_conf_add_port( pjmedia_vid_conf *vid_conf,
 	    PJ_LOG(4,(THIS_FILE, "pjmedia_vid_conf_add_port(): "
 				 "unrecognized format %04X",
 				 port->info.fmt.id));
+	    pj_mutex_unlock(vid_conf->mutex);
 	    return PJMEDIA_EBADFMT;
 	}
 
@@ -314,6 +315,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_conf_add_port( pjmedia_vid_conf *vid_conf,
 	    PJ_LOG(4,(THIS_FILE, "pjmedia_vid_conf_add_port(): "
 				 "Failed to apply format %04X",
 				 port->info.fmt.id));
+	    pj_mutex_unlock(vid_conf->mutex);
 	    return status;
 	}
 	if (port->put_frame) {
@@ -331,28 +333,41 @@ PJ_DEF(pj_status_t) pjmedia_vid_conf_add_port( pjmedia_vid_conf *vid_conf,
 			    pj_pool_zalloc(pool,
 					   vid_conf->opt.max_slot_cnt *
 					   sizeof(unsigned));
-    PJ_ASSERT_RETURN(cport->listener_slots, PJ_ENOMEM);
+    if (!cport->listener_slots) {	
+	pj_mutex_unlock(vid_conf->mutex);
+	return PJ_ENOMEM;
+    }
 
     /* Create transmitter array */
     cport->transmitter_slots = (unsigned*)
 			       pj_pool_zalloc(pool,
 					      vid_conf->opt.max_slot_cnt *
-					      sizeof(unsigned));
-    PJ_ASSERT_RETURN(cport->transmitter_slots, PJ_ENOMEM);
+					      sizeof(unsigned));    
+    if (!cport->transmitter_slots) {
+	pj_mutex_unlock(vid_conf->mutex);
+	return PJ_ENOMEM;
+    }
 
     /* Create pointer-to-render_state array */
     cport->render_states = (render_state**)
 			   pj_pool_zalloc(pool,
 					  vid_conf->opt.max_slot_cnt *
 					  sizeof(render_state*));
-    PJ_ASSERT_RETURN(cport->render_states, PJ_ENOMEM);
+
+    if (!cport->render_states) {
+	pj_mutex_unlock(vid_conf->mutex);
+	return PJ_ENOMEM;
+    }
 
     /* Create pointer-to-render-pool array */
     cport->render_pool = (pj_pool_t**)
 			 pj_pool_zalloc(pool,
 					vid_conf->opt.max_slot_cnt *
-					sizeof(pj_pool_t*));
-    PJ_ASSERT_RETURN(cport->render_pool, PJ_ENOMEM);
+					sizeof(pj_pool_t*));    
+    if (!cport->render_pool) {
+	pj_mutex_unlock(vid_conf->mutex);
+	return PJ_ENOMEM;
+    }
 
     /* Register the conf port. */
     vid_conf->ports[index] = cport;
@@ -420,6 +435,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_conf_remove_port( pjmedia_vid_conf *vid_conf,
 	status = pjmedia_clock_stop(vid_conf->clock);
 	if (status != PJ_SUCCESS) {
 	    PJ_PERROR(4, (THIS_FILE, status, "Failed to stop clock"));
+	    pj_mutex_unlock(vid_conf->mutex);
 	    return status;
 	}
     }
@@ -584,6 +600,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_conf_connect_port(
 	    status = pjmedia_clock_start(vid_conf->clock);
 	    if (status != PJ_SUCCESS) {
 		PJ_PERROR(4, (THIS_FILE, status, "Failed to start clock"));
+		pj_mutex_unlock(vid_conf->mutex);
 		return status;
 	    }
 	}
@@ -673,6 +690,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_conf_disconnect_port(
 	    status = pjmedia_clock_stop(vid_conf->clock);
 	    if (status != PJ_SUCCESS) {
 		PJ_PERROR(4, (THIS_FILE, status, "Failed to stop clock"));
+		pj_mutex_unlock(vid_conf->mutex);
 		return status;
 	    }
 	}

programming_language: C