aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-03-21 01:40:54 -0500
committerDavid S. Miller <davem@davemloft.net>2006-03-21 01:40:54 -0500
commitbe33690d8fcf40377f16193c463681170eb6b295 (patch)
tree08c7be2ba1d046fca40bbb1d3ddac789b393ecc9
parent15d99e02babae8bc20b836917ace07d93e318149 (diff)
[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>
-rw-r--r--include/net/xfrm.h10
-rw-r--r--net/xfrm/xfrm_user.c15
2 files changed, 20 insertions, 5 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 786371365f2b..61b7504fc2ba 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1001,7 +1001,15 @@ static inline int xfrm_policy_id2dir(u32 index)
1001 1001
1002static inline int xfrm_aevent_is_on(void) 1002static inline int xfrm_aevent_is_on(void)
1003{ 1003{
1004 return netlink_has_listeners(xfrm_nl,XFRMNLGRP_AEVENTS); 1004 struct sock *nlsk;
1005 int ret = 0;
1006
1007 rcu_read_lock();
1008 nlsk = rcu_dereference(xfrm_nl);
1009 if (nlsk)
1010 ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS);
1011 rcu_read_unlock();
1012 return ret;
1005} 1013}
1006 1014
1007static inline void xfrm_aevent_doreplay(struct xfrm_state *x) 1015static inline void xfrm_aevent_doreplay(struct xfrm_state *x)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 4a7120a7e10f..81d1005830f4 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1947,12 +1947,15 @@ static struct xfrm_mgr netlink_mgr = {
1947 1947
1948static int __init xfrm_user_init(void) 1948static int __init xfrm_user_init(void)
1949{ 1949{
1950 struct sock *nlsk;
1951
1950 printk(KERN_INFO "Initializing IPsec netlink socket\n"); 1952 printk(KERN_INFO "Initializing IPsec netlink socket\n");
1951 1953
1952 xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, 1954 nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
1953 xfrm_netlink_rcv, THIS_MODULE); 1955 xfrm_netlink_rcv, THIS_MODULE);
1954 if (xfrm_nl == NULL) 1956 if (nlsk == NULL)
1955 return -ENOMEM; 1957 return -ENOMEM;
1958 rcu_assign_pointer(xfrm_nl, nlsk);
1956 1959
1957 xfrm_register_km(&netlink_mgr); 1960 xfrm_register_km(&netlink_mgr);
1958 1961
@@ -1961,8 +1964,12 @@ static int __init xfrm_user_init(void)
1961 1964
1962static void __exit xfrm_user_exit(void) 1965static void __exit xfrm_user_exit(void)
1963{ 1966{
1967 struct sock *nlsk = xfrm_nl;
1968
1964 xfrm_unregister_km(&netlink_mgr); 1969 xfrm_unregister_km(&netlink_mgr);
1965 sock_release(xfrm_nl->sk_socket); 1970 rcu_assign_pointer(xfrm_nl, NULL);
1971 synchronize_rcu();
1972 sock_release(nlsk->sk_socket);
1966} 1973}
1967 1974
1968module_init(xfrm_user_init); 1975module_init(xfrm_user_init);