|
@@ -155,6 +155,18 @@ nf_ct_find_expectation(struct net *net, u16 zone,
|
|
|
if (!nf_ct_is_confirmed(exp->master))
|
|
|
return NULL;
|
|
|
|
|
|
+ /* Avoid race with other CPUs, that for exp->master ct, is
|
|
|
+ * about to invoke ->destroy(), or nf_ct_delete() via timeout
|
|
|
+ * or early_drop().
|
|
|
+ *
|
|
|
+ * The atomic_inc_not_zero() check tells: If that fails, we
|
|
|
+ * know that the ct is being destroyed. If it succeeds, we
|
|
|
+ * can be sure the ct cannot disappear underneath.
|
|
|
+ */
|
|
|
+ if (unlikely(nf_ct_is_dying(exp->master) ||
|
|
|
+ !atomic_inc_not_zero(&exp->master->ct_general.use)))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
if (exp->flags & NF_CT_EXPECT_PERMANENT) {
|
|
|
atomic_inc(&exp->use);
|
|
|
return exp;
|
|
@@ -162,6 +174,8 @@ nf_ct_find_expectation(struct net *net, u16 zone,
|
|
|
nf_ct_unlink_expect(exp);
|
|
|
return exp;
|
|
|
}
|
|
|
+ /* Undo exp->master refcnt increase, if del_timer() failed */
|
|
|
+ nf_ct_put(exp->master);
|
|
|
|
|
|
return NULL;
|
|
|
}
|