CVE-2022-23608 (C, published 2022-02-22T20:15Z)
Description: value: 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 versions up to and including 2.11.1 when in a dialog set (or forking) scenario, a hash key shared by multiple UAC dialogs can potentially be prematurely freed when one of the dialogs is destroyed . The issue may cause a dialog set to be registered in the hash table multiple times (with different hash keys) leading to undefined behavior such as dialog list collision which eventually leading to endless loop. A patch is available in commit db3235953baa56d2fb0e276ca510fefca751643f which will be included in the next release. There are no known workarounds for this issue.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-416 \u2014 Use After Free
The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
Repository: https://github.com/pjsip/pjproject
Files changed:
pjsip/src/pjsip/sip_ua_layer.c
Commit message: Merge pull request from GHSA-ffff-m5fm-qm62

* Update pjsip_ua_unregister_dlg():
- update the hash key if the dialog being unregistered is used as hash key.
- add an assertion check to make sure that the dlg_set to be removed is valid (can be found in the hash table).

* Change hash key string comparison method.

Vulnerable code:
			         dlg->local.info->tag.ptr,
                                 (unsigned)dlg->local.info->tag.slen,
		             dlg->local.info->tag.ptr,
                             (unsigned)dlg->local.info->tag.slen,
	pj_hash_set_lower(NULL, mod_ua.dlg_table, dlg->local.info->tag.ptr,
		          (unsigned)dlg->local.info->tag.slen, 

Fixed code:
    /* Entry key in the hash table */
    pj_str_t ht_key;

	    dlg_set->ht_key = dlg->local.info->tag;
			         dlg_set->ht_key.ptr,
                                 (unsigned)dlg_set->ht_key.slen,
	dlg_set->ht_key = dlg->local.info->tag;
		             dlg_set->ht_key.ptr,
                             (unsigned)dlg_set->ht_key.slen,

	/* Verify that the dialog set is valid */
	pj_assert(pj_hash_get_lower(mod_ua.dlg_table, dlg_set->ht_key.ptr,
				    (unsigned)dlg_set->ht_key.slen,
				    &dlg->local.tag_hval) == dlg_set);

	pj_hash_set_lower(NULL, mod_ua.dlg_table, dlg_set->ht_key.ptr,
		          (unsigned)dlg_set->ht_key.slen,
    } else {
	/* If the just unregistered dialog is being used as hash key,
	 * reset the dlg_set entry with a new key (i.e: from the first dialog
	 * in dlg_set).
	 */
	if (dlg_set->ht_key.ptr  == dlg->local.info->tag.ptr &&
	    dlg_set->ht_key.slen == dlg->local.info->tag.slen)
	{
	    pjsip_dialog* key_dlg = dlg_set->dlg_list.next;

	    /* Verify that the old & new keys share the hash value */
	    pj_assert(key_dlg->local.tag_hval == dlg->local.tag_hval);

	    pj_hash_set_lower(NULL, mod_ua.dlg_table, dlg_set->ht_key.ptr,
			      (unsigned)dlg_set->ht_key.slen,
			      dlg->local.tag_hval, NULL);

	    dlg_set->ht_key = key_dlg->local.info->tag;

	    pj_hash_set_np_lower(mod_ua.dlg_table,
				 dlg_set->ht_key.ptr,
				 (unsigned)dlg_set->ht_key.slen,
				 key_dlg->local.tag_hval, dlg_set->ht_entry,
				 dlg_set);
	}