Skip to content

Commit 197c297

Browse files
committed
Merge branch 'xfrm & bonding: Correct use of xso.real_dev'
Cosmin Ratiu says: ==================== This patch series was motivated by fixing a few bugs in the bonding driver related to xfrm state migration on device failover. struct xfrm_dev_offload has two net_device pointers: dev and real_dev. The first one is the device the xfrm_state is offloaded on and the second one is used by the bonding driver to manage the underlying device xfrm_states are actually offloaded on. When bonding isn't used, the two pointers are the same. This causes confusion in drivers: Which device pointer should they use? If they want to support bonding, they need to only use real_dev and never look at dev. Furthermore, real_dev is used without proper locking from multiple code paths and changing it is dangerous. See commit [1] for example. This patch series clears things out by removing all uses of real_dev from outside the bonding driver. Then, the bonding driver is refactored to fix a couple of long standing races and the original bug which motivated this patch series. [1] commit f8cde98 ("bonding: fix xfrm real_dev null pointer dereference") v2 -> v3: Added a comment with locking expectations for real_dev. Removed unnecessary bond variable from bond_ipsec_del_sa(). v1 -> v2: Added missing kdoc for various functions. Made bond_ipsec_del_sa() use xso.real_dev instead of curr_active_slave. ==================== Signed-off-by: Steffen Klassert <[email protected]>
2 parents 20eb35d + d2fddbd commit 197c297

File tree

15 files changed

+185
-167
lines changed

15 files changed

+185
-167
lines changed

Documentation/networking/xfrm_device.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,13 @@ Callbacks to implement
6565
/* from include/linux/netdevice.h */
6666
struct xfrmdev_ops {
6767
/* Crypto and Packet offload callbacks */
68-
int (*xdo_dev_state_add) (struct xfrm_state *x, struct netlink_ext_ack *extack);
69-
void (*xdo_dev_state_delete) (struct xfrm_state *x);
70-
void (*xdo_dev_state_free) (struct xfrm_state *x);
68+
int (*xdo_dev_state_add)(struct net_device *dev,
69+
struct xfrm_state *x,
70+
struct netlink_ext_ack *extack);
71+
void (*xdo_dev_state_delete)(struct net_device *dev,
72+
struct xfrm_state *x);
73+
void (*xdo_dev_state_free)(struct net_device *dev,
74+
struct xfrm_state *x);
7175
bool (*xdo_dev_offload_ok) (struct sk_buff *skb,
7276
struct xfrm_state *x);
7377
void (*xdo_dev_state_advance_esn) (struct xfrm_state *x);

drivers/net/bonding/bond_main.c

Lines changed: 58 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -453,13 +453,14 @@ static struct net_device *bond_ipsec_dev(struct xfrm_state *xs)
453453

454454
/**
455455
* bond_ipsec_add_sa - program device with a security association
456+
* @bond_dev: pointer to the bond net device
456457
* @xs: pointer to transformer state struct
457458
* @extack: extack point to fill failure reason
458459
**/
459-
static int bond_ipsec_add_sa(struct xfrm_state *xs,
460+
static int bond_ipsec_add_sa(struct net_device *bond_dev,
461+
struct xfrm_state *xs,
460462
struct netlink_ext_ack *extack)
461463
{
462-
struct net_device *bond_dev = xs->xso.dev;
463464
struct net_device *real_dev;
464465
netdevice_tracker tracker;
465466
struct bond_ipsec *ipsec;
@@ -495,9 +496,9 @@ static int bond_ipsec_add_sa(struct xfrm_state *xs,
495496
goto out;
496497
}
497498

498-
xs->xso.real_dev = real_dev;
499-
err = real_dev->xfrmdev_ops->xdo_dev_state_add(xs, extack);
499+
err = real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev, xs, extack);
500500
if (!err) {
501+
xs->xso.real_dev = real_dev;
501502
ipsec->xs = xs;
502503
INIT_LIST_HEAD(&ipsec->list);
503504
mutex_lock(&bond->ipsec_lock);
@@ -539,66 +540,53 @@ static void bond_ipsec_add_sa_all(struct bonding *bond)
539540
if (ipsec->xs->xso.real_dev == real_dev)
540541
continue;
541542

542-
ipsec->xs->xso.real_dev = real_dev;
543-
if (real_dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs, NULL)) {
543+
if (real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev,
544+
ipsec->xs, NULL)) {
544545
slave_warn(bond_dev, real_dev, "%s: failed to add SA\n", __func__);
545-
ipsec->xs->xso.real_dev = NULL;
546+
continue;
546547
}
548+
549+
spin_lock_bh(&ipsec->xs->lock);
550+
/* xs might have been killed by the user during the migration
551+
* to the new dev, but bond_ipsec_del_sa() should have done
552+
* nothing, as xso.real_dev is NULL.
553+
* Delete it from the device we just added it to. The pending
554+
* bond_ipsec_free_sa() call will do the rest of the cleanup.
555+
*/
556+
if (ipsec->xs->km.state == XFRM_STATE_DEAD &&
557+
real_dev->xfrmdev_ops->xdo_dev_state_delete)
558+
real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
559+
ipsec->xs);
560+
ipsec->xs->xso.real_dev = real_dev;
561+
spin_unlock_bh(&ipsec->xs->lock);
547562
}
548563
out:
549564
mutex_unlock(&bond->ipsec_lock);
550565
}
551566

