pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-bts/+/32552?usp=email )

Change subject: trx_if: Allow calling trx_if_flush/close from within TRXC 
callback (v2)
......................................................................

trx_if: Allow calling trx_if_flush/close from within TRXC callback (v2)

- If the llist is flushed during rx rsp callback, when the flow is
  returned to trx_ctrl_read_cb() it would access tcm which was in the
llist and end up in use-after-free.
- We need to store state on whether code path is inside the read_cb in
  order to:
-- Delay transmission of new message if callback calls trx_if_flush()
   followed by trx_ctrl_send(), since the trx_ctrl_send() at the end of
   trx_ctrl_read_cb would retransmit it again immediatelly.
-- Avoid accessing tcm pointer if the callback called trx_if_flush(),
   since it has been freed.

Related: OS#6020
Change-Id: Ibdffa4644aa3a7d219452644d3e74b411734f1df
---
M src/osmo-bts-trx/l1_if.h
M src/osmo-bts-trx/trx_if.c
2 files changed, 52 insertions(+), 7 deletions(-)

Approvals:
  daniel: Looks good to me, but someone else must approve
  Jenkins Builder: Verified
  pespin: Looks good to me, approved




diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index 18d84c2..84fd4b5 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -120,6 +120,10 @@
        struct llist_head       trx_ctrl_list;
        /* Latest RSPed cmd, used to catch duplicate RSPs from sent 
retransmissions */
        struct trx_ctrl_msg     *last_acked;
+       /* Whether the code path is in the middle of handling a received 
message. */
+       bool                    in_trx_ctrl_read_cb;
+       /* Whether the l1h->trx_ctrl_list was flushed by the callback handling 
a received message */
+       bool                    flushed_while_in_trx_ctrl_read_cb;

        //struct gsm_bts_trx    *trx;
        struct phy_instance     *phy_inst;
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index 3f9fc04..89078a3 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -269,8 +269,10 @@
                tcm->cmd, tcm->params_len ? " " : "", tcm->params);
        llist_add_tail(&tcm->list, &l1h->trx_ctrl_list);

-       /* send message, if we didn't already have pending messages */
-       if (prev == NULL)
+       /* send message, if we didn't already have pending messages.
+        * If we are in the rx_rsp callback code path, skip sending, the
+        * callback will do so when returning to it. */
+       if (prev == NULL && !l1h->in_trx_ctrl_read_cb)
                trx_ctrl_send(l1h);

        return 0;
@@ -673,6 +675,7 @@
        struct trx_ctrl_rsp rsp;
        int len, rc;
        struct trx_ctrl_msg *tcm;
+       bool flushed;

        len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
        if (len <= 0)
@@ -722,21 +725,34 @@
        rsp.cb = tcm->cb;

        /* check for response code */
+       l1h->in_trx_ctrl_read_cb = true;
        rc = trx_ctrl_rx_rsp(l1h, &rsp, tcm);
+       /* Reset state: */
+       flushed = l1h->flushed_while_in_trx_ctrl_read_cb;
+       l1h->flushed_while_in_trx_ctrl_read_cb = false;
+       l1h->in_trx_ctrl_read_cb = false;
+
        if (rc == -EINVAL)
                goto rsp_error;

        /* re-schedule last cmd in rc seconds time */
        if (rc > 0) {
-               osmo_timer_schedule(&l1h->trx_ctrl_timer, rc, 0);
+               /* The queue may have been flushed in the trx_ctrl_rx_rsp(): */
+               if (!llist_empty(&l1h->trx_ctrl_list))
+                       osmo_timer_schedule(&l1h->trx_ctrl_timer, rc, 0);
                return 0;
        }

-       /* remove command from list, save it to last_acked and removed previous 
last_acked */
-       llist_del(&tcm->list);
-       talloc_free(l1h->last_acked);
-       l1h->last_acked = tcm;
+       if (!flushed) {
+               /* Remove command from list, save it to last_acked and removed
+                * previous last_acked */
+               llist_del(&tcm->list);
+               talloc_free(l1h->last_acked);
+               l1h->last_acked = tcm;
+       } /* else: tcm was freed by trx_if_flush(), do not access it. */

+
+       /* Send next message waiting in the list: */
        trx_ctrl_send(l1h);

        return 0;
@@ -1224,6 +1240,10 @@

        /* Tx queue is now empty, so there's no point in keeping the retrans 
timer armed: */
        osmo_timer_del(&l1h->trx_ctrl_timer);
+
+       /* If we are in read_cb, signal to the returning code path that we 
freed the list. */
+       if (l1h->in_trx_ctrl_read_cb)
+               l1h->flushed_while_in_trx_ctrl_read_cb = true;
 }

 /*! close the TRX for given handle (data + control socket) */

--
To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/32552?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: Ibdffa4644aa3a7d219452644d3e74b411734f1df
Gerrit-Change-Number: 32552
Gerrit-PatchSet: 7
Gerrit-Owner: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillm...@sysmocom.de>
Gerrit-Reviewer: fixeria <axilira...@gmail.com>
Gerrit-Reviewer: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: pespin <pes...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to