<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/11699">View Change</a></p><div style="white-space:pre-wrap">Approvals:
George Joseph: Looks good to me, but someone else must approve; Approved for Submit
Joshua Colp: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">srtp: Fix possible race condition, and add NULL checks<br><br>Somehow it's possible for the srtp session object to be NULL even though the<br>Asterisk srtp object itself is valid. When this happened it would cause a<br>crash down in the srtp code when attempting to protect or unprotect data.<br><br>After looking at the code there is at least one spot that makes this situation<br>possible. If Asterisk fails to unprotect the data, and after several retries<br>it still can't then the srtp->session gets freed, and set to NULL while still<br>leaving the Asterisk srtp object around. However, according to the original<br>issue reporter this does not appear to be their situation since they found<br>no errors logged stating the above happened (which Asterisk does for that<br>situation).<br><br>An issue was found however, where a possible race condition could occur between<br>the pjsip incoming negotiation, and the receiving of RTP packets. Both places<br>could attempt to create/setup srtp for the same rtp instance at the same time.<br>This potentially could be the cause of the problem as well.<br><br>Given the above this patch adds locking around srtp setup for a given rtp, or<br>rtcp instance. NULL checks for the session have also been added within the<br>protect and unprotect functions as a precaution. These checks should at least<br>stop Asterisk from crashing if it gets in this situation again.<br><br>This patch also fixes one other issue noticed during investigation. When doing<br>a replace the old object was freed before creating the replacement. If the new<br>replacement object failed to create then the rtp/rtcp instance would now point<br>to freed srtp data which could potentially cause a crash as well when the next<br>attempt to reference it was made. This is now fixed so the old srtp object is<br>kept upon replacement failure.<br><br>Lastly, more logging has been added to help diagnose future issues.<br><br>ASTERISK-28472<br><br>Change-Id: I240e11cbb1e9ea8083d59d50db069891228fe5cc<br>---<br>M main/rtp_engine.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_srtp.c<br>3 files changed, 33 insertions(+), 5 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/main/rtp_engine.c b/main/rtp_engine.c</span><br><span>index 2153a8f..39ad1b3 100644</span><br><span>--- a/main/rtp_engine.c</span><br><span>+++ b/main/rtp_engine.c</span><br><span>@@ -2742,6 +2742,7 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(instance);</span><br><span> </span><br><span> srtp = rtcp ? &instance->rtcp_srtp : &instance->srtp;</span><br><span> </span><br><span>@@ -2754,6 +2755,8 @@</span><br><span> res = res_srtp->add_stream(*srtp, local_policy);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return res;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c</span><br><span>index dfbaad6..8d9cece 100644</span><br><span>--- a/res/res_pjsip_sdp_rtp.c</span><br><span>+++ b/res/res_pjsip_sdp_rtp.c</span><br><span>@@ -1006,7 +1006,7 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_debug(1, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);</span><br><span> }</span><br><span> </span><br><span> /* no usable crypto attributes found */</span><br><span>diff --git a/res/res_srtp.c b/res/res_srtp.c</span><br><span>index 06d5188..3e4b51f 100644</span><br><span>--- a/res/res_srtp.c</span><br><span>+++ b/res/res_srtp.c</span><br><span>@@ -373,6 +373,12 @@</span><br><span> </span><br><span> tryagain:</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!srtp->session) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "SRTP unprotect %s - missing session\n", rtcp ? "rtcp" : "rtp");</span><br><span style="color: hsl(120, 100%, 40%);">+ errno = EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> for (i = 0; i < 2; i++) {</span><br><span> res = rtcp ? srtp_unprotect_rtcp(srtp->session, buf, len) : srtp_unprotect(srtp->session, buf, len);</span><br><span> if (res != err_status_no_ctx) {</span><br><span>@@ -481,6 +487,12 @@</span><br><span> int res;</span><br><span> unsigned char *localbuf;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!srtp->session) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "SRTP protect %s - missing session\n", rtcp ? "rtcp" : "rtp");</span><br><span style="color: hsl(120, 100%, 40%);">+ errno = EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if ((*len + SRTP_MAX_TRAILER_LEN) > sizeof(srtp->buf)) {</span><br><span> return -1;</span><br><span> }</span><br><span>@@ -501,6 +513,7 @@</span><br><span> static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy)</span><br><span> {</span><br><span> struct ast_srtp *temp;</span><br><span style="color: hsl(120, 100%, 40%);">+ int status;</span><br><span> </span><br><span> if (!(temp = res_srtp_new())) {</span><br><span> return -1;</span><br><span>@@ -508,10 +521,13 @@</span><br><span> ast_module_ref(ast_module_info->self);</span><br><span> </span><br><span> /* Any failures after this point can use ast_srtp_destroy to destroy the instance */</span><br><span style="color: hsl(0, 100%, 40%);">- if (srtp_create(&temp->session, &policy->sp) != err_status_ok) {</span><br><span style="color: hsl(120, 100%, 40%);">+ status = srtp_create(&temp->session, &policy->sp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status != err_status_ok) {</span><br><span> /* Session either wasn't created or was created and dealloced. */</span><br><span> temp->session = NULL;</span><br><span> ast_srtp_destroy(temp);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to create srtp session on rtp instance (%p) - %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp, srtp_errstr(status));</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span>@@ -525,10 +541,19 @@</span><br><span> </span><br><span> static int ast_srtp_replace(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if ((*srtp) != NULL) {</span><br><span style="color: hsl(0, 100%, 40%);">- ast_srtp_destroy(*srtp);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_srtp *old = *srtp;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = ast_srtp_create(srtp, rtp, policy);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!res && old) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_srtp_destroy(old);</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- return ast_srtp_create(srtp, rtp, policy);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to replace srtp (%p) on rtp instance (%p) "</span><br><span style="color: hsl(120, 100%, 40%);">+ "- keeping old\n", *srtp, rtp);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span> }</span><br><span> </span><br><span> static void ast_srtp_destroy(struct ast_srtp *srtp)</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/11699">change 11699</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/11699"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 17 </div>
<div style="display:none"> Gerrit-Change-Id: I240e11cbb1e9ea8083d59d50db069891228fe5cc </div>
<div style="display:none"> Gerrit-Change-Number: 11699 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>