552567
/**
553568
* bond_ipsec_del_sa - clear out this specific SA
569+
* @bond_dev: pointer to the bond net device
554570
* @xs: pointer to transformer state struct
555571
**/
556-
static void bond_ipsec_del_sa(struct xfrm_state *xs)
572+
static void bond_ipsec_del_sa(struct net_device *bond_dev,
573+
struct xfrm_state *xs)
557574
{
558-
struct net_device *bond_dev = xs->xso.dev;
559575
struct net_device *real_dev;
560-
netdevice_tracker tracker;
561-
struct bond_ipsec *ipsec;
562-
struct bonding *bond;
563-
struct slave *slave;
564576

565-
if (!bond_dev)
577+
if (!bond_dev || !xs->xso.real_dev)
566578
return;
567579

568-
rcu_read_lock();
569-
bond = netdev_priv(bond_dev);
570-
slave = rcu_dereference(bond->curr_active_slave);
571-
real_dev = slave ? slave->dev : NULL;
572-
netdev_hold(real_dev, &tracker, GFP_ATOMIC);
573-
rcu_read_unlock();
574-
575-
if (!slave)
576-
goto out;
577-
578-
if (!xs->xso.real_dev)
579-
goto out;
580-
581-
WARN_ON(xs->xso.real_dev != real_dev);
580+
real_dev = xs->xso.real_dev;
582581

583582
if (!real_dev->xfrmdev_ops ||
584583
!real_dev->xfrmdev_ops->xdo_dev_state_delete ||
585584
netif_is_bond_master(real_dev)) {
586585
slave_warn(bond_dev, real_dev, "%s: no slave xdo_dev_state_delete\n", __func__);
587-
goto out;
586+
return;
588587
}
589588

590-
real_dev->xfrmdev_ops->xdo_dev_state_delete(xs);
591-
out:
592-
netdev_put(real_dev, &tracker);
593-
mutex_lock(&bond->ipsec_lock);
594-
list_for_each_entry(ipsec, &bond->ipsec_list, list) {
595-
if (ipsec->xs == xs) {
596-
list_del(&ipsec->list);
597-
kfree(ipsec);
598-
break;
599-
}
600-
}
601-
mutex_unlock(&bond->ipsec_lock);
589+
real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev, xs);
602590
}
603591

