<p>Neels Hofmeyr <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13277">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
Harald Welte: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add caller-owns-msgb variant osmo_sccp_user_sap_down_nofree()<br><br>Add osmo_sccp_user_sap_down_nofree(), which is identical to<br>osmo_sccp_user_sap_down(), but doesn't imply a msgb_free().<br><br>To implement that, sccp_sclc_user_sap_down_nofree() with the same msgb<br>semantics is required.<br><br>Rationale:<br><br>Avoiding msgb leaks is easiest if the caller retains ownership of the msgb.<br>Take this hypothetical chain where leaks are obviously avoided:<br><br> void send()<br> {<br> msg = msgb_alloc();<br> dispatch(msg);<br> msgb_free(msg);<br> }<br><br> void dispatch(msg)<br> {<br> osmo_fsm_inst_dispatch(fi, msg);<br> }<br><br> void fi_on_event(fi, data)<br> {<br> if (socket_is_ok)<br> socket_write((struct msgb*)data);<br> }<br><br> void socket_write(msgb)<br> {<br> if (!ok1)<br> return;<br> if (ok2) {<br> if (!ok3)<br> return;<br> write(sock, msg->data);<br> }<br> }<br><br>However, if the caller passes ownership down to the msgb consumer, things<br>become nightmarishly complex:<br><br> void send()<br> {<br> msg = msgb_alloc();<br> rc = dispatch(msg);<br> /* dispatching event failed? */<br> if (rc)<br> msgb_free(msg);<br> }<br><br> int dispatch(msg)<br> {<br> if (osmo_fsm_inst_dispatch(fi, msg))<br> return -1;<br> if (something_else())<br> return -1; // <-- double free!<br> }<br><br> void fi_on_event(fi, data)<br> {<br> if (socket_is_ok) {<br> socket_write((struct msgb*)data);<br> else<br> /* socket didn't consume? */<br> msgb_free(data);<br> }<br><br> int socket_write(msgb)<br> {<br> if (!ok1)<br> return -1; // <-- leak!<br> if (ok2) {<br> if (!ok3)<br> goto out;<br> write(sock, msg->data);<br> }<br> out:<br> msgb_free(msg);<br> return -2;<br> }<br><br>If any link in this call chain fails to be aware of the importance to return a<br>failed RC or to free a msgb if the chain is broken, or to not return a failed<br>RC if the msgb is consumed, we have a hidden msgb leak or double free.<br><br>This is the case with osmo_sccp_user_sap_down(). In new osmo-msc, passing data<br>through various FSM instances, there is high potential for leak/double-free<br>bugs. A very large brain is required to track down every msgb path.<br><br>osmo_sccp_user_sap_down_nofree() makes this problem trivial to solve even for<br>humans.<br><br>Change-Id: Ic818efa78b90f727e1a94c18b60d9a306644f340<br>---<br>M include/osmocom/sigtran/sccp_sap.h<br>M src/sccp_internal.h<br>M src/sccp_sclc.c<br>M src/sccp_scoc.c<br>4 files changed, 38 insertions(+), 23 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/sigtran/sccp_sap.h b/include/osmocom/sigtran/sccp_sap.h</span><br><span>index 84d762c..f64b7aa 100644</span><br><span>--- a/include/osmocom/sigtran/sccp_sap.h</span><br><span>+++ b/include/osmocom/sigtran/sccp_sap.h</span><br><span>@@ -263,6 +263,7 @@</span><br><span> osmo_prim_cb prim_cb, uint16_t ssn);</span><br><span> </span><br><span> int osmo_sccp_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_sccp_user_sap_down_nofree(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph);</span><br><span> </span><br><span> struct osmo_ss7_instance *</span><br><span> osmo_sccp_addr_by_name(struct osmo_sccp_addr *dest_addr,</span><br><span>diff --git a/src/sccp_internal.h b/src/sccp_internal.h</span><br><span>index ad8a6fd..8df6c9b 100644</span><br><span>--- a/src/sccp_internal.h</span><br><span>+++ b/src/sccp_internal.h</span><br><span>@@ -116,6 +116,7 @@</span><br><span> </span><br><span> /* SCU -> SCLC */</span><br><span> int sccp_sclc_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph);</span><br><span style="color: hsl(120, 100%, 40%);">+int sccp_sclc_user_sap_down_nofree(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph);</span><br><span> </span><br><span> struct msgb *sccp_msgb_alloc(const char *name);</span><br><span> </span><br><span>diff --git a/src/sccp_sclc.c b/src/sccp_sclc.c</span><br><span>index db67660..218fb56 100644</span><br><span>--- a/src/sccp_sclc.c</span><br><span>+++ b/src/sccp_sclc.c</span><br><span>@@ -115,15 +115,14 @@</span><br><span> return rc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Main entrance function for primitives from SCCP User</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Main entrance function for primitives from SCCP User.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The caller is required to free oph->msg, otherwise the same as sccp_sclc_user_sap_down().</span><br><span> * \param[in] scu SCCP User who is sending the primitive</span><br><span> * \param[on] oph Osmocom primitive header of the primitive</span><br><span> * \returns 0 on success; negtive in case of error */</span><br><span style="color: hsl(0, 100%, 40%);">-int sccp_sclc_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+int sccp_sclc_user_sap_down_nofree(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph)</span><br><span> {</span><br><span> struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg = prim->oph.msg;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc = 0;</span><br><span> </span><br><span> /* we get called from osmo_sccp_user_sap_down() which already</span><br><span> * has debug-logged the primitive */</span><br><span>@@ -131,20 +130,26 @@</span><br><span> switch (OSMO_PRIM_HDR(&prim->oph)) {</span><br><span> case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_REQUEST):</span><br><span> /* Connectionless by-passes this altogether */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = xua_gen_encode_and_send(scu, -1, prim, SUA_CL_CLDT);</span><br><span style="color: hsl(0, 100%, 40%);">- goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ return xua_gen_encode_and_send(scu, -1, prim, SUA_CL_CLDT);</span><br><span> default:</span><br><span> LOGP(DLSCCP, LOGL_ERROR, "Received unknown SCCP User "</span><br><span> "primitive %s from user\n",</span><br><span> osmo_scu_prim_name(&prim->oph));</span><br><span style="color: hsl(0, 100%, 40%);">- rc = -1;</span><br><span style="color: hsl(0, 100%, 40%);">- goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-out:</span><br><span style="color: hsl(0, 100%, 40%);">- /* the SAP is supposed to consume the primitive/msgb */</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Main entrance function for primitives from SCCP User.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Implies a msgb_free(oph->msg), otherwise the same as sccp_sclc_user_sap_down_nofree().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] scu SCCP User who is sending the primitive</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[on] oph Osmocom primitive header of the primitive</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns 0 on success; negtive in case of error */</span><br><span style="color: hsl(120, 100%, 40%);">+int sccp_sclc_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = prim->oph.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = sccp_sclc_user_sap_down_nofree(scu, oph);</span><br><span> msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> return rc;</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/sccp_scoc.c b/src/sccp_scoc.c</span><br><span>index 91a1ab7..7570764 100644</span><br><span>--- a/src/sccp_scoc.c</span><br><span>+++ b/src/sccp_scoc.c</span><br><span>@@ -1694,15 +1694,15 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Main entrance function for primitives from SCCP User</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Main entrance function for primitives from SCCP User.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The caller is required to free oph->msg, otherwise the same as osmo_sccp_user_sap_down().</span><br><span> * \param[in] scu SCCP User sending us the primitive</span><br><span> * \param[in] oph Osmocom primitive sent by the user</span><br><span> * \returns 0 on success; negative on error */</span><br><span style="color: hsl(0, 100%, 40%);">-int osmo_sccp_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_sccp_user_sap_down_nofree(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph)</span><br><span> {</span><br><span> struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;</span><br><span> struct osmo_sccp_instance *inst = scu->inst;</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg = prim->oph.msg;</span><br><span> struct sccp_connection *conn;</span><br><span> int rc = 0;</span><br><span> int event;</span><br><span>@@ -1714,7 +1714,7 @@</span><br><span> case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_REQUEST):</span><br><span> /* other CL primitives? */</span><br><span> /* Connectionless by-passes this altogether */</span><br><span style="color: hsl(0, 100%, 40%);">- return sccp_sclc_user_sap_down(scu, oph);</span><br><span style="color: hsl(120, 100%, 40%);">+ return sccp_sclc_user_sap_down_nofree(scu, oph);</span><br><span> case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_REQUEST):</span><br><span> /* Allocate new connection structure */</span><br><span> conn = conn_create_id(scu, prim->u.connect.conn_id);</span><br><span>@@ -1722,7 +1722,7 @@</span><br><span> /* FIXME: inform SCCP user with proper reply */</span><br><span> LOGP(DLSCCP, LOGL_ERROR, "Cannot create conn-id for primitive %s\n",</span><br><span> osmo_scu_prim_name(&prim->oph));</span><br><span style="color: hsl(0, 100%, 40%);">- goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span> }</span><br><span> break;</span><br><span> case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_RESPONSE):</span><br><span>@@ -1735,25 +1735,33 @@</span><br><span> /* FIXME: inform SCCP user with proper reply */</span><br><span> LOGP(DLSCCP, LOGL_ERROR, "Received unknown conn-id %u for primitive %s\n",</span><br><span> scu_prim_conn_id(prim), osmo_scu_prim_name(&prim->oph));</span><br><span style="color: hsl(0, 100%, 40%);">- goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span> }</span><br><span> break;</span><br><span> default:</span><br><span> LOGP(DLSCCP, LOGL_ERROR, "Received unknown primitive %s\n",</span><br><span> osmo_scu_prim_name(&prim->oph));</span><br><span style="color: hsl(0, 100%, 40%);">- rc = -1;</span><br><span style="color: hsl(0, 100%, 40%);">- goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> /* Map from primitive to event */</span><br><span> event = osmo_event_for_prim(oph, scu_scoc_event_map);</span><br><span> </span><br><span> /* Dispatch event into connection */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_fsm_inst_dispatch(conn->fi, event, prim);</span><br><span style="color: hsl(0, 100%, 40%);">-out:</span><br><span style="color: hsl(0, 100%, 40%);">- /* the SAP is supposed to consume the primitive/msgb */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_fsm_inst_dispatch(conn->fi, event, prim);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Main entrance function for primitives from SCCP User.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Implies a msgb_free(oph->msg), otherwise the same as osmo_sccp_user_sap().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] scu SCCP User sending us the primitive</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] oph Osmocom primitive sent by the user</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_sccp_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = prim->oph.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = osmo_sccp_user_sap_down_nofree(scu, oph);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span> return rc;</span><br><span> }</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13277">change 13277</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.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.osmocom.org/13277"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: libosmo-sccp </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ic818efa78b90f727e1a94c18b60d9a306644f340 </div>
<div style="display:none"> Gerrit-Change-Number: 13277 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>