[XFRM]: Fix aevent related crash

When xfrm_user isn't loaded xfrm_nl is NULL, which makes IPsec crash because
xfrm_aevent_is_on passes the NULL pointer to netlink_has_listeners as socket.
A second problem is that the xfrm_nl pointer is not cleared when the socket
is releases at module unload time.

Protect references of xfrm_nl from outside of xfrm_user by RCU, check
that the socket is present in xfrm_aevent_is_on and set it to NULL
when unloading xfrm_user.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 4a7120a..81d1005 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1947,12 +1947,15 @@
 
 static int __init xfrm_user_init(void)
 {
+	struct sock *nlsk;
+
 	printk(KERN_INFO "Initializing IPsec netlink socket\n");
 
-	xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
-	                                xfrm_netlink_rcv, THIS_MODULE);
-	if (xfrm_nl == NULL)
+	nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
+	                             xfrm_netlink_rcv, THIS_MODULE);
+	if (nlsk == NULL)
 		return -ENOMEM;
+	rcu_assign_pointer(xfrm_nl, nlsk);
 
 	xfrm_register_km(&netlink_mgr);
 
@@ -1961,8 +1964,12 @@
 
 static void __exit xfrm_user_exit(void)
 {
+	struct sock *nlsk = xfrm_nl;
+
 	xfrm_unregister_km(&netlink_mgr);
-	sock_release(xfrm_nl->sk_socket);
+	rcu_assign_pointer(xfrm_nl, NULL);
+	synchronize_rcu();
+	sock_release(nlsk->sk_socket);
 }
 
 module_init(xfrm_user_init);