604592
static void bond_ipsec_del_sa_all(struct bonding *bond)
@@ -624,46 +612,55 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
624612
slave_warn(bond_dev, real_dev,
625613
"%s: no slave xdo_dev_state_delete\n",
626614
__func__);
627-
} else {
628-
real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
629-
if (real_dev->xfrmdev_ops->xdo_dev_state_free)
630-
real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
615+
continue;
631616
}
617+
618+
spin_lock_bh(&ipsec->xs->lock);
619+
ipsec->xs->xso.real_dev = NULL;
620+
/* Don't double delete states killed by the user. */
621+
if (ipsec->xs->km.state != XFRM_STATE_DEAD)
622+
real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
623+
ipsec->xs);
624+
spin_unlock_bh(&ipsec->xs->lock);
625+
626+
if (real_dev->xfrmdev_ops->xdo_dev_state_free)
627+
real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev,
628+
ipsec->xs);
632629
}
633630
mutex_unlock(&bond->ipsec_lock);
634631
}
635632

636-
static void bond_ipsec_free_sa(struct xfrm_state *xs)
633+
static void bond_ipsec_free_sa(struct net_device *bond_dev,
634+
struct xfrm_state *xs)
637635
{
638-
struct net_device *bond_dev = xs->xso.dev;
639636
struct net_device *real_dev;
640-
netdevice_tracker tracker;
637+
struct bond_ipsec *ipsec;
641638
struct bonding *bond;
642-
struct slave *slave;
643639

644640
if (!bond_dev)
645641
return;
646642

647-
rcu_read_lock();
648643
bond = netdev_priv(bond_dev);
649-
slave = rcu_dereference(bond->curr_active_slave);
650-
real_dev = slave ? slave->dev : NULL;
651-
netdev_hold(real_dev, &tracker, GFP_ATOMIC);
652-
rcu_read_unlock();
653-
654-
if (!slave)
655-
goto out;
656644

645+
mutex_lock(&bond->ipsec_lock);
657646
if (!xs->xso.real_dev)
658647
goto out;
659648

660-
WARN_ON(xs->xso.real_dev != real_dev);
649+
real_dev = xs->xso.real_dev;
661650

662-
if (real_dev && real_dev->xfrmdev_ops &&
651+
xs->xso.real_dev = NULL;
652+
if (real_dev->xfrmdev_ops &&
663653
real_dev->xfrmdev_ops->xdo_dev_state_free)
664-
real_dev->xfrmdev_ops->xdo_dev_state_free(xs);
654+
real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev, xs);
665655
out:
666-
netdev_put(real_dev, &tracker);
656+
list_for_each_entry(ipsec, &bond->ipsec_list, list) {
657+
if (ipsec->xs == xs) {
658+
list_del(&ipsec->list);
659+
kfree(ipsec);
660+
break;
661+
}
662+
}
663+
mutex_unlock(&bond->ipsec_lock);
667664
}
668665

