Subject: kern/1677: union FS can return bogus value for lookup of `.', causing later panic
To: None <gnats-bugs@gnats.netbsd.org>
From: John Kohl <jtk@kolvir.arlington.ma.us>
List: netbsd-bugs
Date: 10/23/1995 19:10:21
>Number: 1677
>Category: kern
>Synopsis: union FS can return bogus value for lookup of `.', causing later panic
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Oct 23 19:35:03 1995
>Last-Modified:
>Originator: John Kohl
>Organization:
NetBSD Kernel Hackers `R` Us
>Release: NetBSD-1.1ALPHA, 22 October 1995
>Environment:
System: NetBSD pattern 1.1_ALPHA NetBSD 1.1_ALPHA (PATTERN) #195: Sun Oct 22 13:31:09 EDT 1995 jtk@pattern:/u1/NetBSD-current/src/sys/arch/i386/compile/PATTERN i386
>Description:
If the union FS is looking up `.' in a directory which is searchable in
the top level but unsearchable in the bottom level, it returns a union vnode
that is not the same as the starting vnode. This returned vnode is only
half-locked, in that another union vnode points to the same lower layer
vnode.
Because the lower layer could not be looked up, union_lookup() called
union_allocvp() with lowervp == NULLVP. This resulted in
union_allocvp() failing to find the "real" cached vnode for `.' and it
creates a new one. The new one has UN_LOCKED set, and the uppervp is
indeed locked, but the lock was taken on behalf of the "real" vnode for `.'
This causes trouble in things like sys_lstat() and it kin which have
code like:
NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
SCARG(uap, path), p);
if (error = namei(&nd))
return (error);
vp = nd.ni_vp;
dvp = nd.ni_dvp;
if (dvp == vp)
vrele(dvp);
else
vput(dvp);
error = vn_stat(vp, &sb, p);
vput(vp);
if (error)
return (error);
The second vput() results in a panic from UFS (if DIAGNOSTIC) when it
attempts to unlock an unlocked UFS vnode.
>How-To-Repeat:
1) in the lower layer:
mkdir Foo
chmod 700 Foo
chown otheruser Foo
2) in the upper layer:
mkdir Foo
3) mount the union FS
4) ls -la /union_mountpoint/Foo
5) watch the machine croak
>Fix:
Not sure what the "right thing" is. Maybe short-circuit `.'?
What about other cases where some user might not have the appropriate
lookup permissions in the lower layer? It seems like we must never let
union_allocvp() be called in such a way as to generate two union vnodes
for the same underlying object.
>Audit-Trail:
>Unformatted: