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