Patrick McHardy wrote:
> Fix a regression in net-2.6.17 from the aevent patches.
> 
> 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.
> 
>  static void __exit xfrm_user_exit(void)
>  {
>       xfrm_unregister_km(&netlink_mgr);
> +     rcu_assign_pointer(xfrm_nl, NULL);
> +     synchronize_rcu();
>       sock_release(xfrm_nl->sk_socket);
>  }
>  

Sorry, thats just as broken as before. Better patch attached.
[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 <[EMAIL PROTECTED]>

---
commit 4b76213dc1378f874a64acd1c088d8e9a22759a1
tree d4fc2906ffcfa5afb0ad7f68bc861f0c1fb59cc8
parent 5134e9a6559778d2f3f8dcaf60a1009360e477a2
author Patrick McHardy <[EMAIL PROTECTED]> Mon, 06 Mar 2006 14:20:29 +0100
committer Patrick McHardy <[EMAIL PROTECTED]> Mon, 06 Mar 2006 14:20:29 +0100

 include/net/xfrm.h   |   10 +++++++++-
 net/xfrm/xfrm_user.c |   15 +++++++++++----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 156f52e..7dff185 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1000,7 +1000,15 @@ static inline int xfrm_policy_id2dir(u32
 
 static inline int xfrm_aevent_is_on(void)
 {
-       return netlink_has_listeners(xfrm_nl,XFRMNLGRP_AEVENTS);
+       struct sock *nlsk;
+       int ret = 0;
+
+       rcu_read_lock();
+       nlsk = rcu_dereference(xfrm_nl);
+       if (nlsk)
+               ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS);
+       rcu_read_unlock();
+       return ret;
 }
 
 static inline void xfrm_aevent_doreplay(struct xfrm_state *x)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index ca8ac61..25c2fcf 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1947,12 +1947,15 @@ static struct xfrm_mgr netlink_mgr = {
 
 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 int __init xfrm_user_init(void)
 
 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);

Reply via email to