2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-20 00:26:39 +08:00

autofs4: fix waitq locking

The autofs4_catatonic_mode() function accesses the wait queue without any
locking but can be called at any time.  This could lead to a possible
double free of the name field of the wait and a double fput of the daemon
communication pipe or an fput of a NULL file pointer.

Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Ian Kent 2008-07-23 21:30:17 -07:00 committed by Linus Torvalds
parent 70b52a0a50
commit 5a11d4d0ee
2 changed files with 14 additions and 13 deletions

View File

@ -163,8 +163,8 @@ void autofs4_kill_sb(struct super_block *sb)
if (!sbi)
goto out_kill_sb;
if (!sbi->catatonic)
autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
/* Free wait queues, close pipe */
autofs4_catatonic_mode(sbi);
/* Clean up and release dangling references */
autofs4_force_release(sbi);

View File

@ -28,6 +28,12 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
{
struct autofs_wait_queue *wq, *nwq;
mutex_lock(&sbi->wq_mutex);
if (sbi->catatonic) {
mutex_unlock(&sbi->wq_mutex);
return;
}
DPRINTK("entering catatonic mode");
sbi->catatonic = 1;
@ -45,6 +51,8 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
}
fput(sbi->pipe); /* Close the pipe */
sbi->pipe = NULL;
sbi->pipefd = -1;
mutex_unlock(&sbi->wq_mutex);
}
static int autofs4_write(struct file *file, const void *addr, int bytes)
@ -333,17 +341,10 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
wq->name.name, notify);
}
/* wq->name is NULL if and only if the lock is already released */
if (sbi->catatonic) {
/* We might have slept, so check again for catatonic mode */
wq->status = -ENOENT;
if (wq->name.name) {
kfree(wq->name.name);
wq->name.name = NULL;
}
}
/*
* wq->name.name is NULL iff the lock is already released
* or the mount has been made catatonic.
*/
if (wq->name.name) {
/* Block all but "shutdown" signals while waiting */
sigset_t oldset;