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; |
