diff options
author | Ian Kent <raven@themaw.net> | 2008-07-24 00:30:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 13:47:32 -0400 |
commit | 5a11d4d0ee1ff284271f7265929d07ea4a1168a6 (patch) | |
tree | 4b9b76486afa5d9fc29216df069c5a557e09011a /fs/autofs4 | |
parent | 70b52a0a5005ce6a0ceec56e97222437a0ba7506 (diff) |
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>
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/inode.c | 4 | ||||
-rw-r--r-- | fs/autofs4/waitq.c | 23 |
2 files changed, 14 insertions, 13 deletions
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index e3e70994ab46..7bb3e5ba0537 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -163,8 +163,8 @@ void autofs4_kill_sb(struct super_block *sb) | |||
163 | if (!sbi) | 163 | if (!sbi) |
164 | goto out_kill_sb; | 164 | goto out_kill_sb; |
165 | 165 | ||
166 | if (!sbi->catatonic) | 166 | /* Free wait queues, close pipe */ |
167 | autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ | 167 | autofs4_catatonic_mode(sbi); |
168 | 168 | ||
169 | /* Clean up and release dangling references */ | 169 | /* Clean up and release dangling references */ |
170 | autofs4_force_release(sbi); | 170 | autofs4_force_release(sbi); |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 5208cfb1df4e..55aac10cf328 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -28,6 +28,12 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) | |||
28 | { | 28 | { |
29 | struct autofs_wait_queue *wq, *nwq; | 29 | struct autofs_wait_queue *wq, *nwq; |
30 | 30 | ||
31 | mutex_lock(&sbi->wq_mutex); | ||
32 | if (sbi->catatonic) { | ||
33 | mutex_unlock(&sbi->wq_mutex); | ||
34 | return; | ||
35 | } | ||
36 | |||
31 | DPRINTK("entering catatonic mode"); | 37 | DPRINTK("entering catatonic mode"); |
32 | 38 | ||
33 | sbi->catatonic = 1; | 39 | sbi->catatonic = 1; |
@@ -45,6 +51,8 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) | |||
45 | } | 51 | } |
46 | fput(sbi->pipe); /* Close the pipe */ | 52 | fput(sbi->pipe); /* Close the pipe */ |
47 | sbi->pipe = NULL; | 53 | sbi->pipe = NULL; |
54 | sbi->pipefd = -1; | ||
55 | mutex_unlock(&sbi->wq_mutex); | ||
48 | } | 56 | } |
49 | 57 | ||
50 | static int autofs4_write(struct file *file, const void *addr, int bytes) | 58 | 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, | |||
333 | wq->name.name, notify); | 341 | wq->name.name, notify); |
334 | } | 342 | } |
335 | 343 | ||
336 | /* wq->name is NULL if and only if the lock is already released */ | 344 | /* |
337 | 345 | * wq->name.name is NULL iff the lock is already released | |
338 | if (sbi->catatonic) { | 346 | * or the mount has been made catatonic. |
339 | /* We might have slept, so check again for catatonic mode */ | 347 | */ |
340 | wq->status = -ENOENT; | ||
341 | if (wq->name.name) { | ||
342 | kfree(wq->name.name); | ||
343 | wq->name.name = NULL; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (wq->name.name) { | 348 | if (wq->name.name) { |
348 | /* Block all but "shutdown" signals while waiting */ | 349 | /* Block all but "shutdown" signals while waiting */ |
349 | sigset_t oldset; | 350 | sigset_t oldset; |