Commit 70c676cb authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
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/20240711100025.1949454-1-steffen.klassert@secunet.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 528dd46d 89a2aefe
Loading
Loading
Loading
Loading
+10 −26
Original line number Diff line number Diff line
@@ -178,7 +178,10 @@ struct xfrm_state {
		struct hlist_node	gclist;
		struct hlist_node	bydst;
	};
	union {
		struct hlist_node	dev_gclist;
		struct hlist_node	bysrc;
	};
	struct hlist_node	byspi;
	struct hlist_node	byseq;

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

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

static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
{
	struct xfrm_dev_offload *xso = &x->xso;
	struct net_device *dev = READ_ONCE(xso->dev);

	if (xso->dev && xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn)
		xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
	if (dev && dev->xfrmdev_ops->xdo_dev_state_advance_esn)
		dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
}

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)
	return false;
}

static inline void xfrm_dev_state_delete(struct xfrm_state *x)
{
	struct xfrm_dev_offload *xso = &x->xso;

	if (xso->dev)
		xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
}

static inline void xfrm_dev_state_free(struct xfrm_state *x)
{
	struct xfrm_dev_offload *xso = &x->xso;
	struct net_device *dev = xso->dev;

	if (dev && dev->xfrmdev_ops) {
		if (dev->xfrmdev_ops->xdo_dev_state_free)
			dev->xfrmdev_ops->xdo_dev_state_free(x);
		xso->dev = NULL;
		xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
		netdev_put(dev, &xso->dev_tracker);
	}
}

static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
{
	struct xfrm_dev_offload *xdo = &x->xdo;
+1 −2
Original line number Diff line number Diff line
@@ -239,8 +239,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
#else
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
{
	kfree_skb(skb);

	WARN_ON(1);
	return -EOPNOTSUPP;
}
#endif
+7 −0
Original line number Diff line number Diff line
@@ -56,6 +56,13 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
		x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
				      (xfrm_address_t *)&ip_hdr(skb)->daddr,
				      spi, IPPROTO_ESP, AF_INET);

		if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) {
			/* non-offload path will record the error and audit log */
			xfrm_state_put(x);
			x = NULL;
		}

		if (!x)
			goto out_reset;

+1 −2
Original line number Diff line number Diff line
@@ -256,8 +256,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
#else
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
{
	kfree_skb(skb);

	WARN_ON(1);
	return -EOPNOTSUPP;
}
#endif
+7 −0
Original line number Diff line number Diff line
@@ -83,6 +83,13 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
		x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
				      (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
				      spi, IPPROTO_ESP, AF_INET6);

		if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) {
			/* non-offload path will record the error and audit log */
			xfrm_state_put(x);
			x = NULL;
		}

		if (!x)
			goto out_reset;

Loading