669666
/**

drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6480,10 +6480,11 @@ static const struct tlsdev_ops cxgb4_ktls_ops = {
64806480

64816481
#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE)
64826482

6483-
static int cxgb4_xfrm_add_state(struct xfrm_state *x,
6483+
static int cxgb4_xfrm_add_state(struct net_device *dev,
6484+
struct xfrm_state *x,
64846485
struct netlink_ext_ack *extack)
64856486
{
6486-
struct adapter *adap = netdev2adap(x->xso.dev);
6487+
struct adapter *adap = netdev2adap(dev);
64876488
int ret;
64886489

64896490
if (!mutex_trylock(&uld_mutex)) {
@@ -6494,17 +6495,18 @@ static int cxgb4_xfrm_add_state(struct xfrm_state *x,
64946495
if (ret)
64956496
goto out_unlock;
64966497

6497-
ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(x, extack);
6498+
ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(dev, x,
6499+
extack);
64986500

64996501
out_unlock:
65006502
mutex_unlock(&uld_mutex);
65016503

65026504
return ret;
65036505
}
65046506

6505-
static void cxgb4_xfrm_del_state(struct xfrm_state *x)
6507+
static void cxgb4_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
65066508
{
6507-
struct adapter *adap = netdev2adap(x->xso.dev);
6509+
struct adapter *adap = netdev2adap(dev);
65086510

65096511
if (!mutex_trylock(&uld_mutex)) {
65106512
dev_dbg(adap->pdev_dev,
@@ -6514,15 +6516,15 @@ static void cxgb4_xfrm_del_state(struct xfrm_state *x)
65146516
if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
65156517
goto out_unlock;
65166518

6517-
adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(x);
6519+
adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(dev, x);
65186520

65196521
out_unlock:
65206522
mutex_unlock(&uld_mutex);
65216523
}
65226524

6523-
static void cxgb4_xfrm_free_state(struct xfrm_state *x)
6525+
static void cxgb4_xfrm_free_state(struct net_device *dev, struct xfrm_state *x)
65246526
{
6525-
struct adapter *adap = netdev2adap(x->xso.dev);
6527+
struct adapter *adap = netdev2adap(dev);
65266528

65276529
if (!mutex_trylock(&uld_mutex)) {
65286530
dev_dbg(adap->pdev_dev,
@@ -6532,7 +6534,7 @@ static void cxgb4_xfrm_free_state(struct xfrm_state *x)
65326534
if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
65336535
goto out_unlock;
65346536

6535-
adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(x);
6537+
adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(dev, x);
65366538

65376539
out_unlock:
65386540
mutex_unlock(&uld_mutex);

drivers/net/ethernet/chelsio/inline_crypto/ch_ipsec/chcr_ipsec.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,12 @@ static int ch_ipsec_uld_state_change(void *handle, enum cxgb4_state new_state);
7575
static int ch_ipsec_xmit(struct sk_buff *skb, struct net_device *dev);
7676
static void *ch_ipsec_uld_add(const struct cxgb4_lld_info *infop);
7777
static void ch_ipsec_advance_esn_state(struct xfrm_state *x);
78-
static void ch_ipsec_xfrm_free_state(struct xfrm_state *x);
79-
static void ch_ipsec_xfrm_del_state(struct xfrm_state *x);
80-
static int ch_ipsec_xfrm_add_state(struct xfrm_state *x,
78+
static void ch_ipsec_xfrm_free_state(struct net_device *dev,
79+
struct xfrm_state *x);
80+
static void ch_ipsec_xfrm_del_state(struct net_device *dev,
81+
struct xfrm_state *x);
82+
static int ch_ipsec_xfrm_add_state(struct net_device *dev,
83+
struct xfrm_state *x,
8184
struct netlink_ext_ack *extack);
8285

8386
static const struct xfrmdev_ops ch_ipsec_xfrmdev_ops = {
@@ -223,7 +226,8 @@ static int ch_ipsec_setkey(struct xfrm_state *x,
223226
* returns 0 on success, negative error if failed to send message to FPGA
224227
* positive error if FPGA returned a bad response
225228
*/
226-
static int ch_ipsec_xfrm_add_state(struct xfrm_state *x,
229+
static int ch_ipsec_xfrm_add_state(struct net_device *dev,
230+
struct xfrm_state *x,
227231
struct netlink_ext_ack *extack)
228232
{
229233
struct ipsec_sa_entry *sa_entry;
@@ -302,14 +306,16 @@ static int ch_ipsec_xfrm_add_state(struct xfrm_state *x,
302306
return res;
303307
}
304308

305-
static void ch_ipsec_xfrm_del_state(struct xfrm_state *x)
309+
static void ch_ipsec_xfrm_del_state(struct net_device *dev,
310+
struct xfrm_state *x)
306311
{
307312
/* do nothing */
308313
if (!x->xso.offload_handle)
309314
return;
310315
}
311316

312-
static void ch_ipsec_xfrm_free_state(struct xfrm_state *x)
317+
static void ch_ipsec_xfrm_free_state(struct net_device *dev,
318+
struct xfrm_state *x)
313319
{
314320
struct ipsec_sa_entry *sa_entry;
315321

0 commit comments

Comments
 (0)