From 8284e861e1ddb54cbfb5b6185861464005acceed Mon Sep 17 00:00:00 2001
From: Kevin Harwell <kharwell@sangoma.com>
Date: Mon, 10 May 2021 17:59:00 -0500
Subject: [PATCH] AST-2021-008 - chan_iax2: remote crash on unsupported media format

If chan_iax2 received a packet with an unsupported media format, for
example vp9, then it would set the frame's format to NULL. This could
then result in a crash later when an attempt was made to access the
format.

This patch makes it so chan_iax2 now ignores/drops frames received
with unsupported media format types.

ASTERISK-29392 #close

Change-Id: Ifa869a90dafe33eed8fd9463574fe6f1c0ad3eb1
---

diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 81bdf15..0ff4be9 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -4157,6 +4157,7 @@
 	long ms;
 	long next;
 	struct timeval now = ast_tvnow();
+	struct ast_format *voicefmt;
 
 	/* Make sure we have a valid private structure before going on */
 	ast_mutex_lock(&iaxsl[callno]);
@@ -4176,10 +4177,9 @@
 
 	ms = ast_tvdiff_ms(now, pvt->rxcore);
 
-	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);
+	voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
+	if (voicefmt && ms >= (next = jb_next(pvt->jb))) {
+		ret = jb_get(pvt->jb, &frame, ms, ast_format_get_default_ms(voicefmt));
 		switch(ret) {
 		case JB_OK:
 			fr = frame.data;
@@ -4207,7 +4207,7 @@
 				pvt = iaxs[callno];
 			}
 		}
-			break;
+		break;
 		case JB_DROP:
 			iax2_frame_free(frame.data);
 			break;
@@ -6467,8 +6467,14 @@
 		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);
 		}
@@ -9940,8 +9946,8 @@
 		} else if (iaxs[fr->callno]->voiceformat == 0) {
 			ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n");
 			iax2_vnak(fr->callno);
-		} else {
-			f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
+		} else if ((f.subclass.format = ast_format_compatibility_bitfield2format(
+						iaxs[fr->callno]->voiceformat))) {
 			f.datalen = len;
 			if (f.datalen >= 0) {
 				if (f.datalen)
@@ -10184,11 +10190,17 @@
 		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);
 		}
@@ -11807,6 +11819,11 @@
 				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);
@@ -11828,9 +11845,14 @@
 	} 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);
