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: