mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 21:53:44 +00:00
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>
This commit is contained in:
parent
e2c63e091e
commit
03a9a42a1a
@ -65,7 +65,7 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
|
|||||||
return (struct sockaddr *)&nsm->sm_addr;
|
return (struct sockaddr *)&nsm->sm_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rpc_clnt *nsm_create(struct net *net)
|
static struct rpc_clnt *nsm_create(struct net *net, const char *nodename)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin = {
|
struct sockaddr_in sin = {
|
||||||
.sin_family = AF_INET,
|
.sin_family = AF_INET,
|
||||||
@ -77,6 +77,7 @@ static struct rpc_clnt *nsm_create(struct net *net)
|
|||||||
.address = (struct sockaddr *)&sin,
|
.address = (struct sockaddr *)&sin,
|
||||||
.addrsize = sizeof(sin),
|
.addrsize = sizeof(sin),
|
||||||
.servername = "rpc.statd",
|
.servername = "rpc.statd",
|
||||||
|
.nodename = nodename,
|
||||||
.program = &nsm_program,
|
.program = &nsm_program,
|
||||||
.version = NSM_VERSION,
|
.version = NSM_VERSION,
|
||||||
.authflavor = RPC_AUTH_NULL,
|
.authflavor = RPC_AUTH_NULL,
|
||||||
@ -102,7 +103,7 @@ static struct rpc_clnt *nsm_client_set(struct lockd_net *ln,
|
|||||||
return clnt;
|
return clnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rpc_clnt *nsm_client_get(struct net *net)
|
static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename)
|
||||||
{
|
{
|
||||||
struct rpc_clnt *clnt, *new;
|
struct rpc_clnt *clnt, *new;
|
||||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||||
@ -111,7 +112,7 @@ static struct rpc_clnt *nsm_client_get(struct net *net)
|
|||||||
if (clnt != NULL)
|
if (clnt != NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
clnt = new = nsm_create(net);
|
clnt = new = nsm_create(net, nodename);
|
||||||
if (IS_ERR(clnt))
|
if (IS_ERR(clnt))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -190,19 +191,23 @@ int nsm_monitor(const struct nlm_host *host)
|
|||||||
struct nsm_res res;
|
struct nsm_res res;
|
||||||
int status;
|
int status;
|
||||||
struct rpc_clnt *clnt;
|
struct rpc_clnt *clnt;
|
||||||
|
const char *nodename = NULL;
|
||||||
|
|
||||||
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
|
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
|
||||||
|
|
||||||
if (nsm->sm_monitored)
|
if (nsm->sm_monitored)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (host->h_rpcclnt)
|
||||||
|
nodename = host->h_rpcclnt->cl_nodename;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Choose whether to record the caller_name or IP address of
|
* Choose whether to record the caller_name or IP address of
|
||||||
* this peer in the local rpc.statd's database.
|
* this peer in the local rpc.statd's database.
|
||||||
*/
|
*/
|
||||||
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
|
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
|
||||||
|
|
||||||
clnt = nsm_client_get(host->net);
|
clnt = nsm_client_get(host->net, nodename);
|
||||||
if (IS_ERR(clnt)) {
|
if (IS_ERR(clnt)) {
|
||||||
status = PTR_ERR(clnt);
|
status = PTR_ERR(clnt);
|
||||||
dprintk("lockd: failed to create NSM upcall transport, "
|
dprintk("lockd: failed to create NSM upcall transport, "
|
||||||
|
@ -57,7 +57,7 @@ struct rpc_clnt {
|
|||||||
const struct rpc_timeout *cl_timeout; /* Timeout strategy */
|
const struct rpc_timeout *cl_timeout; /* Timeout strategy */
|
||||||
|
|
||||||
int cl_nodelen; /* nodename length */
|
int cl_nodelen; /* nodename length */
|
||||||
char cl_nodename[UNX_MAXNODENAME];
|
char cl_nodename[UNX_MAXNODENAME+1];
|
||||||
struct rpc_pipe_dir_head cl_pipedir_objects;
|
struct rpc_pipe_dir_head cl_pipedir_objects;
|
||||||
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
||||||
struct rpc_rtt cl_rtt_default;
|
struct rpc_rtt cl_rtt_default;
|
||||||
@ -112,6 +112,7 @@ struct rpc_create_args {
|
|||||||
struct sockaddr *saddress;
|
struct sockaddr *saddress;
|
||||||
const struct rpc_timeout *timeout;
|
const struct rpc_timeout *timeout;
|
||||||
const char *servername;
|
const char *servername;
|
||||||
|
const char *nodename;
|
||||||
const struct rpc_program *program;
|
const struct rpc_program *program;
|
||||||
u32 prognumber; /* overrides program->number */
|
u32 prognumber; /* overrides program->number */
|
||||||
u32 version;
|
u32 version;
|
||||||
|
@ -286,10 +286,8 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
|
|||||||
|
|
||||||
static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
|
static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
|
||||||
{
|
{
|
||||||
clnt->cl_nodelen = strlen(nodename);
|
clnt->cl_nodelen = strlcpy(clnt->cl_nodename,
|
||||||
if (clnt->cl_nodelen > UNX_MAXNODENAME)
|
nodename, sizeof(clnt->cl_nodename));
|
||||||
clnt->cl_nodelen = UNX_MAXNODENAME;
|
|
||||||
memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rpc_client_register(struct rpc_clnt *clnt,
|
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,
|
|||||||
const struct rpc_version *version;
|
const struct rpc_version *version;
|
||||||
struct rpc_clnt *clnt = NULL;
|
struct rpc_clnt *clnt = NULL;
|
||||||
const struct rpc_timeout *timeout;
|
const struct rpc_timeout *timeout;
|
||||||
|
const char *nodename = args->nodename;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* sanity check the name before trying to print it */
|
/* 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,
|
|||||||
|
|
||||||
atomic_set(&clnt->cl_count, 1);
|
atomic_set(&clnt->cl_count, 1);
|
||||||
|
|
||||||
|
if (nodename == NULL)
|
||||||
|
nodename = utsname()->nodename;
|
||||||
/* save the nodename */
|
/* save the nodename */
|
||||||
rpc_clnt_set_nodename(clnt, utsname()->nodename);
|
rpc_clnt_set_nodename(clnt, nodename);
|
||||||
|
|
||||||
err = rpc_client_register(clnt, args->authflavor, args->client_name);
|
err = rpc_client_register(clnt, args->authflavor, args->client_name);
|
||||||
if (err)
|
if (err)
|
||||||
@ -576,6 +577,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
|
|||||||
if (xprt == NULL)
|
if (xprt == NULL)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
args->servername = xprt->servername;
|
args->servername = xprt->servername;
|
||||||
|
args->nodename = clnt->cl_nodename;
|
||||||
|
|
||||||
new = rpc_new_client(args, xprt, clnt);
|
new = rpc_new_client(args, xprt, clnt);
|
||||||
if (IS_ERR(new)) {
|
if (IS_ERR(new)) {
|
||||||
|
@ -355,7 +355,8 @@ int rpcb_create_local(struct net *net)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
|
static struct rpc_clnt *rpcb_create(struct net *net, const char *nodename,
|
||||||
|
const char *hostname,
|
||||||
struct sockaddr *srvaddr, size_t salen,
|
struct sockaddr *srvaddr, size_t salen,
|
||||||
int proto, u32 version)
|
int proto, u32 version)
|
||||||
{
|
{
|
||||||
@ -365,6 +366,7 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
|
|||||||
.address = srvaddr,
|
.address = srvaddr,
|
||||||
.addrsize = salen,
|
.addrsize = salen,
|
||||||
.servername = hostname,
|
.servername = hostname,
|
||||||
|
.nodename = nodename,
|
||||||
.program = &rpcb_program,
|
.program = &rpcb_program,
|
||||||
.version = version,
|
.version = version,
|
||||||
.authflavor = RPC_AUTH_UNIX,
|
.authflavor = RPC_AUTH_UNIX,
|
||||||
@ -740,7 +742,9 @@ void rpcb_getport_async(struct rpc_task *task)
|
|||||||
dprintk("RPC: %5u %s: trying rpcbind version %u\n",
|
dprintk("RPC: %5u %s: trying rpcbind version %u\n",
|
||||||
task->tk_pid, __func__, bind_version);
|
task->tk_pid, __func__, bind_version);
|
||||||
|
|
||||||
rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen,
|
rpcb_clnt = rpcb_create(xprt->xprt_net,
|
||||||
|
clnt->cl_nodename,
|
||||||
|
xprt->servername, sap, salen,
|
||||||
xprt->prot, bind_version);
|
xprt->prot, bind_version);
|
||||||
if (IS_ERR(rpcb_clnt)) {
|
if (IS_ERR(rpcb_clnt)) {
|
||||||
status = PTR_ERR(rpcb_clnt);
|
status = PTR_ERR(rpcb_clnt);
|
||||||
|
Loading…
Reference in New Issue
Block a user