Skip to contentSkip to conversation

Patch "NFSD: fix corruption in notifier registration" has been added to the 4.8-stable tree

PATCH [email protected] 1 participant 1 message Oct 26, 2016

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

NFSD: fix corruption in notifier registration

to the 4.8-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
nfsd-fix-corruption-in-notifier-registration.patch
and it can be found in the queue-4.8 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From 1eca45f8a840987d0df355e0176921653e4f7ec2 Mon Sep 17 00:00:00 2001

From: Vasily Averin <[email protected]>
Date: Wed, 21 Sep 2016 15:33:05 +0300
Subject: NFSD: fix corruption in notifier registration

From: Vasily Averin <[email protected]>

commit 1eca45f8a840987d0df355e0176921653e4f7ec2 upstream.

By design notifier can be registered once only, however nfsd registers the same inetaddr notifiers per net-namespace. When this happen it corrupts list of notifiers, as result some notifiers can be not called on proper event, traverse on list can be cycled forever, and second unregister can access already freed memory.

Fixes 36684996 ("nfsd: Register callbacks on the inetaddr_chain and inet6addr_chain")
---
 fs/nfsd/nfssvc.c |   18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
fs/nfsd/nfssvc.c +14 -4
@@ -366,14 +366,21 @@ static struct notifier_block nfsd_inet6a
 };
 #endif
 
+/* Only used under nfsd_mutex, so this atomic may be overkill: */
+static atomic_t nfsd_notifier_refcount = ATOMIC_INIT(0);
+
 static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
 {
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-	unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
+	/* check if the notifier still has clients */
+	if (atomic_dec_return(&nfsd_notifier_refcount) == 0) {
+		unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
 #if IS_ENABLED(CONFIG_IPV6)
-	unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
+		unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
 #endif
+	}
+
 	/*
 	 * write_ports can create the server without actually starting
 	 * any threads--if we get shut down before any threads are
@@ -488,10 +495,13 @@ int nfsd_create_serv(struct net *net)
 	}
 
 	set_max_drc();
-	register_inetaddr_notifier(&nfsd_inetaddr_notifier);
+	/* check if the notifier is already set */
+	if (atomic_inc_return(&nfsd_notifier_refcount) == 1) {
+		register_inetaddr_notifier(&nfsd_inetaddr_notifier);
 #if IS_ENABLED(CONFIG_IPV6)
-	register_inet6addr_notifier(&nfsd_inet6addr_notifier);
+		register_inet6addr_notifier(&nfsd_inet6addr_notifier);
 #endif
+	}
 	do_gettimeofday(&nn->nfssvc_boot);		/* record boot time */
 	return 0;
 }

Patches currently in stable-queue which might be from [email protected] are

queue-4.8/nfsd-fix-corruption-in-notifier-registration.patch