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

Reply via email to