NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/48135: Bad locking for umount
>Number: 48135
>Category: kern
>Synopsis: Bad locking for umount
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Aug 18 11:00:00 +0000 2013
>Originator: mlelstv%serpens.de@localhost
>Release: NetBSD 6.99.23
>Organization:
>Environment:
System: NetBSD pussyfoot 6.99.23 NetBSD 6.99.23 (PUSSYFOOT) #2: Sun Aug 18
12:13:03 CEST 2013
mlelstv@pussyfoot:/home/netbsd-current/obj.amd64/home/netbsd-current/src/sys/arch/amd64/compile/PUSSYFOOT
amd64
Architecture: x86_64
Machine: amd64
>Description:
Accessing a filesystem that is being umounted can cause a panic
for a LOCKDEBUG kernel and undefined behaviour otherwise.
There is a race condition between vfs_busy() and vfs_destroy().
When vfs_destroy() decrements the reference count of a mount to
zero, it assumes that no code accesses the mount point.
vfs_busy() starts with the assumption that there is already
a reference to the mount point. However, that reference may go
away at any time.
A LOCKDEBUG kernel panics when vfs_busy() has acquired a mutex
and vfs_destroy() tries to destroy the mutex. Without that check
vfs_destroy() continues to free the data structure that is still
used by vfs_busy().
>How-To-Repeat:
On a LOCKDEBUG system, start automounter with auto_attrcache=1, and
run something like:
while true; do
ls -ld /amd/watchpoint/.
done
>Fix:
The following diff makes vfs_busy() increment the reference count
to protect the data structure and calls vfs_destroy() in its
failure path to unreference (and possibly free) the data structure.
The last hunk avoids another possible use-after-free case in
vfs_unbusy().
Index: sys/kern/vfs_mount.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_mount.c,v
retrieving revision 1.19
diff -u -r1.19 vfs_mount.c
--- sys/kern/vfs_mount.c 28 Apr 2013 21:34:31 -0000 1.19
+++ sys/kern/vfs_mount.c 18 Aug 2013 10:48:42 -0000
@@ -288,6 +288,7 @@
KASSERT(mp->mnt_refcnt > 0);
+ atomic_inc_uint(&mp->mnt_refcnt);
mutex_enter(&mp->mnt_unmounting);
if (__predict_false((mp->mnt_iflag & IMNT_GONE) != 0)) {
mutex_exit(&mp->mnt_unmounting);
@@ -295,6 +296,7 @@
KASSERT(mutex_owned(&mountlist_lock));
*nextp = CIRCLEQ_NEXT(mp, mnt_list);
}
+ vfs_destroy(mp);
return ENOENT;
}
++mp->mnt_busynest;
@@ -303,7 +305,6 @@
if (nextp != NULL) {
mutex_exit(&mountlist_lock);
}
- atomic_inc_uint(&mp->mnt_refcnt);
return 0;
}
@@ -328,13 +329,13 @@
KASSERT(mp->mnt_busynest != 0);
mp->mnt_busynest--;
mutex_exit(&mp->mnt_unmounting);
- if (!keepref) {
- vfs_destroy(mp);
- }
if (nextp != NULL) {
KASSERT(mutex_owned(&mountlist_lock));
*nextp = CIRCLEQ_NEXT(mp, mnt_list);
}
+ if (!keepref) {
+ vfs_destroy(mp);
+ }
}
/*
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index