Skip to content

Commit 70c676c

Browse files
committed
Merge tag 'ipsec-2024-07-11' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2024-07-11 1) Fix esp_output_tail_tcp() on unsupported ESPINTCP. From Hagar Hemdan. 2) Fix two bugs in the recently introduced SA direction separation. From Antony Antony. 3) Fix unregister netdevice hang on hardware offload. We had to add another list where skbs linked to that are unlinked from the lists (deleted) but not yet freed. 4) Fix netdev reference count imbalance in xfrm_state_find. From Jianbo Liu. 5) Call xfrm_dev_policy_delete when killingi them on offloaded policies. Jianbo Liu. * tag 'ipsec-2024-07-11' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec: xfrm: call xfrm_dev_policy_delete when kill policy xfrm: fix netdev reference count imbalance xfrm: Export symbol xfrm_dev_state_delete. xfrm: Fix unregister netdevice hang on hardware offload. xfrm: Log input direction mismatch error in one place xfrm: Fix input error path memory access net: esp: cleanup esp_output_tail_tcp() in case of unsupported ESPINTCP ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 528dd46 + 89a2aef commit 70c676c

File tree

9 files changed

+92
-43
lines changed

9 files changed

+92
-43
lines changed

include/net/xfrm.h

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,10 @@ struct xfrm_state {
178178
struct hlist_node gclist;
179179
struct hlist_node bydst;
180180
};
181-
struct hlist_node bysrc;
181+
union {
182+
struct hlist_node dev_gclist;
183+
struct hlist_node bysrc;
184+
};
182185
struct hlist_node byspi;
183186
struct hlist_node byseq;
184187

@@ -1588,7 +1591,7 @@ void xfrm_state_update_stats(struct net *net);
15881591
static inline void xfrm_dev_state_update_stats(struct xfrm_state *x)
15891592
{
15901593
struct xfrm_dev_offload *xdo = &x->xso;
1591-
struct net_device *dev = xdo->dev;
1594+
struct net_device *dev = READ_ONCE(xdo->dev);
15921595

15931596
if (dev && dev->xfrmdev_ops &&
15941597
dev->xfrmdev_ops->xdo_dev_state_update_stats)
@@ -1946,13 +1949,16 @@ int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
19461949
struct xfrm_user_offload *xuo, u8 dir,
19471950
struct netlink_ext_ack *extack);
19481951
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
1952+
void xfrm_dev_state_delete(struct xfrm_state *x);
1953+
void xfrm_dev_state_free(struct xfrm_state *x);
19491954

19501955
static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
19511956
{
19521957
struct xfrm_dev_offload *xso = &x->xso;
1958+
struct net_device *dev = READ_ONCE(xso->dev);
19531959

1954-
if (xso->dev && xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn)
1955-
xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
1960+
if (dev && dev->xfrmdev_ops->xdo_dev_state_advance_esn)
1961+
dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
19561962
}
19571963

19581964
static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
@@ -1973,28 +1979,6 @@ static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
19731979
return false;
19741980
}
19751981

1976-
static inline void xfrm_dev_state_delete(struct xfrm_state *x)
1977-
{
1978-
struct xfrm_dev_offload *xso = &x->xso;
1979-
1980-
if (xso->dev)
1981-
xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
1982-
}
1983-
1984-
static inline void xfrm_dev_state_free(struct xfrm_state *x)
1985-
{
1986-
struct xfrm_dev_offload *xso = &x->xso;
1987-
struct net_device *dev = xso->dev;
1988-
1989-
if (dev && dev->xfrmdev_ops) {
1990-
if (dev->xfrmdev_ops->xdo_dev_state_free)
1991-
dev->xfrmdev_ops->xdo_dev_state_free(x);
1992-
xso->dev = NULL;
1993-
xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
1994-
netdev_put(dev, &xso->dev_tracker);
1995-
}
1996-
}
1997-
19981982
static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
19991983
{
20001984
struct xfrm_dev_offload *xdo = &x->xdo;

net/ipv4/esp4.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
239239
#else
240240
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
241241
{
242-
kfree_skb(skb);
243-
242+
WARN_ON(1);
244243
return -EOPNOTSUPP;
245244
}
246245
#endif

net/ipv4/esp4_offload.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
5656
x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
5757
(xfrm_address_t *)&ip_hdr(skb)->daddr,
5858
spi, IPPROTO_ESP, AF_INET);
59+
60+
if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) {
61+
/* non-offload path will record the error and audit log */
62+
xfrm_state_put(x);
63+
x = NULL;
64+
}
65+
5966
if (!x)
6067
goto out_reset;
6168

