From: Aviv Heller <av...@mellanox.com> Adding the state to the offload device prior to replay init in xfrm_state_construct() will result in NULL dereference if a matching ESP packet is received in between.
In order to inhibit driver offload logic from processing the state's packets prior to the xfrm_state object being completely initialized and added to the SADBs, a new activate() operation was added to inform the driver the aforementioned conditions have been met. Signed-off-by: Aviv Heller <av...@mellanox.com> Signed-off-by: Yossi Kuperman <yoss...@mellanox.com> --- v1 -> v2: - Separate to state addition and then activation, instead of relocating dev state addition call. --- include/linux/netdevice.h | 1 + include/net/xfrm.h | 12 ++++++++++++ net/xfrm/xfrm_user.c | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2eaac7d..c6ca356 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -819,6 +819,7 @@ struct netdev_xdp { #ifdef CONFIG_XFRM_OFFLOAD struct xfrmdev_ops { int (*xdo_dev_state_add) (struct xfrm_state *x); + void (*xdo_dev_state_activate) (struct xfrm_state *x); void (*xdo_dev_state_delete) (struct xfrm_state *x); void (*xdo_dev_state_free) (struct xfrm_state *x); bool (*xdo_dev_offload_ok) (struct sk_buff *skb, diff --git a/include/net/xfrm.h b/include/net/xfrm.h index e015e16..324374e 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1877,6 +1877,14 @@ static inline bool xfrm_dst_offload_ok(struct dst_entry *dst) return false; } +static inline void xfrm_dev_state_activate(struct xfrm_state *x) +{ + struct xfrm_state_offload *xso = &x->xso; + + if (xso->dev && xso->dev->xfrmdev_ops->xdo_dev_state_activate) + xso->dev->xfrmdev_ops->xdo_dev_state_activate(x); +} + static inline void xfrm_dev_state_delete(struct xfrm_state *x) { struct xfrm_state_offload *xso = &x->xso; @@ -1907,6 +1915,10 @@ static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, stru return 0; } +static inline void xfrm_dev_state_activate(struct xfrm_state *x) +{ +} + static inline void xfrm_dev_state_delete(struct xfrm_state *x) { } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e44a0fe..d06f579 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -662,6 +662,11 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; } + spin_lock_bh(&x->lock); + if (x->km.state == XFRM_STATE_VALID) + xfrm_dev_state_activate(x); + spin_unlock_bh(&x->lock); + c.seq = nlh->nlmsg_seq; c.portid = nlh->nlmsg_pid; c.event = nlh->nlmsg_type; -- 1.8.3.1