bnxt_free_filter_mem() freed each filter and then passed the freed
pointer to STAILQ_REMOVE, which walks the list to unlink it.
STAILQ_FOREACH also read the next pointer out of the freed element.

Remove the entry from the list before freeing it, and use
STAILQ_FOREACH_SAFE so that the iteration does not depend on the
element that was just freed. glibc does not provide the _SAFE
variants, so define it locally the same way several other drivers
already do.

Found while moving the list macros into a DPDK header, where the
compiler could see them and report -Wuse-after-free. The fix does
not depend on that work.

Fixes: f11fd694a84a ("net/bnxt: free memory allocated for VF filters")
Cc: [email protected]

Signed-off-by: Stephen Hemminger <[email protected]>
---
 drivers/net/bnxt/bnxt_filter.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_filter.c b/drivers/net/bnxt/bnxt_filter.c
index 7b90ba651f..0225215dae 100644
--- a/drivers/net/bnxt/bnxt_filter.c
+++ b/drivers/net/bnxt/bnxt_filter.c
@@ -18,6 +18,13 @@
 #include "bnxt_vnic.h"
 #include "hsi_struct_def_dpdk.h"
 
+#ifndef STAILQ_FOREACH_SAFE
+#define        STAILQ_FOREACH_SAFE(var, head, field, tvar)                     
\
+       for ((var) = STAILQ_FIRST((head));                              \
+           (var) && ((tvar) = STAILQ_NEXT((var), field), 1);           \
+           (var) = (tvar))
+#endif
+
 /*
  * Filter Functions
  */
@@ -110,7 +117,7 @@ void bnxt_free_all_filters(struct bnxt *bp)
 
 void bnxt_free_filter_mem(struct bnxt *bp)
 {
-       struct bnxt_filter_info *filter;
+       struct bnxt_filter_info *filter, *temp_filter;
        uint16_t max_filters, i;
        int rc = 0;
 
@@ -151,10 +158,11 @@ void bnxt_free_filter_mem(struct bnxt *bp)
        bp->filter_info = NULL;
 
        for (i = 0; i < bp->pf->max_vfs; i++) {
-               STAILQ_FOREACH(filter, &bp->pf->vf_info[i].filter, next) {
-                       rte_free(filter);
+               STAILQ_FOREACH_SAFE(filter, &bp->pf->vf_info[i].filter, next,
+                                   temp_filter) {
                        STAILQ_REMOVE(&bp->pf->vf_info[i].filter, filter,
                                      bnxt_filter_info, next);
+                       rte_free(filter);
                }
        }
 }
-- 
2.53.0

Reply via email to