commit 859fcb75f811c55d5645c9ae31680bbc610d5905
Author: Kevin Harwell <kharwell@sangoma.com>
Date:   Mon May 10 17:59:00 2021 -0500

    AST-2021-008 - chan_iax2: remote crash on unsupported packet type
    
    If chan_iax2 received an unsupported packet type, for example vp9,
    then it would set the frame's format to NULL. This would then result
    in a crash in the channel core when an attempt was made to access
    the format.
    
    This patch makes it so chan_iax2 now ignores/drops frames received
    with unsupported packet types.
    
    ASTERISK-29392 #close
    
    Change-Id: Ifa869a90dafe33eed8fd9463574fe6f1c0ad3eb1

diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 3d8cd72b5d..21e146d63c 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -4154,46 +4154,48 @@ static void __get_from_jb(const void *p)
 	if(ms >= (next = jb_next(pvt->jb))) {
 		struct ast_format *voicefmt;
 		voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
-		ret = jb_get(pvt->jb, &frame, ms, voicefmt ? ast_format_get_default_ms(voicefmt) : 20);
-		switch(ret) {
-		case JB_OK:
-			fr = frame.data;
-			__do_deliver(fr);
-			/* __do_deliver() can cause the call to disappear */
-			pvt = iaxs[callno];
-			break;
-		case JB_INTERP:
-		{
-			struct ast_frame af = { 0, };
-
-			/* create an interpolation frame */
-			af.frametype = AST_FRAME_VOICE;
-			af.subclass.format = voicefmt;
-			af.samples  = frame.ms * (ast_format_get_sample_rate(voicefmt) / 1000);
-			af.src  = "IAX2 JB interpolation";
-			af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
-			af.offset = AST_FRIENDLY_OFFSET;
-
-			/* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
-			 * which we'd need to malloc, and then it would free it.  That seems like a drag */
-			if (!ast_test_flag64(iaxs[callno], IAX_ALREADYGONE)) {
-				iax2_queue_frame(callno, &af);
-				/* iax2_queue_frame() could cause the call to disappear */
-				pvt = iaxs[callno];
+		if (voicefmt) {
+			ret = jb_get(pvt->jb, &frame, ms, voicefmt ? ast_format_get_default_ms(voicefmt) : 20);
+			switch(ret) {
+				case JB_OK:
+					fr = frame.data;
+					__do_deliver(fr);
+					/* __do_deliver() can cause the call to disappear */
+					pvt = iaxs[callno];
+					break;
+				case JB_INTERP:
+				{
+					struct ast_frame af = { 0, };
+
+					/* create an interpolation frame */
+					af.frametype = AST_FRAME_VOICE;
+					af.subclass.format = voicefmt;
+					af.samples  = frame.ms * (ast_format_get_sample_rate(voicefmt) / 1000);
+					af.src  = "IAX2 JB interpolation";
+					af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
+					af.offset = AST_FRIENDLY_OFFSET;
+
+					/* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
+					 * which we'd need to malloc, and then it would free it.  That seems like a drag */
+					if (!ast_test_flag64(iaxs[callno], IAX_ALREADYGONE)) {
+						iax2_queue_frame(callno, &af);
+						/* iax2_queue_frame() could cause the call to disappear */
+						pvt = iaxs[callno];
+					}
+				}
+				break;
+				case JB_DROP:
+					iax2_frame_free(frame.data);
+					break;
+				case JB_NOFRAME:
+				case JB_EMPTY:
+					/* do nothing */
+					break;
+				default:
+					/* shouldn't happen */
+					break;
 			}
 		}
-			break;
-		case JB_DROP:
-			iax2_frame_free(frame.data);
-			break;
-		case JB_NOFRAME:
-		case JB_EMPTY:
-			/* do nothing */
-			break;
-		default:
-			/* shouldn't happen */
-			break;
-		}
 	}
 	if (pvt)
 		update_jbsched(pvt);
@@ -6451,8 +6453,14 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
 		f->frametype = fh->type;
 		if (f->frametype == AST_FRAME_VIDEO) {
 			f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1));
+			if (!f->subclass.format) {
+				f->subclass.format = ast_format_none;
+			}
 		} else if (f->frametype == AST_FRAME_VOICE) {
 			f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
+			if (!f->subclass.format) {
+				f->subclass.format = ast_format_none;
+			}
 		} else {
 			f->subclass.integer = uncompress_subclass(fh->csub);
 		}
