<p>Neels Hofmeyr has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/13277">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add caller-owns-msgb variant osmo_sccp_user_sap_down2()<br><br>Add osmo_sccp_user_sap_down2(), 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_down2() with the same msgb semantics is<br>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_down2() makes this problem trivial to solve even for 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, 36 insertions(+), 23 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmo-sccp refs/changes/77/13277/1</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..f1fdd98 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_down2(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 000f0f7..f4c723f 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_down2(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..bfaaafc 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.</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_down2(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,25 @@</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%);">+/*! Same as sccp_sclc_user_sap_down2() but implies a msgb_free(oph->msg).</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_down2(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 cb1d567..6a56692 100644</span><br><span>--- a/src/sccp_scoc.c</span><br><span>+++ b/src/sccp_scoc.c</span><br><span>@@ -1687,15 +1687,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.</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_down2(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>@@ -1707,7 +1707,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_down2(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(inst, prim->u.connect.conn_id);</span><br><span>@@ -1715,7 +1715,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>            conn->user = scu;</span><br><span>                 break;</span><br><span>@@ -1729,25 +1729,32 @@</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%);">+/*! Same as osmo_sccp_user_sap_down2() but implies a msgb_free(oph->msg).</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_down2(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: newchange </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: 1 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>