Fix a regression in net-2.6.17 from the aevent patches.
[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 bee4457e500cbbe3f6d8a5b200588f6b0afb6f93 tree f174724ffb83f8a9768257d2ac320710f008002b parent 5134e9a6559778d2f3f8dcaf60a1009360e477a2 author Patrick McHardy <[EMAIL PROTECTED]> Mon, 06 Mar 2006 14:14:30 +0100 committer Patrick McHardy <[EMAIL PROTECTED]> Mon, 06 Mar 2006 14:14:30 +0100 include/net/xfrm.h | 10 +++++++++- net/xfrm/xfrm_user.c | 11 ++++++++--- 2 files changed, 17 insertions(+), 4 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..7afe4b1 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); @@ -1962,6 +1965,8 @@ static int __init xfrm_user_init(void) 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); }