Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be33690d authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 15d99e02
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -1001,7 +1001,15 @@ static inline int xfrm_policy_id2dir(u32 index)

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)
+11 −4
Original line number Diff line number Diff line
@@ -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,
	nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
	                             xfrm_netlink_rcv, THIS_MODULE);
	if (xfrm_nl == NULL)
	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);