net/ipv6/esp6.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
256256
#else
257257
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
258258
{
259-
kfree_skb(skb);
260-
259+
WARN_ON(1);
261260
return -EOPNOTSUPP;
262261
}
263262
#endif

net/ipv6/esp6_offload.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
8383
x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
8484
(xfrm_address_t *)&ipv6_hdr(skb)->daddr,
8585
spi, IPPROTO_ESP, AF_INET6);
86+
87+
if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) {
88+
/* non-offload path will record the error and audit log */
89+
xfrm_state_put(x);
90+
x = NULL;
91+
}
92+
8693
if (!x)
8794
goto out_reset;
8895

net/xfrm/xfrm_input.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -474,11 +474,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
474474
if (encap_type < 0 || (xo && xo->flags & XFRM_GRO)) {
475475
x = xfrm_input_state(skb);
476476

477-
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
478-
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
479-
goto drop;
480-
}
481-
482477
if (unlikely(x->km.state != XFRM_STATE_VALID)) {
483478
if (x->km.state == XFRM_STATE_ACQ)
484479
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
@@ -585,8 +580,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
585580
}
586581

587582
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
583+
secpath_reset(skb);
588584
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
585+
xfrm_audit_state_notfound(skb, family, spi, seq);
589586
xfrm_state_put(x);
587+
x = NULL;
590588
goto drop;
591589
}
592590

net/xfrm/xfrm_policy.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ EXPORT_SYMBOL(xfrm_policy_destroy);
452452

453453
static void xfrm_policy_kill(struct xfrm_policy *policy)
454454
{
455+
xfrm_dev_policy_delete(policy);
456+
455457
write_lock_bh(&policy->lock);
456458
policy->walk.dead = 1;
457459
write_unlock_bh(&policy->lock);
@@ -1850,7 +1852,6 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
18501852

18511853
__xfrm_policy_unlink(pol, dir);
18521854
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1853-
xfrm_dev_policy_delete(pol);
18541855
cnt++;
18551856
xfrm_audit_policy_delete(pol, 1, task_valid);
18561857
xfrm_policy_kill(pol);
@@ -1891,7 +1892,6 @@ int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
18911892

18921893
__xfrm_policy_unlink(pol, dir);
18931894
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1894-
xfrm_dev_policy_delete(pol);
18951895
cnt++;
18961896
xfrm_audit_policy_delete(pol, 1, task_valid);
18971897
xfrm_policy_kill(pol);
@@ -2342,7 +2342,6 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
23422342
pol = __xfrm_policy_unlink(pol, dir);
23432343
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
23442344
if (pol) {
2345-
xfrm_dev_policy_delete(pol);
23462345
xfrm_policy_kill(pol);
23472346
return 0;
23482347
}

net/xfrm/xfrm_state.c

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ static struct kmem_cache *xfrm_state_cache __ro_after_init;
4949

5050
static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task);
5151
static HLIST_HEAD(xfrm_state_gc_list);
52+
static HLIST_HEAD(xfrm_state_dev_gc_list);
5253

5354
static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
5455
{
@@ -214,6 +215,7 @@ static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
214215
static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
215216

216217
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
218+
static DEFINE_SPINLOCK(xfrm_state_dev_gc_lock);
217219

218220
int __xfrm_state_delete(struct xfrm_state *x);
219221

@@ -683,6 +685,41 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
683685
}
684686
EXPORT_SYMBOL(xfrm_state_alloc);
685687

