Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Jun 2002 16:11:17 +0200 (CEST)
From:      Serge van den Boom <svdb@stack.nl>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/39331: namei cache unreliable for __getcwd()
Message-ID:  <20020615141117.F38FB63@inferno.stuiver.net>

next in thread | raw e-mail | index | archive | help


>Number:         39331
>Category:       kern
>Synopsis:       namei cache unreliable for __getcwd()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jun 15 07:30:02 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Serge van den Boom
>Release:        FreeBSD 4.5-RELEASE i386
>Organization:
M.C.G.V. Stack
>Environment:
System: FreeBSD inferno.stuiver.net 4.5-RELEASE FreeBSD 4.5-RELEASE #0: Sun Mar 17 04:23:07 CET 2002 svdb@inferno.stuiver.net:/usr/src/sys/compile/INFERNO i386

>Description:
The libc function getcwd() calls the kernel function __getcwd() to see if
the current directory is in the namei cache, in which case it can save
itself a lot of work. If not, getcwd() records the path itself by going
back to the root dir by following the '..' links.
The problem is that the information that __getcwd() returns, may be out of
date. A parent dir of the cwd might have been moved, or its permissions may
no longer allow the current user to inspect a dir part.
The result is that getcwd() might sometimes return the incorrect old value,
and sometimes the new, correct value (or error), depending on whether the dir
is in the namei cache. This can lead to unexpected results, as a namei may
leave the cache during the execution of a program, as the 'how-to-repeat'
will show.

>How-To-Repeat:
$ mkdir foo foo/bar foo/bar/{a,b}
$ cd foo/bar
$ chmod ../../foo
$ mv a b /tmp  # A dir on another filesystem
mv: cannot resolve b: b

'a' will be moved, but not 'b'.
So what happened?
For each of the arguments 'a' and 'b', mv calls realpath(), which calls
getcwd(). At the time of the getcwd() call for 'a', the current dir is still
in the namei cache, and __getcwd(), called by getcwd() will return its name.
At the time of the getcwd() call for 'b', the current dir is no longer in
the namei cache, and __getcwd() will fail. getcwd() will try to build the
path itself by following the '..' links, but that fails on the permissions,
so 'b' can't be resolved, and its move fails.

BTW, the reason the move has to be cross-filesystem, is because otherwise
realpath() won't be called by /bin/mv.

>Fix:
Invalidate the namei entry for all subdirs of a dir (and the dir itself)
when its permissions change, or the dir is moved?
Though it's probably not as simple as I might make it look here.

>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020615141117.F38FB63>