autofs4: close the races around autofs4_notify_daemon()
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 14 Sep 2013 21:32:12 +0000 (17:32 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 16 Sep 2013 23:16:38 +0000 (19:16 -0400)
Don't drop ->wq_mutex before calling autofs4_notify_daemon() only to regain it
there.  Besides being pointless, that opens a race window where autofs4_wait_release()
could've come and freed wq->name.name.  And do the debugging printk in the "reused an
existing wq" case before dropping ->wq_mutex - the same reason...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Ian Kent <raven@themaw.net>
fs/autofs4/waitq.c

index 3db70dae40d3a842de562c9fb4e26c29f9284239..689e40d983ad64ca3726cd5f8dd64c44d49bb5e6 100644 (file)
@@ -109,13 +109,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
 
        pkt.hdr.proto_version = sbi->version;
        pkt.hdr.type = type;
-       mutex_lock(&sbi->wq_mutex);
 
-       /* Check if we have become catatonic */
-       if (sbi->catatonic) {
-               mutex_unlock(&sbi->wq_mutex);
-               return;
-       }
        switch (type) {
        /* Kernel protocol v4 missing and expire packets */
        case autofs_ptype_missing:
@@ -427,7 +421,6 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                wq->tgid = current->tgid;
                wq->status = -EINTR; /* Status return if interrupted */
                wq->wait_ctr = 2;
-               mutex_unlock(&sbi->wq_mutex);
 
                if (sbi->version < 5) {
                        if (notify == NFY_MOUNT)
@@ -449,15 +442,15 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                        (unsigned long) wq->wait_queue_token, wq->name.len,
                        wq->name.name, notify);
 
-               /* autofs4_notify_daemon() may block */
+               /* autofs4_notify_daemon() may block; it will unlock ->wq_mutex */
                autofs4_notify_daemon(sbi, wq, type);
        } else {
                wq->wait_ctr++;
-               mutex_unlock(&sbi->wq_mutex);
-               kfree(qstr.name);
                DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
                        (unsigned long) wq->wait_queue_token, wq->name.len,
                        wq->name.name, notify);
+               mutex_unlock(&sbi->wq_mutex);
+               kfree(qstr.name);
        }
 
        /*