diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2015-01-30 18:12:28 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2015-02-03 16:40:17 -0500 |
commit | 03a9a42a1a7e5b3e7919ddfacc1d1cc81882a955 (patch) | |
tree | eb1e9497ef3e6dd0090cfb054cfe08b6bbea5d6a /net/sunrpc | |
parent | e2c63e091e29786a34ecf42c169e627a3d1d96d7 (diff) |
SUNRPC: NULL utsname dereference on NFS umount during namespace cleanup
Fix an Oopsable condition when nsm_mon_unmon is called as part of the
namespace cleanup, which now apparently happens after the utsname
has been freed.
Link: http://lkml.kernel.org/r/20150125220604.090121ae@neptune.home
Reported-by: Bruno Prémont <bonbons@linux-vserver.org>
Cc: stable@vger.kernel.org # 3.18
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/clnt.c | 12 | ||||
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 8 |
2 files changed, 13 insertions, 7 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 05da12a33945..3f5d4d48f0cb 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -286,10 +286,8 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt, | |||
286 | 286 | ||
287 | static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) | 287 | static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) |
288 | { | 288 | { |
289 | clnt->cl_nodelen = strlen(nodename); | 289 | clnt->cl_nodelen = strlcpy(clnt->cl_nodename, |
290 | if (clnt->cl_nodelen > UNX_MAXNODENAME) | 290 | nodename, sizeof(clnt->cl_nodename)); |
291 | clnt->cl_nodelen = UNX_MAXNODENAME; | ||
292 | memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen); | ||
293 | } | 291 | } |
294 | 292 | ||
295 | static int rpc_client_register(struct rpc_clnt *clnt, | 293 | static int rpc_client_register(struct rpc_clnt *clnt, |
@@ -365,6 +363,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | |||
365 | const struct rpc_version *version; | 363 | const struct rpc_version *version; |
366 | struct rpc_clnt *clnt = NULL; | 364 | struct rpc_clnt *clnt = NULL; |
367 | const struct rpc_timeout *timeout; | 365 | const struct rpc_timeout *timeout; |
366 | const char *nodename = args->nodename; | ||
368 | int err; | 367 | int err; |
369 | 368 | ||
370 | /* sanity check the name before trying to print it */ | 369 | /* sanity check the name before trying to print it */ |
@@ -420,8 +419,10 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | |||
420 | 419 | ||
421 | atomic_set(&clnt->cl_count, 1); | 420 | atomic_set(&clnt->cl_count, 1); |
422 | 421 | ||
422 | if (nodename == NULL) | ||
423 | nodename = utsname()->nodename; | ||
423 | /* save the nodename */ | 424 | /* save the nodename */ |
424 | rpc_clnt_set_nodename(clnt, utsname()->nodename); | 425 | rpc_clnt_set_nodename(clnt, nodename); |
425 | 426 | ||
426 | err = rpc_client_register(clnt, args->authflavor, args->client_name); | 427 | err = rpc_client_register(clnt, args->authflavor, args->client_name); |
427 | if (err) | 428 | if (err) |
@@ -576,6 +577,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args, | |||
576 | if (xprt == NULL) | 577 | if (xprt == NULL) |
577 | goto out_err; | 578 | goto out_err; |
578 | args->servername = xprt->servername; | 579 | args->servername = xprt->servername; |
580 | args->nodename = clnt->cl_nodename; | ||
579 | 581 | ||
580 | new = rpc_new_client(args, xprt, clnt); | 582 | new = rpc_new_client(args, xprt, clnt); |
581 | if (IS_ERR(new)) { | 583 | if (IS_ERR(new)) { |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 05202012bcfc..cf5770d8f49a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -355,7 +355,8 @@ out: | |||
355 | return result; | 355 | return result; |
356 | } | 356 | } |
357 | 357 | ||
358 | static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, | 358 | static struct rpc_clnt *rpcb_create(struct net *net, const char *nodename, |
359 | const char *hostname, | ||
359 | struct sockaddr *srvaddr, size_t salen, | 360 | struct sockaddr *srvaddr, size_t salen, |
360 | int proto, u32 version) | 361 | int proto, u32 version) |
361 | { | 362 | { |
@@ -365,6 +366,7 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, | |||
365 | .address = srvaddr, | 366 | .address = srvaddr, |
366 | .addrsize = salen, | 367 | .addrsize = salen, |
367 | .servername = hostname, | 368 | .servername = hostname, |
369 | .nodename = nodename, | ||
368 | .program = &rpcb_program, | 370 | .program = &rpcb_program, |
369 | .version = version, | 371 | .version = version, |
370 | .authflavor = RPC_AUTH_UNIX, | 372 | .authflavor = RPC_AUTH_UNIX, |
@@ -740,7 +742,9 @@ void rpcb_getport_async(struct rpc_task *task) | |||
740 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", | 742 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", |
741 | task->tk_pid, __func__, bind_version); | 743 | task->tk_pid, __func__, bind_version); |
742 | 744 | ||
743 | rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen, | 745 | rpcb_clnt = rpcb_create(xprt->xprt_net, |
746 | clnt->cl_nodename, | ||
747 | xprt->servername, sap, salen, | ||
744 | xprt->prot, bind_version); | 748 | xprt->prot, bind_version); |
745 | if (IS_ERR(rpcb_clnt)) { | 749 | if (IS_ERR(rpcb_clnt)) { |
746 | status = PTR_ERR(rpcb_clnt); | 750 | status = PTR_ERR(rpcb_clnt); |