688+
#ifdef CONFIG_XFRM_OFFLOAD
689+
void xfrm_dev_state_delete(struct xfrm_state *x)
690+
{
691+
struct xfrm_dev_offload *xso = &x->xso;
692+
struct net_device *dev = READ_ONCE(xso->dev);
693+
694+
if (dev) {
695+
dev->xfrmdev_ops->xdo_dev_state_delete(x);
696+
spin_lock_bh(&xfrm_state_dev_gc_lock);
697+
hlist_add_head(&x->dev_gclist, &xfrm_state_dev_gc_list);
698+
spin_unlock_bh(&xfrm_state_dev_gc_lock);
699+
}
700+
}
701+
EXPORT_SYMBOL_GPL(xfrm_dev_state_delete);
702+
703+
void xfrm_dev_state_free(struct xfrm_state *x)
704+
{
705+
struct xfrm_dev_offload *xso = &x->xso;
706+
struct net_device *dev = READ_ONCE(xso->dev);
707+
708+
if (dev && dev->xfrmdev_ops) {
709+
spin_lock_bh(&xfrm_state_dev_gc_lock);
710+
if (!hlist_unhashed(&x->dev_gclist))
711+
hlist_del(&x->dev_gclist);
712+
spin_unlock_bh(&xfrm_state_dev_gc_lock);
713+
714+
if (dev->xfrmdev_ops->xdo_dev_state_free)
715+
dev->xfrmdev_ops->xdo_dev_state_free(x);
716+
WRITE_ONCE(xso->dev, NULL);
717+
xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
718+
netdev_put(dev, &xso->dev_tracker);
719+
}
720+
}
721+
#endif
722+
686723
void __xfrm_state_destroy(struct xfrm_state *x, bool sync)
687724
{
688725
WARN_ON(x->km.state != XFRM_STATE_DEAD);
@@ -848,6 +885,9 @@ EXPORT_SYMBOL(xfrm_state_flush);
848885

849886
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid)
850887
{
888+
struct xfrm_state *x;
889+
struct hlist_node *tmp;
890+
struct xfrm_dev_offload *xso;
851891
int i, err = 0, cnt = 0;
852892

853893
spin_lock_bh(&net->xfrm.xfrm_state_lock);
@@ -857,8 +897,6 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali
857897

858898
err = -ESRCH;
859899
for (i = 0; i <= net->xfrm.state_hmask; i++) {
860-
struct xfrm_state *x;
861-
struct xfrm_dev_offload *xso;
862900
restart:
863901
hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
864902
xso = &x->xso;
@@ -868,6 +906,8 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali
868906
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
869907

870908
err = xfrm_state_delete(x);
909+
xfrm_dev_state_free(x);
910+
871911
xfrm_audit_state_delete(x, err ? 0 : 1,
872912
task_valid);
873913
xfrm_state_put(x);
@@ -884,6 +924,24 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali
884924

885925
out:
886926
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
927+
928+
spin_lock_bh(&xfrm_state_dev_gc_lock);
929+
restart_gc:
930+
hlist_for_each_entry_safe(x, tmp, &xfrm_state_dev_gc_list, dev_gclist) {
931+
xso = &x->xso;
932+
933+
if (xso->dev == dev) {
934+
spin_unlock_bh(&xfrm_state_dev_gc_lock);
935+
xfrm_dev_state_free(x);
936+
spin_lock_bh(&xfrm_state_dev_gc_lock);
937+
goto restart_gc;
938+
}
939+
940+
}
941+
spin_unlock_bh(&xfrm_state_dev_gc_lock);
942+
943+
xfrm_flush_gc();
944+
887945
return err;
888946
}
889947
EXPORT_SYMBOL(xfrm_dev_state_flush);
@@ -1273,8 +1331,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12731331
xso->dev = xdo->dev;
12741332
xso->real_dev = xdo->real_dev;
12751333
xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
1276-
netdev_tracker_alloc(xso->dev, &xso->dev_tracker,
1277-
GFP_ATOMIC);
1334+
netdev_hold(xso->dev, &xso->dev_tracker, GFP_ATOMIC);
12781335
error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x, NULL);
12791336
if (error) {
12801337
xso->dir = 0;

net/xfrm/xfrm_user.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2455,7 +2455,6 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
24552455
NETLINK_CB(skb).portid);
24562456
}
24572457
} else {
2458-
xfrm_dev_policy_delete(xp);
24592458
xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
24602459

24612460
if (err != 0)

0 commit comments

Comments
 (0)