From 41589a3e7af0c7ea02785cb113888a96790989dd Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Mon, 19 Jul 2021 03:40:02 +0200 Subject: gprs_ns2: add recursive anchor to protect against double free When free'ing a NSE/NSVC/BIND ensure there can't be a double free by using a free anchor in the struct. Recursive free's can happen when the NS user reacts on an event (e.g. GPRS_NS2_AFF_CAUSE_VC_FAILURE) and calls the free(). Or when the user free's a NSVC when the NSE uses SNS as configuration, the fsm tries to free it again. Change-Id: If9823aadaa936e136aa43e88cee925ddd5974841 --- src/gb/gprs_ns2.c | 16 +++++++++++----- src/gb/gprs_ns2_internal.h | 9 +++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c index fb2965a3..45cdfcc1 100644 --- a/src/gb/gprs_ns2.c +++ b/src/gb/gprs_ns2.c @@ -639,9 +639,9 @@ err: * \param[in] nsvc NS-VC to destroy */ void gprs_ns2_free_nsvc(struct gprs_ns2_vc *nsvc) { - if (!nsvc) + if (!nsvc || nsvc->freed) return; - + nsvc->freed = true; ns2_prim_status_ind(nsvc->nse, nsvc, 0, GPRS_NS2_AFF_CAUSE_VC_FAILURE); llist_del(&nsvc->list); @@ -671,7 +671,7 @@ void gprs_ns2_free_nsvcs(struct gprs_ns2_nse *nse) { struct gprs_ns2_vc *nsvc, *tmp; - if (!nse) + if (!nse || nse->freed) return; llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) { @@ -889,9 +889,11 @@ uint16_t gprs_ns2_nse_nsei(struct gprs_ns2_nse *nse) * \param[in] nse NS Entity to destroy */ void gprs_ns2_free_nse(struct gprs_ns2_nse *nse) { - if (!nse) + struct gprs_ns2_vc *nsvc, *nsvc2; + if (!nse || nse->freed) return; + nse->freed = true; nse->alive = false; if (nse->bss_sns_fi) { osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL); @@ -901,6 +903,9 @@ void gprs_ns2_free_nse(struct gprs_ns2_nse *nse) gprs_ns2_free_nsvcs(nse); ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_FAILURE); rate_ctr_group_free(nse->ctrg); + llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) { + gprs_ns2_free_nsvc(nsvc); + } llist_del(&nse->list); talloc_free(nse); @@ -1466,9 +1471,10 @@ void gprs_ns2_free_bind(struct gprs_ns2_vc_bind *bind) { struct gprs_ns2_vc *nsvc, *tmp; struct gprs_ns2_nse *nse; - if (!bind) + if (!bind || bind->freed) return; + bind->freed = true; llist_for_each_entry_safe(nsvc, tmp, &bind->nsvc, blist) { gprs_ns2_free_nsvc(nsvc); } diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h index db01c2ee..95efbae7 100644 --- a/src/gb/gprs_ns2_internal.h +++ b/src/gb/gprs_ns2_internal.h @@ -215,6 +215,9 @@ struct gprs_ns2_nse { /*! NSE-wide statistics */ struct rate_ctr_group *ctrg; + + /*! recursive anchor */ + bool freed; }; /*! Structure representing a single NS-VC */ @@ -259,6 +262,9 @@ struct gprs_ns2_vc { enum gprs_ns2_vc_mode mode; struct osmo_fsm_inst *fi; + + /*! recursive anchor */ + bool freed; }; /*! Structure repesenting a bind instance. E.g. IPv4 listen port. */ @@ -303,6 +309,9 @@ struct gprs_ns2_vc_bind { uint8_t sns_data_weight; struct osmo_stat_item_group *statg; + + /*! recursive anchor */ + bool freed; }; struct gprs_ns2_vc_driver { -- cgit v1.2.3