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

Commit 6b18dd1c authored by Vasily Averin's avatar Vasily Averin Committed by J. Bruce Fields
Browse files

race of lockd inetaddr notifiers vs nlmsvc_rqst change



lockd_inet[6]addr_event use nlmsvc_rqst without taken nlmsvc_mutex,
nlmsvc_rqst can be changed during execution of notifiers and crash the host.

Patch enables access to nlmsvc_rqst only when it was correctly initialized
and delays its cleanup until notifiers are no longer in use.

Note that nlmsvc_rqst can be temporally set to ERR_PTR, so the "if
(nlmsvc_rqst)" check in notifiers is insufficient on its own.

Signed-off-by: default avatarVasily Averin <vvs@virtuozzo.com>
Tested-by: default avatarScott Mayhew <smayhew@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent ee24eac3
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -57,6 +57,9 @@ static struct task_struct *nlmsvc_task;
static struct svc_rqst		*nlmsvc_rqst;
unsigned long			nlmsvc_timeout;

atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0);
DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq);

unsigned int lockd_net_id;

/*
@@ -293,7 +296,8 @@ static int lockd_inetaddr_event(struct notifier_block *this,
	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
	struct sockaddr_in sin;

	if (event != NETDEV_DOWN)
	if ((event != NETDEV_DOWN) ||
	    !atomic_inc_not_zero(&nlm_ntf_refcnt))
		goto out;

	if (nlmsvc_rqst) {
@@ -304,6 +308,8 @@ static int lockd_inetaddr_event(struct notifier_block *this,
		svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
			(struct sockaddr *)&sin);
	}
	atomic_dec(&nlm_ntf_refcnt);
	wake_up(&nlm_ntf_wq);

out:
	return NOTIFY_DONE;
@@ -320,7 +326,8 @@ static int lockd_inet6addr_event(struct notifier_block *this,
	struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
	struct sockaddr_in6 sin6;

	if (event != NETDEV_DOWN)
	if ((event != NETDEV_DOWN) ||
	    !atomic_inc_not_zero(&nlm_ntf_refcnt))
		goto out;

	if (nlmsvc_rqst) {
@@ -332,6 +339,8 @@ static int lockd_inet6addr_event(struct notifier_block *this,
		svc_age_temp_xprts_now(nlmsvc_rqst->rq_server,
			(struct sockaddr *)&sin6);
	}
	atomic_dec(&nlm_ntf_refcnt);
	wake_up(&nlm_ntf_wq);

out:
	return NOTIFY_DONE;
@@ -348,10 +357,12 @@ static void lockd_unregister_notifiers(void)
#if IS_ENABLED(CONFIG_IPV6)
	unregister_inet6addr_notifier(&lockd_inet6addr_notifier);
#endif
	wait_event(nlm_ntf_wq, atomic_read(&nlm_ntf_refcnt) == 0);
}

static void lockd_svc_exit_thread(void)
{
	atomic_dec(&nlm_ntf_refcnt);
	lockd_unregister_notifiers();
	svc_exit_thread(nlmsvc_rqst);
}
@@ -376,6 +387,7 @@ static int lockd_start_svc(struct svc_serv *serv)
		goto out_rqst;
	}

	atomic_inc(&nlm_ntf_refcnt);
	svc_sock_update_bufs(serv);
	serv->sv_maxconn = nlm_max_connections;