@@ -392,9 +392,15 @@ static void flow_offload_del(struct nf_flowtable *flow_table,
void flow_offload_teardown(struct flow_offload *flow)
{
- clear_bit(IPS_OFFLOAD_BIT, &flow->ct->status);
- if (!test_and_set_bit(NF_FLOW_TEARDOWN, &flow->flags))
+ if (unlikely(!refcount_inc_not_zero(&flow->ct->ct_general.use)))
+ return;
+
+ if (!test_and_set_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
flow_offload_fixup_ct(flow);
+ smp_mb__before_atomic();
+ clear_bit(IPS_OFFLOAD_BIT, &flow->ct->status);
+ }
+ nf_ct_put(flow->ct);
}
EXPORT_SYMBOL_GPL(flow_offload_teardown);
The existing ct state and timeout fix up after setting the teardown bit is unsafe. The flowtable GC owns the flow entry once the teardown bit is set on. Therefore, it might release the flow entry and drop the reference on the ct while the ct fix up is being performed from either packet path or netdevice notifier. Bump the ct refcount, in combination with the teardown bit, as a synchronization point, if refcount is zero, then this flow is being teardown. Furthermore, if the teardown bit has been already set, then this CPU lost race to tear down this flow. Fixes: d2d31ea8cd80 ("netfilter: conntrack: fix erronous removal of offload bit") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- v1: new in this series. net/netfilter/nf_flow_table_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)