From c062515c092d2fb1ce98e0decb31479971207b95 Mon Sep 17 00:00:00 2001
From: Ivan Poddubnyi <ivan.poddubny@gmail.com>
Date: Mon, 28 Dec 2020 13:43:23 +0100
Subject: [PATCH] res_pjsip_diversion: Fix adding more than one histinfo to
 Supported

New responses sent within a PJSIP sessions are based on those that were
sent before. Therefore, adding/modifying a header once causes it to be
sent on all responses that follow.

Sending 181 Call Is Being Forwarded many times first adds "histinfo"
duplicated more and more, and eventually overflows past the array
boundary.

This commit adds a check preventing adding "histinfo" more than once,
and skipping it if there is no more space in the header.

Similar overflow situations can also occur in res_pjsip_path and
res_pjsip_outbound_registration so those were also modified to
check the bounds and suppress duplicate Supported values.

ASTERISK-29227
Reported by: Ivan Poddubny

Change-Id: Id43704a1f1a0293e35cc7f844026f0b04f2ac322
---
 res/res_pjsip_diversion.c             | 14 ++++++++++++++
 res/res_pjsip_outbound_registration.c | 12 ++++++++++++
 res/res_pjsip_path.c                  | 12 ++++++++++++
 3 files changed, 38 insertions(+)

diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c
index 08f75e0903..d344214e3b 100644
--- a/res/res_pjsip_diversion.c
+++ b/res/res_pjsip_diversion.c
@@ -120,6 +120,7 @@ static enum AST_REDIRECTING_REASON cause_to_reason(const unsigned long cause) {
 static int add_supported(pjsip_tx_data *tdata)
 {
 	pjsip_supported_hdr *hdr;
+	unsigned int i;
 
 	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
 	if (!hdr) {
@@ -132,6 +133,19 @@ static int add_supported(pjsip_tx_data *tdata)
 		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
 	}
 
+	/* Asterisk can send multiple "181 Call forwarded" in a single session,
+	 * we might have already modified Supported before
+	 */
+	for (i = 0; i < hdr->count; ++i) {
+		if (pj_stricmp(&hdr->values[i], &HISTINFO_SUPPORTED_NAME) == 0) {
+			return 0;
+		}
+	}
+
+	if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
+		return -1;
+	}
+
 	/* add on to the existing Supported header */
 	pj_strassign(&hdr->values[hdr->count++], &HISTINFO_SUPPORTED_NAME);
 
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 0f590f5364..1b8fbe2d2a 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -586,6 +586,7 @@ static int handle_client_registration(void *data)
 
 	if (client_state->support_path) {
 		pjsip_supported_hdr *hdr;
+		int i;
 
 		hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
 		if (!hdr) {
@@ -599,6 +600,17 @@ static int handle_client_registration(void *data)
 			pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
 		}
 
+		/* Don't add the value if it's already there */
+		for (i = 0; i < hdr->count; ++i) {
+			if (pj_stricmp(&hdr->values[i], &PATH_NAME) == 0) {
+				return 1;
+			}
+		}
+
+		if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
+			return 0;
+		}
+
 		/* add on to the existing Supported header */
 		pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
 	}
diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c
index de231fb2d4..28f2cfd7a2 100644
--- a/res/res_pjsip_path.c
+++ b/res/res_pjsip_path.c
@@ -123,6 +123,7 @@ static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_
 static int add_supported(pjsip_tx_data *tdata)
 {
 	pjsip_supported_hdr *hdr;
+	int i;
 
 	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
 	if (!hdr) {
@@ -135,6 +136,17 @@ static int add_supported(pjsip_tx_data *tdata)
 		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
 	}
 
+	/* Don't add the value if it's already there */
+	for (i = 0; i < hdr->count; ++i) {
+		if (pj_stricmp(&hdr->values[i], &PATH_SUPPORTED_NAME) == 0) {
+			return 0;
+		}
+	}
+
+	if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
+		return -1;
+	}
+
 	/* add on to the existing Supported header */
 	pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
 
-- 
2.29.2

