Skip to content

Commit 0ad9547

Browse files
aryabininJ. Bruce Fields
authored and
J. Bruce Fields
committed
lockd: create NSM handles per net namespace
Commit cb7323f ("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. Signed-off-by: Andrey Ryabinin <[email protected]> Cc: <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent aaf91ec commit 0ad9547

File tree

7 files changed

+36
-22
lines changed

7 files changed

+36
-22
lines changed

fs/lockd/host.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
116116
atomic_inc(&nsm->sm_count);
117117
else {
118118
host = NULL;
119-
nsm = nsm_get_handle(ni->sap, ni->salen,
119+
nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
120120
ni->hostname, ni->hostname_len);
121121
if (unlikely(nsm == NULL)) {
122122
dprintk("lockd: %s failed; no nsm handle\n",
@@ -534,17 +534,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
534534

535535
/**
536536
* nlm_host_rebooted - Release all resources held by rebooted host
537+
* @net: network namespace
537538
* @info: pointer to decoded results of NLM_SM_NOTIFY call
538539
*
539540
* We were notified that the specified host has rebooted. Release
540541
* all resources held by that peer.
541542
*/
542-
void nlm_host_rebooted(const struct nlm_reboot *info)
543+
void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
543544
{
544545
struct nsm_handle *nsm;
545546
struct nlm_host *host;
546547

547-
nsm = nsm_reboot_lookup(info);
548+
nsm = nsm_reboot_lookup(net, info);
548549
if (unlikely(nsm == NULL))
549550
return;
550551

fs/lockd/mon.c

+22-14
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ struct nsm_res {
5151
};
5252

5353
static const struct rpc_program nsm_program;
54-
static LIST_HEAD(nsm_handles);
5554
static DEFINE_SPINLOCK(nsm_lock);
5655

5756
/*
@@ -264,33 +263,35 @@ void nsm_unmonitor(const struct nlm_host *host)
264263
}
265264
}
266265

267-
static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
268-
const size_t len)
266+
static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles,
267+
const char *hostname, const size_t len)
269268
{
270269
struct nsm_handle *nsm;
271270

272-
list_for_each_entry(nsm, &nsm_handles, sm_link)
271+
list_for_each_entry(nsm, nsm_handles, sm_link)
273272
if (strlen(nsm->sm_name) == len &&
274273
memcmp(nsm->sm_name, hostname, len) == 0)
275274
return nsm;
276275
return NULL;
277276
}
278277

279-
static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
278+
static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles,
279+
const struct sockaddr *sap)
280280
{
281281
struct nsm_handle *nsm;
282282

283-
list_for_each_entry(nsm, &nsm_handles, sm_link)
283+
list_for_each_entry(nsm, nsm_handles, sm_link)
284284
if (rpc_cmp_addr(nsm_addr(nsm), sap))
285285
return nsm;
286286
return NULL;
287287
}
288288

289-
static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
289+
static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles,
290+
const struct nsm_private *priv)
290291
{
291292
struct nsm_handle *nsm;
292293

293-
list_for_each_entry(nsm, &nsm_handles, sm_link)
294+
list_for_each_entry(nsm, nsm_handles, sm_link)
294295
if (memcmp(nsm->sm_priv.data, priv->data,
295296
sizeof(priv->data)) == 0)
296297
return nsm;
@@ -353,6 +354,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
353354

354355
/**
355356
* nsm_get_handle - Find or create a cached nsm_handle
357+
* @net: network namespace
356358
* @sap: pointer to socket address of handle to find
357359
* @salen: length of socket address
358360
* @hostname: pointer to C string containing hostname to find
@@ -365,11 +367,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
365367
* @hostname cannot be found in the handle cache. Returns NULL if
366368
* an error occurs.
367369
*/
368-
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
370+
struct nsm_handle *nsm_get_handle(const struct net *net,
371+
const struct sockaddr *sap,
369372
const size_t salen, const char *hostname,
370373
const size_t hostname_len)
371374
{
372375
struct nsm_handle *cached, *new = NULL;
376+
struct lockd_net *ln = net_generic(net, lockd_net_id);
373377

374378
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
375379
if (printk_ratelimit()) {
@@ -384,9 +388,10 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
384388
spin_lock(&nsm_lock);
385389

386390
if (nsm_use_hostnames && hostname != NULL)
387-
cached = nsm_lookup_hostname(hostname, hostname_len);
391+
cached = nsm_lookup_hostname(&ln->nsm_handles,
392+
hostname, hostname_len);
388393
else
389-
cached = nsm_lookup_addr(sap);
394+
cached = nsm_lookup_addr(&ln->nsm_handles, sap);
390395

391396
if (cached != NULL) {
392397
atomic_inc(&cached->sm_count);
@@ -400,7 +405,7 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
400405
}
401406

402407
if (new != NULL) {
403-
list_add(&new->sm_link, &nsm_handles);
408+
list_add(&new->sm_link, &ln->nsm_handles);
404409
spin_unlock(&nsm_lock);
405410
dprintk("lockd: created nsm_handle for %s (%s)\n",
406411
new->sm_name, new->sm_addrbuf);
@@ -417,19 +422,22 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
417422

418423
/**
419424
* nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
425+
* @net: network namespace
420426
* @info: pointer to NLMPROC_SM_NOTIFY arguments
421427
*
422428
* Returns a matching nsm_handle if found in the nsm cache. The returned
423429
* nsm_handle's reference count is bumped. Otherwise returns NULL if some
424430
* error occurred.
425431
*/
426-
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
432+
struct nsm_handle *nsm_reboot_lookup(const struct net *net,
433+
const struct nlm_reboot *info)
427434
{
428435
struct nsm_handle *cached;
436+
struct lockd_net *ln = net_generic(net, lockd_net_id);
429437

430438
spin_lock(&nsm_lock);
431439

432-
cached = nsm_lookup_priv(&info->priv);
440+
cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv);
433441
if (unlikely(cached == NULL)) {
434442
spin_unlock(&nsm_lock);
435443
dprintk("lockd: never saw rebooted peer '%.*s' before\n",

fs/lockd/netns.h

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct lockd_net {
1515
spinlock_t nsm_clnt_lock;
1616
unsigned int nsm_users;
1717
struct rpc_clnt *nsm_clnt;
18+
struct list_head nsm_handles;
1819
};
1920

2021
extern int lockd_net_id;

fs/lockd/svc.c

+1
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ static int lockd_init_net(struct net *net)
593593
INIT_LIST_HEAD(&ln->lockd_manager.list);
594594
ln->lockd_manager.block_opens = false;
595595
spin_lock_init(&ln->nsm_clnt_lock);
596+
INIT_LIST_HEAD(&ln->nsm_handles);
596597
return 0;
597598
}
598599

fs/lockd/svc4proc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
421421
return rpc_system_err;
422422
}
423423

424-
nlm_host_rebooted(argp);
424+
nlm_host_rebooted(SVC_NET(rqstp), argp);
425425
return rpc_success;
426426
}
427427

fs/lockd/svcproc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
464464
return rpc_system_err;
465465
}
466466

467-
nlm_host_rebooted(argp);
467+
nlm_host_rebooted(SVC_NET(rqstp), argp);
468468
return rpc_success;
469469
}
470470

include/linux/lockd/lockd.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -235,19 +235,22 @@ void nlm_rebind_host(struct nlm_host *);
235235
struct nlm_host * nlm_get_host(struct nlm_host *);
236236
void nlm_shutdown_hosts(void);
237237
void nlm_shutdown_hosts_net(struct net *net);
238-
void nlm_host_rebooted(const struct nlm_reboot *);
238+
void nlm_host_rebooted(const struct net *net,
239+
const struct nlm_reboot *);
239240

240241
/*
241242
* Host monitoring
242243
*/
243244
int nsm_monitor(const struct nlm_host *host);
244245
void nsm_unmonitor(const struct nlm_host *host);
245246

246-
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
247+
struct nsm_handle *nsm_get_handle(const struct net *net,
248+
const struct sockaddr *sap,
247249
const size_t salen,
248250
const char *hostname,
249251
const size_t hostname_len);
250-
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info);
252+
struct nsm_handle *nsm_reboot_lookup(const struct net *net,
253+
const struct nlm_reboot *info);
251254
void nsm_release(struct nsm_handle *nsm);
252255

253256
/*

0 commit comments

Comments
 (0)