On Sat, Mar 08, 2025 at 08:54:51AM +0000, Simon Horman wrote:
On Fri, Mar 07, 2025 at 03:19:01AM +0000, Hangbin Liu wrote:
...
@@ -616,9 +615,22 @@ static void bond_ipsec_del_sa_all(struct bonding *bond) return; mutex_lock(&bond->ipsec_lock);
- list_for_each_entry(ipsec, &bond->ipsec_list, list) {
if (!ipsec->xs->xso.real_dev)
- list_for_each_entry_safe(ipsec, tmp_ipsec, &bond->ipsec_list, list) {
spin_lock_bh(&ipsec->xs->lock);
if (!ipsec->xs->xso.real_dev) {
spin_unlock_bh(&ipsec->xs->lock); continue;
}
if (ipsec->xs->km.state == XFRM_STATE_DEAD) {
list_del(&ipsec->list);
kfree(ipsec);
Hi Hangbin,
Apologies if this was covered elsewhere, but ipsec is kfree'd here...
Oh.. I need to get the xs with xs = ipsec->xs, then hold the xs lock.
Thanks Hangbin
/* Need to free device here, or the xs->xso.real_dev
* may changed in bond_ipsec_add_sa_all and free
* on old device will never be called.
*/
goto next;
}
if (!real_dev->xfrmdev_ops || !real_dev->xfrmdev_ops->xdo_dev_state_delete || @@ -626,11 +638,20 @@ static void bond_ipsec_del_sa_all(struct bonding *bond) slave_warn(bond_dev, real_dev, "%s: no slave xdo_dev_state_delete\n", __func__);
} else {
real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
if (real_dev->xfrmdev_ops->xdo_dev_state_free)
real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
spin_unlock_bh(&ipsec->xs->lock);
}continue;
real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
+next:
/* set real_dev to NULL in case __xfrm_state_delete() is called in parallel */
ipsec->xs->xso.real_dev = NULL;
... and the dereferenced here.
Flagged by Smatch.
/* Unlock before freeing device state, it could sleep. */
spin_unlock_bh(&ipsec->xs->lock);
if (real_dev->xfrmdev_ops->xdo_dev_state_free)
} mutex_unlock(&bond->ipsec_lock);real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
}
...