From owner-freebsd-security Fri Oct 11 14:20:27 2002 Delivered-To: freebsd-security@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 674B337B401 for ; Fri, 11 Oct 2002 14:20:24 -0700 (PDT) Received: from c18609.belrs1.nsw.optusnet.com.au (c18609.belrs1.nsw.optusnet.com.au [210.49.80.204]) by mx1.FreeBSD.org (Postfix) with ESMTP id E2D2343E97 for ; Fri, 11 Oct 2002 14:20:22 -0700 (PDT) (envelope-from peterjeremy@optushome.com.au) Received: from server.c18609.belrs1.nsw.optusnet.com.au (localhost.c18609.belrs1.nsw.optusnet.com.au [127.0.0.1]) by server.c18609.belrs1.nsw.optusnet.com.au (8.12.6/8.12.6) with ESMTP id g9BLKKeB000229; Sat, 12 Oct 2002 07:20:20 +1000 (EST) (envelope-from peter@server.c18609.belrs1.nsw.optusnet.com.au) Received: (from peter@localhost) by server.c18609.belrs1.nsw.optusnet.com.au (8.12.6/8.12.6/Submit) id g9BLKKan000228; Sat, 12 Oct 2002 07:20:20 +1000 (EST) Date: Sat, 12 Oct 2002 07:20:20 +1000 From: Peter Jeremy To: Chris BeHanna Cc: FreeBSD Security Subject: Re: access() is a security hole? Message-ID: <20021011212020.GA209@server.c18609.belrs1.nsw.optusnet.com.au> References: <20021011185423.B12227-100000@gamplex.bde.org> <20021011094935.I86274-100000@topperwein.pennasoft.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20021011094935.I86274-100000@topperwein.pennasoft.com> User-Agent: Mutt/1.4i Sender: owner-freebsd-security@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org On Fri, Oct 11, 2002 at 10:01:30AM -0400, Chris BeHanna wrote: > Perhaps the way to avoid the race is to open the file, lock it, >and *then* call access(), then close the file or proceed based upon >the result. > > Yes, I know--there's a possible race between open() and fcntl(). ... > Once a process has the lock, it can call fstat() to determine if >the real [ug]id (which it already knows) has permission to access the >file in the desired manner. I can see two more critical problems: Firstly, open() options like O_TRUNC and O_CREAT will have already modified the file based on the e[gu]id before the later checks discover that the r[gu]id shouldn't have access to the file. You can delay the O_TRUNC by calling ftruncate() later, but there's no way to postpone O_CREAT. Secondly (and more seriously), open() only returns a file descriptor referring to the leaf file in the pathname - and file locks only affect that specific file. Using fstat() on the returned descriptor can only tell you the access permissions on that particular file, it can't tell you that access should have been blocked due to permissions on intervening directories - and the file lock won't prevent an attacker changing the intervening directory structure. The sequence open(),fstat(),access(),stat() and verifying that the inode returned by the fstat() and stat() are the same makes the race harder to win, but there's still a race: Someone could manage to swap the file back to the original between the access() and stat(). It's not at all clear how to solve this in userland. In the absence of symlinks, you can parse the pathname, using open(),fstat(),fchdir() to securely get to the final pathname component. Unfortunately, there's no way to securely do this and handle symlinks (because you have to use lstat() to detect a symlink and there is a gap between the lstat() and subsequent open(). The only solution I can see is a new "open_as_real_user()" system call which is identical to open(2) except that it performs all the access checks using the processes real credentials instead of the effective credentials. (This could potentially be done using a new O_REALUSER flag on the existing open()). Peter To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message