From owner-freebsd-bugs Sat Jun 15 7:30:18 2002 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id C6D4B37B419 for ; Sat, 15 Jun 2002 07:30:02 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g5FEU2Z97778; Sat, 15 Jun 2002 07:30:02 -0700 (PDT) (envelope-from gnats) Received: from inferno.stuiver.net (t-indiv8-234.athome.tue.nl [131.155.242.234]) by hub.freebsd.org (Postfix) with ESMTP id 87A2E37B408 for ; Sat, 15 Jun 2002 07:23:13 -0700 (PDT) Received: by inferno.stuiver.net (Postfix, from userid 1106) id F38FB63; Sat, 15 Jun 2002 16:11:17 +0200 (CEST) Message-Id: <20020615141117.F38FB63@inferno.stuiver.net> Date: Sat, 15 Jun 2002 16:11:17 +0200 (CEST) From: Serge van den Boom Reply-To: Serge van den Boom To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: kern/39331: namei cache unreliable for __getcwd() Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >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