aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2012-02-27 13:05:45 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-02-27 13:37:09 -0500
commit2c9030eef9dbd0d737a7f55646da70d217fd6255 (patch)
tree69f1eafced52fef9d3939d8e1246d5063d14649a /net
parente9dbca8d732e20b8d31a3094a8669c014e7ee262 (diff)
SUNRPC: check RPC inode's pipe reference before dereferencing
There are 2 tightly bound objects: pipe data (created for kernel needs, has reference to dentry, which depends on PipeFS mount/umount) and PipeFS dentry/inode pair (created on mount for user-space needs). They both independently may have or have not a valid reference to each other. This means, that we have to make sure, that pipe->dentry reference is valid on upcalls, and dentry->pipe reference is valid on downcalls. The latter check is absent - my fault. IOW, PipeFS dentry can be opened by some process (rpc.idmapd for example), but it's pipe data can belong to NFS mount, which was unmounted already and thus pipe data was destroyed. To fix this, pipe reference have to be set to NULL on rpc_unlink() and checked on PipeFS file operations instead of pipe->dentry check. Note: PipeFS "poll" file operation will be updated in next patch, because it's logic is more complicated. Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/rpc_pipe.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 6873c9b51cc9..b67b2aecc4ff 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -174,6 +174,7 @@ rpc_close_pipes(struct inode *inode)
174 pipe->ops->release_pipe(inode); 174 pipe->ops->release_pipe(inode);
175 cancel_delayed_work_sync(&pipe->queue_timeout); 175 cancel_delayed_work_sync(&pipe->queue_timeout);
176 rpc_inode_setowner(inode, NULL); 176 rpc_inode_setowner(inode, NULL);
177 RPC_I(inode)->pipe = NULL;
177 mutex_unlock(&inode->i_mutex); 178 mutex_unlock(&inode->i_mutex);
178} 179}
179 180
@@ -203,12 +204,13 @@ rpc_destroy_inode(struct inode *inode)
203static int 204static int
204rpc_pipe_open(struct inode *inode, struct file *filp) 205rpc_pipe_open(struct inode *inode, struct file *filp)
205{ 206{
206 struct rpc_pipe *pipe = RPC_I(inode)->pipe; 207 struct rpc_pipe *pipe;
207 int first_open; 208 int first_open;
208 int res = -ENXIO; 209 int res = -ENXIO;
209 210
210 mutex_lock(&inode->i_mutex); 211 mutex_lock(&inode->i_mutex);
211 if (pipe->dentry == NULL) 212 pipe = RPC_I(inode)->pipe;
213 if (pipe == NULL)
212 goto out; 214 goto out;
213 first_open = pipe->nreaders == 0 && pipe->nwriters == 0; 215 first_open = pipe->nreaders == 0 && pipe->nwriters == 0;
214 if (first_open && pipe->ops->open_pipe) { 216 if (first_open && pipe->ops->open_pipe) {
@@ -229,12 +231,13 @@ out:
229static int 231static int
230rpc_pipe_release(struct inode *inode, struct file *filp) 232rpc_pipe_release(struct inode *inode, struct file *filp)
231{ 233{
232 struct rpc_pipe *pipe = RPC_I(inode)->pipe; 234 struct rpc_pipe *pipe;
233 struct rpc_pipe_msg *msg; 235 struct rpc_pipe_msg *msg;
234 int last_close; 236 int last_close;
235 237
236 mutex_lock(&inode->i_mutex); 238 mutex_lock(&inode->i_mutex);
237 if (pipe->dentry == NULL) 239 pipe = RPC_I(inode)->pipe;
240 if (pipe == NULL)
238 goto out; 241 goto out;
239 msg = filp->private_data; 242 msg = filp->private_data;
240 if (msg != NULL) { 243 if (msg != NULL) {
@@ -270,12 +273,13 @@ static ssize_t
270rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) 273rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
271{ 274{
272 struct inode *inode = filp->f_path.dentry->d_inode; 275 struct inode *inode = filp->f_path.dentry->d_inode;
273 struct rpc_pipe *pipe = RPC_I(inode)->pipe; 276 struct rpc_pipe *pipe;
274 struct rpc_pipe_msg *msg; 277 struct rpc_pipe_msg *msg;
275 int res = 0; 278 int res = 0;
276 279
277 mutex_lock(&inode->i_mutex); 280 mutex_lock(&inode->i_mutex);
278 if (pipe->dentry == NULL) { 281 pipe = RPC_I(inode)->pipe;
282 if (pipe == NULL) {
279 res = -EPIPE; 283 res = -EPIPE;
280 goto out_unlock; 284 goto out_unlock;
281 } 285 }
@@ -313,13 +317,12 @@ static ssize_t
313rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) 317rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
314{ 318{
315 struct inode *inode = filp->f_path.dentry->d_inode; 319 struct inode *inode = filp->f_path.dentry->d_inode;
316 struct rpc_pipe *pipe = RPC_I(inode)->pipe;
317 int res; 320 int res;
318 321
319 mutex_lock(&inode->i_mutex); 322 mutex_lock(&inode->i_mutex);
320 res = -EPIPE; 323 res = -EPIPE;
321 if (pipe->dentry != NULL) 324 if (RPC_I(inode)->pipe != NULL)
322 res = pipe->ops->downcall(filp, buf, len); 325 res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len);
323 mutex_unlock(&inode->i_mutex); 326 mutex_unlock(&inode->i_mutex);
324 return res; 327 return res;
325} 328}
@@ -344,16 +347,18 @@ static long
344rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 347rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
345{ 348{
346 struct inode *inode = filp->f_path.dentry->d_inode; 349 struct inode *inode = filp->f_path.dentry->d_inode;
347 struct rpc_pipe *pipe = RPC_I(inode)->pipe; 350 struct rpc_pipe *pipe;
348 int len; 351 int len;
349 352
350 switch (cmd) { 353 switch (cmd) {
351 case FIONREAD: 354 case FIONREAD:
352 spin_lock(&pipe->lock); 355 mutex_lock(&inode->i_mutex);
353 if (pipe->dentry == NULL) { 356 pipe = RPC_I(inode)->pipe;
354 spin_unlock(&pipe->lock); 357 if (pipe == NULL) {
358 mutex_unlock(&inode->i_mutex);
355 return -EPIPE; 359 return -EPIPE;
356 } 360 }
361 spin_lock(&pipe->lock);
357 len = pipe->pipelen; 362 len = pipe->pipelen;
358 if (filp->private_data) { 363 if (filp->private_data) {
359 struct rpc_pipe_msg *msg; 364 struct rpc_pipe_msg *msg;
@@ -361,6 +366,7 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
361 len += msg->len - msg->copied; 366 len += msg->len - msg->copied;
362 } 367 }
363 spin_unlock(&pipe->lock); 368 spin_unlock(&pipe->lock);
369 mutex_unlock(&inode->i_mutex);
364 return put_user(len, (int __user *)arg); 370 return put_user(len, (int __user *)arg);
365 default: 371 default:
366 return -EINVAL; 372 return -EINVAL;