diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-14 17:32:12 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-16 19:16:38 -0400 |
commit | 606035e76e79b14bf7a7c219140c045a952cc76e (patch) | |
tree | 43958ffa5278f8ba9d1d6a8884087b196952e94a | |
parent | 3711d86a2de17e967b576af8b8a1e9351a7d1466 (diff) |
autofs4: close the races around autofs4_notify_daemon()
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>
-rw-r--r-- | fs/autofs4/waitq.c | 13 |
1 files changed, 3 insertions, 10 deletions
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 3db70dae40d3..689e40d983ad 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -109,13 +109,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
109 | 109 | ||
110 | pkt.hdr.proto_version = sbi->version; | 110 | pkt.hdr.proto_version = sbi->version; |
111 | pkt.hdr.type = type; | 111 | pkt.hdr.type = type; |
112 | mutex_lock(&sbi->wq_mutex); | ||
113 | 112 | ||
114 | /* Check if we have become catatonic */ | ||
115 | if (sbi->catatonic) { | ||
116 | mutex_unlock(&sbi->wq_mutex); | ||
117 | return; | ||
118 | } | ||
119 | switch (type) { | 113 | switch (type) { |
120 | /* Kernel protocol v4 missing and expire packets */ | 114 | /* Kernel protocol v4 missing and expire packets */ |
121 | case autofs_ptype_missing: | 115 | case autofs_ptype_missing: |
@@ -427,7 +421,6 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
427 | wq->tgid = current->tgid; | 421 | wq->tgid = current->tgid; |
428 | wq->status = -EINTR; /* Status return if interrupted */ | 422 | wq->status = -EINTR; /* Status return if interrupted */ |
429 | wq->wait_ctr = 2; | 423 | wq->wait_ctr = 2; |
430 | mutex_unlock(&sbi->wq_mutex); | ||
431 | 424 | ||
432 | if (sbi->version < 5) { | 425 | if (sbi->version < 5) { |
433 | if (notify == NFY_MOUNT) | 426 | if (notify == NFY_MOUNT) |
@@ -449,15 +442,15 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
449 | (unsigned long) wq->wait_queue_token, wq->name.len, | 442 | (unsigned long) wq->wait_queue_token, wq->name.len, |
450 | wq->name.name, notify); | 443 | wq->name.name, notify); |
451 | 444 | ||
452 | /* autofs4_notify_daemon() may block */ | 445 | /* autofs4_notify_daemon() may block; it will unlock ->wq_mutex */ |
453 | autofs4_notify_daemon(sbi, wq, type); | 446 | autofs4_notify_daemon(sbi, wq, type); |
454 | } else { | 447 | } else { |
455 | wq->wait_ctr++; | 448 | wq->wait_ctr++; |
456 | mutex_unlock(&sbi->wq_mutex); | ||
457 | kfree(qstr.name); | ||
458 | DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", | 449 | DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", |
459 | (unsigned long) wq->wait_queue_token, wq->name.len, | 450 | (unsigned long) wq->wait_queue_token, wq->name.len, |
460 | wq->name.name, notify); | 451 | wq->name.name, notify); |
452 | mutex_unlock(&sbi->wq_mutex); | ||
453 | kfree(qstr.name); | ||
461 | } | 454 | } |
462 | 455 | ||
463 | /* | 456 | /* |