aboutsummaryrefslogtreecommitdiffstats
path: root/main/asterisk/AST-2019-004-15.patch
blob: 561e3d4ed3f275b2e31813fef1755bf8b2a7c446 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
From f361e65dc2c90aaee9472f97b54083e0a2d49303 Mon Sep 17 00:00:00 2001
From: Kevin Harwell <kharwell@digium.com>
Date: Tue, 20 Aug 2019 15:05:45 -0500
Subject: [PATCH] AST-2019-004 - res_pjsip_t38.c: Add NULL checks before using session media

After receiving a 200 OK with a declined stream in response to a T.38
initiated re-invite Asterisk would crash when attempting to dereference
a NULL session media object.

This patch checks to make sure the session media object is not NULL before
attempting to use it.

ASTERISK-28495
patches:
  ast-2019-004.patch submitted by Alexei Gradinari (license 5691)

Change-Id: I168f45f4da29cfe739acf87e597baa2aae7aa572
---

diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c
index fae6fbb..624139f 100644
--- a/res/res_pjsip_t38.c
+++ b/res/res_pjsip_t38.c
@@ -203,7 +203,6 @@
 {
 	RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup);
 	RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
-	struct ast_sip_session_media *session_media;
 
 	if (!datastore) {
 		return 0;
@@ -212,8 +211,7 @@
 	ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n",
 		session->channel ? ast_channel_name(session->channel) : "<gone>");
 
-	session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-	t38_change_state(session, session_media, datastore->data, T38_REJECTED);
+	t38_change_state(session, NULL, datastore->data, T38_REJECTED);
 	ast_sip_session_resume_reinvite(session);
 
 	return 0;
@@ -322,28 +320,37 @@
 		int index;
 
 		session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-		t38_change_state(session, session_media, state, T38_ENABLED);
+		if (!session_media) {
+			ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n",
+					status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel");
+		} else {
+			t38_change_state(session, session_media, state, T38_ENABLED);
 
-		/* Stop all the streams in the stored away active state, they'll go back to being active once
-		 * we reinvite back.
-		 */
-		for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
-			struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
+			/* Stop all the streams in the stored away active state, they'll go back to being active once
+			 * we reinvite back.
+			 */
+			for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
+				struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
 
-			if (session_media && session_media->handler && session_media->handler->stream_stop) {
-				session_media->handler->stream_stop(session_media);
+				if (session_media && session_media->handler && session_media->handler->stream_stop) {
+					session_media->handler->stream_stop(session_media);
+				}
 			}
+
+			return 0;
 		}
 	} else {
 		session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-		t38_change_state(session, session_media, state, T38_REJECTED);
-
-		/* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
-		ast_sip_session_media_state_free(state->media_state);
-		state->media_state = NULL;
-		ast_sip_session_media_state_reset(session->pending_media_state);
 	}
 
+	/* If no session_media then response contained a declined stream, so disable */
+	t38_change_state(session, NULL, state, session_media ? T38_REJECTED : T38_DISABLED);
+
+	/* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
+	ast_sip_session_media_state_free(state->media_state);
+	state->media_state = NULL;
+	ast_sip_session_media_state_reset(session->pending_media_state);
+
 	return 0;
 }
 
@@ -426,12 +433,10 @@
 		/* Negotiation can not take place without a valid max_ifp value. */
 		if (!parameters->max_ifp) {
 			if (data->session->t38state == T38_PEER_REINVITE) {
-				session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-				t38_change_state(data->session, session_media, state, T38_REJECTED);
+				t38_change_state(data->session, NULL, state, T38_REJECTED);
 				ast_sip_session_resume_reinvite(data->session);
 			} else if (data->session->t38state == T38_ENABLED) {
-				session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-				t38_change_state(data->session, session_media, state, T38_DISABLED);
+				t38_change_state(data->session, NULL, state, T38_DISABLED);
 				ast_sip_session_refresh(data->session, NULL, NULL, NULL,
 					AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state);
 				state->media_state = NULL;
@@ -454,6 +459,11 @@
 			state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
 			state->our_parms.rate_management = state->their_parms.rate_management;
 			session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
+			if (!session_media) {
+				ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n",
+					data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
+				break;
+			}
 			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
 			t38_change_state(data->session, session_media, state, T38_ENABLED);
 			ast_sip_session_resume_reinvite(data->session);
@@ -468,8 +478,13 @@
 			}
 			state->our_parms = *parameters;
 			session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE];
+			if (!session_media) {
+				ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n",
+					data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
+				break;
+			}
 			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
-			t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE);
+			t38_change_state(data->session, NULL, state, T38_LOCAL_REINVITE);
 			ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb,
 				AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, media_state);
 		}
@@ -478,12 +493,10 @@
 	case AST_T38_REFUSED:
 	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
 		if (data->session->t38state == T38_PEER_REINVITE) {
-			session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-			t38_change_state(data->session, session_media, state, T38_REJECTED);
+			t38_change_state(data->session, NULL, state, T38_REJECTED);
 			ast_sip_session_resume_reinvite(data->session);
 		} else if (data->session->t38state == T38_ENABLED) {
-			session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
-			t38_change_state(data->session, session_media, state, T38_DISABLED);
+			t38_change_state(data->session, NULL, state, T38_DISABLED);
 			ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state);
 			state->media_state = NULL;
 		}
@@ -493,6 +506,11 @@
 
 		if (data->session->t38state == T38_PEER_REINVITE) {
 			session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
+			if (!session_media) {
+				ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n",
+					data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
+				break;
+			}
 			parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
 			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
 			ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
@@ -788,7 +806,7 @@
 
 	if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
 		ast_debug(3, "Declining; T.38 state is rejected or declined\n");
-		t38_change_state(session, session_media, state, T38_DISABLED);
+		t38_change_state(session, NULL, state, T38_DISABLED);
 		return 0;
 	}