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);}
...