@@ -9931,38 +9939,40 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 			iax2_vnak(fr->callno);
 		} else {
 			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
-			f.datalen = len;
-			if (f.datalen >= 0) {
-				if (f.datalen)
-					f.data.ptr = ptr;
-				else
-					f.data.ptr = NULL;
-				if (trunked_ts)
-					fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
-				else
-					fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
-				/* Don't pass any packets until we're started */
-				if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
-					struct iax_frame *duped_fr;
-
-					/* Common things */
-					f.src = "IAX2";
-					f.mallocd = 0;
-					f.offset = 0;
-					if (f.datalen && (f.frametype == AST_FRAME_VOICE))
-						f.samples = ast_codec_samples_count(&f);
+			if (f.subclass.format) {
+				f.datalen = len;
+				if (f.datalen >= 0) {
+					if (f.datalen)
+						f.data.ptr = ptr;
+					else
+						f.data.ptr = NULL;
+					if (trunked_ts)
+						fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
 					else
-						f.samples = 0;
-					fr->outoforder = 0;
-					iax_frame_wrap(fr, &f);
-					duped_fr = iaxfrdup2(fr);
-					if (duped_fr)
-						schedule_delivery(duped_fr, 1, 1, &fr->ts);
-					if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts)
-						iaxs[fr->callno]->last = fr->ts;
+						fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
+					/* Don't pass any packets until we're started */
+					if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
+						struct iax_frame *duped_fr;
+
+						/* Common things */
+						f.src = "IAX2";
+						f.mallocd = 0;
+						f.offset = 0;
+						if (f.datalen && (f.frametype == AST_FRAME_VOICE))
+							f.samples = ast_codec_samples_count(&f);
+						else
+							f.samples = 0;
+						fr->outoforder = 0;
+						iax_frame_wrap(fr, &f);
+						duped_fr = iaxfrdup2(fr);
+						if (duped_fr)
+							schedule_delivery(duped_fr, 1, 1, &fr->ts);
+						if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts)
+							iaxs[fr->callno]->last = fr->ts;
+					}
+				} else {
+					ast_log(LOG_WARNING, "Datalen < 0?\n");
 				}
-			} else {
-				ast_log(LOG_WARNING, "Datalen < 0?\n");
 			}
 		}
 		ast_mutex_unlock(&iaxsl[fr->callno]);
@@ -10173,11 +10183,17 @@ static int socket_process_helper(struct iax2_thread *thread)
 		f.frametype = fh->type;
 		if (f.frametype == AST_FRAME_VIDEO) {
 			f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40));
+			if (!f.subclass.format) {
+				return 1;
+			}
 			if ((fh->csub >> 6) & 0x1) {
 				f.subclass.frame_ending = 1;
 			}
 		} else if (f.frametype == AST_FRAME_VOICE) {
 			f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
+			if (!f.subclass.format) {
+				return 1;
+			}
 		} else {
 			f.subclass.integer = uncompress_subclass(fh->csub);
 		}
@@ -11795,6 +11811,11 @@ immediatedial:
 				f.subclass.frame_ending = 1;
 			}
 			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->videoformat);
+			if (!f.subclass.format) {
+				ast_variables_destroy(ies.vars);
+				ast_mutex_unlock(&iaxsl[fr->callno]);
+				return 1;
+			}
 		} else {
 			ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
 			iax2_vnak(fr->callno);
@@ -11816,9 +11837,14 @@ immediatedial:
 	} else {
 		/* A mini frame */
 		f.frametype = AST_FRAME_VOICE;
-		if (iaxs[fr->callno]->voiceformat > 0)
+		if (iaxs[fr->callno]->voiceformat > 0) {
 			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
-		else {
+			if (!f.subclass.format) {
+				ast_variables_destroy(ies.vars);
+				ast_mutex_unlock(&iaxsl[fr->callno]);
+				return 1;
+			}
+		} else {
 			ast_debug(1, "Received mini frame before first full voice frame\n");
 			iax2_vnak(fr->callno);
 			ast_variables_destroy(ies.vars);
