autofs4: fix waitq locking
authorIan Kent <raven@themaw.net>
Thu, 24 Jul 2008 04:30:17 +0000 (21:30 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 24 Jul 2008 17:47:32 +0000 (10:47 -0700)
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>
fs/autofs4/inode.c
fs/autofs4/waitq.c

index e3e70994ab463d62914f7417a11b213e4276f8b7..7bb3e5ba0537e29e6b11f438619f4ccecb71dac0 100644 (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);
index 5208cfb1df4e5f9c134a1bfad60aaf404befe38f..55aac10cf328e43790dd560a44a0b554ab76d192 100644 (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;