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 /fs/lockd/mon.c | |
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 'fs/lockd/mon.c')
-rw-r--r-- | fs/lockd/mon.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 1cc6ec51e6b1..47a32b6d9b90 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -65,7 +65,7 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) | |||
65 | return (struct sockaddr *)&nsm->sm_addr; | 65 | return (struct sockaddr *)&nsm->sm_addr; |
66 | } | 66 | } |
67 | 67 | ||
68 | static struct rpc_clnt *nsm_create(struct net *net) | 68 | static struct rpc_clnt *nsm_create(struct net *net, const char *nodename) |
69 | { | 69 | { |
70 | struct sockaddr_in sin = { | 70 | struct sockaddr_in sin = { |
71 | .sin_family = AF_INET, | 71 | .sin_family = AF_INET, |
@@ -77,6 +77,7 @@ static struct rpc_clnt *nsm_create(struct net *net) | |||
77 | .address = (struct sockaddr *)&sin, | 77 | .address = (struct sockaddr *)&sin, |
78 | .addrsize = sizeof(sin), | 78 | .addrsize = sizeof(sin), |
79 | .servername = "rpc.statd", | 79 | .servername = "rpc.statd", |
80 | .nodename = nodename, | ||
80 | .program = &nsm_program, | 81 | .program = &nsm_program, |
81 | .version = NSM_VERSION, | 82 | .version = NSM_VERSION, |
82 | .authflavor = RPC_AUTH_NULL, | 83 | .authflavor = RPC_AUTH_NULL, |
@@ -102,7 +103,7 @@ out: | |||
102 | return clnt; | 103 | return clnt; |
103 | } | 104 | } |
104 | 105 | ||
105 | static struct rpc_clnt *nsm_client_get(struct net *net) | 106 | static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename) |
106 | { | 107 | { |
107 | struct rpc_clnt *clnt, *new; | 108 | struct rpc_clnt *clnt, *new; |
108 | struct lockd_net *ln = net_generic(net, lockd_net_id); | 109 | struct lockd_net *ln = net_generic(net, lockd_net_id); |
@@ -111,7 +112,7 @@ static struct rpc_clnt *nsm_client_get(struct net *net) | |||
111 | if (clnt != NULL) | 112 | if (clnt != NULL) |
112 | goto out; | 113 | goto out; |
113 | 114 | ||
114 | clnt = new = nsm_create(net); | 115 | clnt = new = nsm_create(net, nodename); |
115 | if (IS_ERR(clnt)) | 116 | if (IS_ERR(clnt)) |
116 | goto out; | 117 | goto out; |
117 | 118 | ||
@@ -190,19 +191,23 @@ int nsm_monitor(const struct nlm_host *host) | |||
190 | struct nsm_res res; | 191 | struct nsm_res res; |
191 | int status; | 192 | int status; |
192 | struct rpc_clnt *clnt; | 193 | struct rpc_clnt *clnt; |
194 | const char *nodename = NULL; | ||
193 | 195 | ||
194 | dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); | 196 | dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); |
195 | 197 | ||
196 | if (nsm->sm_monitored) | 198 | if (nsm->sm_monitored) |
197 | return 0; | 199 | return 0; |
198 | 200 | ||
201 | if (host->h_rpcclnt) | ||
202 | nodename = host->h_rpcclnt->cl_nodename; | ||
203 | |||
199 | /* | 204 | /* |
200 | * Choose whether to record the caller_name or IP address of | 205 | * Choose whether to record the caller_name or IP address of |
201 | * this peer in the local rpc.statd's database. | 206 | * this peer in the local rpc.statd's database. |
202 | */ | 207 | */ |
203 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 208 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
204 | 209 | ||
205 | clnt = nsm_client_get(host->net); | 210 | clnt = nsm_client_get(host->net, nodename); |
206 | if (IS_ERR(clnt)) { | 211 | if (IS_ERR(clnt)) { |
207 | status = PTR_ERR(clnt); | 212 | status = PTR_ERR(clnt); |
208 | dprintk("lockd: failed to create NSM upcall transport, " | 213 | dprintk("lockd: failed to create NSM upcall transport, " |