Patch "lockd: create NSM handles per net namespace" has been added to the 3.10-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
lockd: create NSM handles per net namespace
to the 3.10-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:
lockd-create-nsm-handles-per-net-namespace.patch
and it can be found in the queue-3.10 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
0ad95472bf169a3501991f8f33f5147f792a8116Mon Sep 17 00:00:00 2001
From: Andrey Ryabinin <[email protected]>
Date: Wed, 23 Sep 2015 15:49:29 +0300
Subject: lockd: create NSM handles per net namespace
From: Andrey Ryabinin <[email protected]>
commit 0ad95472bf169a3501991f8f33f5147f792a8116 upstream.
Commit cb7323fffa85 ("lockd: create and use per-net NSM
RPC clients on MON/UNMON requests") introduced per-net
NSM RPC clients. Unfortunately this doesn't make any sense without per-net nsm_handle.
E.g. the following scenario could happen
Two hosts (X and Y) in different namespaces (A and B) share the same nsm struct.
1. nsm_monitor(host_X) called => NSM rpc client created,
nsm->sm_monitored bit set. 2. nsm_mointor(host-Y) called => nsm->sm_monitored already set, we just exit. Thus in namespace B ln->nsm_clnt == NULL. 3. host X destroyed => nsm->sm_count decremented to 1 4. host Y destroyed => nsm_unmonitor() => nsm_mon_unmon() => NULL-ptr dereference of *ln->nsm_clnt
So this could be fixed by making per-net nsm_handles list, instead of global. Thus different net namespaces will not be able share the same nsm_handle.
--- fs/lockd/host.c | 7 ++++--- fs/lockd/mon.c | 36 ++++++++++++++++++++++-------------- fs/lockd/netns.h | 1 + fs/lockd/svc.c | 1 + fs/lockd/svc4proc.c | 2 +- fs/lockd/svcproc.c | 2 +- include/linux/lockd/lockd.h | 9 ++++++--- 7 files changed, 36 insertions(+), 22 deletions(-)
fs/lockd/host.c +4 -3
@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(satomic_inc (&nsm->sm_count); else { host =NULL ; - nsm =nsm_get_handle (ni->sap, ni->salen, + nsm =nsm_get_handle (ni->net, ni->sap, ni->salen, ni->hostname, ni->hostname_len);if (unlikely (nsm ==NULL )) { dprintk("lockd: %s failed; no nsm handle\n",
@@ -534,17 +534,18 @@ static struct nlm_host *next_host_state(/** * nlm_host_rebooted - Release all resources held by rebooted host +* @net: network namespace * @info: pointer to decoded results of NLM_SM_NOTIFY call * * We were notified that the specified host has rebooted. Release * all resources held by that peer. */ -void nlm_host_rebooted (const struct nlm_reboot *info) +void nlm_host_rebooted (const struct net *net,const struct nlm_reboot *info) {struct nsm_handle *nsm;struct nlm_host *host; - nsm =nsm_reboot_lookup (info); + nsm =nsm_reboot_lookup (net, info);if (unlikely (nsm ==NULL ))return ;
fs/lockd/mon.c +22 -14
@@ -51,7 +51,6 @@ struct nsm_res { };static const struct rpc_program nsm_program; -static LIST_HEAD (nsm_handles);static DEFINE_SPINLOCK (nsm_lock);/*
@@ -259,33 +258,35 @@ void nsm_unmonitor(const struct nlm_host } } -static struct nsm_handle *nsm_lookup_hostname (const char *hostname, -const size_t len) +static struct nsm_handle *nsm_lookup_hostname (const struct list_head *nsm_handles, +const char *hostname,const size_t len) {struct nsm_handle *nsm; -list_for_each_entry (nsm, &nsm_handles, sm_link) +list_for_each_entry (nsm, nsm_handles, sm_link)if (strlen (nsm->sm_name) == len &&memcmp (nsm->sm_name, hostname, len) ==0 )return nsm;return NULL ; } -static struct nsm_handle *nsm_lookup_addr (const struct sockaddr *sap) +static struct nsm_handle *nsm_lookup_addr (const struct list_head *nsm_handles, +const struct sockaddr *sap) {struct nsm_handle *nsm; -list_for_each_entry (nsm, &nsm_handles, sm_link) +list_for_each_entry (nsm, nsm_handles, sm_link)if (rpc_cmp_addr (nsm_addr (nsm), sap))return nsm;return NULL ; } -static struct nsm_handle *nsm_lookup_priv (const struct nsm_private *priv) +static struct nsm_handle *nsm_lookup_priv (const struct list_head *nsm_handles, +const struct nsm_private *priv) {struct nsm_handle *nsm; -list_for_each_entry (nsm, &nsm_handles, sm_link) +list_for_each_entry (nsm, nsm_handles, sm_link)if (memcmp (nsm->sm_priv.data, priv->data,sizeof (priv->data)) ==0 )return nsm;
@@ -350,6 +351,7 @@ static struct nsm_handle *nsm_create_han/** * nsm_get_handle - Find or create a cached nsm_handle +* @net: network namespace * @sap: pointer to socket address of handle to find * @salen: length of socket address * @hostname: pointer to C string containing hostname to find
@@ -362,11 +364,13 @@ static struct nsm_handle *nsm_create_han* @hostname cannot be found in the handle cache. Returns NULL if * an error occurs. */ -struct nsm_handle *nsm_get_handle (const struct sockaddr *sap, +struct nsm_handle *nsm_get_handle (const struct net *net, +const struct sockaddr *sap,const size_t salen,const char *hostname,const size_t hostname_len) {struct nsm_handle *cached, *new =NULL ; +struct lockd_net *ln =net_generic (net, lockd_net_id);if (hostname &&memchr (hostname,'/' , hostname_len) !=NULL ) {if (printk_ratelimit ()) {
@@ -381,9 +385,10 @@ retry:spin_lock (&nsm_lock);if (nsm_use_hostnames && hostname !=NULL ) - cached =nsm_lookup_hostname (hostname, hostname_len); + cached =nsm_lookup_hostname (&ln->nsm_handles, + hostname, hostname_len);else - cached =nsm_lookup_addr (sap); + cached =nsm_lookup_addr (&ln->nsm_handles, sap);if (cached !=NULL ) {atomic_inc (&cached->sm_count);
@@ -397,7 +402,7 @@ retry: }if (new !=NULL ) { -list_add (&new->sm_link, &nsm_handles); +list_add (&new->sm_link, &ln->nsm_handles);spin_unlock (&nsm_lock);dprintk ("lockd: created nsm_handle for %s (%s)\n" , new->sm_name, new->sm_addrbuf);
@@ -414,19 +419,22 @@ retry:/** * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle +* @net: network namespace * @info: pointer to NLMPROC_SM_NOTIFY arguments * * Returns a matching nsm_handle if found in the nsm cache. The returned * nsm_handle's reference count is bumped. Otherwise returns NULL if some * error occurred. */ -struct nsm_handle *nsm_reboot_lookup (const struct nlm_reboot *info) +struct nsm_handle *nsm_reboot_lookup (const struct net *net, +const struct nlm_reboot *info) {struct nsm_handle *cached; +struct lockd_net *ln =net_generic (net, lockd_net_id);spin_lock (&nsm_lock); - cached =nsm_lookup_priv (&info->priv); + cached =nsm_lookup_priv (&ln->nsm_handles, &info->priv);if (unlikely (cached ==NULL )) {spin_unlock (&nsm_lock); dprintk("lockd: never saw rebooted peer '%.*s' before\n",
fs/lockd/netns.h +1 -0
@@ -16,6 +16,7 @@ struct lockd_net {spinlock_t nsm_clnt_lock;unsigned int nsm_users;struct rpc_clnt *nsm_clnt; +struct list_head nsm_handles; };extern int lockd_net_id;
fs/lockd/svc.c +1 -0
@@ -583,6 +583,7 @@ static int lockd_init_net(struct net *neINIT_DELAYED_WORK (&ln->grace_period_end, grace_ender);INIT_LIST_HEAD (&ln->grace_list);spin_lock_init (&ln->nsm_clnt_lock); +INIT_LIST_HEAD (&ln->nsm_handles);return 0 ; }
fs/lockd/svc4proc.c +1 -1
@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *return rpc_system_err; } -nlm_host_rebooted (argp); +nlm_host_rebooted (SVC_NET (rqstp), argp);return rpc_success; }
fs/lockd/svcproc.c +1 -1
@@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rreturn rpc_system_err; } -nlm_host_rebooted (argp); +nlm_host_rebooted (SVC_NET (rqstp), argp);return rpc_success; }
include/linux/lockd/lockd.h +6 -3
@@ -236,7 +236,8 @@ void nlm_rebind_host(struct nlm_hoststruct nlm_host *nlm_get_host (struct nlm_host *);void nlm_shutdown_hosts (void );void nlm_shutdown_hosts_net (struct net *net); -void nlm_host_rebooted (const struct nlm_reboot *); +void nlm_host_rebooted (const struct net *net, +const struct nlm_reboot *);/* * Host monitoring
@@ -244,11 +245,13 @@ void nlm_host_rebooted(const struct nint nsm_monitor (const struct nlm_host *host);void nsm_unmonitor (const struct nlm_host *host); -struct nsm_handle *nsm_get_handle (const struct sockaddr *sap, +struct nsm_handle *nsm_get_handle (const struct net *net, +const struct sockaddr *sap,const size_t salen,const char *hostname,const size_t hostname_len); -struct nsm_handle *nsm_reboot_lookup (const struct nlm_reboot *info); +struct nsm_handle *nsm_reboot_lookup (const struct net *net, +const struct nlm_reboot *info);void nsm_release (struct nsm_handle *nsm);/*
Patches currently in stable-queue which might be from [email protected] are
queue-3.10/lockd-create-nsm-handles-per-net-namespace.patch