From owner-freebsd-hackers@FreeBSD.ORG Tue May 21 16:17:28 2013 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 04FC3FBC for ; Tue, 21 May 2013 16:17:28 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from bigwig.baldwin.cx (bigwig.baldwin.cx [IPv6:2001:470:1f11:75::1]) by mx1.freebsd.org (Postfix) with ESMTP id CCBABBFD for ; Tue, 21 May 2013 16:17:27 +0000 (UTC) Received: from jhbbsd.localnet (unknown [209.249.190.124]) by bigwig.baldwin.cx (Postfix) with ESMTPSA id B5037B964; Tue, 21 May 2013 12:17:24 -0400 (EDT) From: John Baldwin To: freebsd-hackers@freebsd.org Subject: Re: find -delete broken, or just used improperly? Date: Tue, 21 May 2013 11:06:39 -0400 User-Agent: KMail/1.13.5 (FreeBSD/8.2-CBSD-20110714-p25; KDE/4.5.5; amd64; ; ) References: <20130520192316.GA32531@pix.net> <20130520214731.GA43407@stack.nl> In-Reply-To: <20130520214731.GA43407@stack.nl> MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-Id: <201305211106.39313.jhb@freebsd.org> X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.7 (bigwig.baldwin.cx); Tue, 21 May 2013 12:17:24 -0400 (EDT) Cc: Kurt Lidl , Jilles Tjoelker X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 May 2013 16:17:28 -0000 On Monday, May 20, 2013 5:47:31 pm Jilles Tjoelker wrote: > On Mon, May 20, 2013 at 03:23:16PM -0400, Kurt Lidl wrote: > > OK, maybe I'm missing something obvious, but... > > > find(1) says: > > > -delete > > Delete found files and/or directories. Always returns true. > > This executes from the current working directory as find recurses > > down the tree. It will not attempt to delete a filename with a > > ``/'' character in its pathname relative to ``.'' for security > > reasons. Depth-first traversal processing is implied by this > > option. Following symlinks is incompatible with this option. > > > However, it fails even when the path is absolute: > > > bhyve9# mkdir /tmp/foo > > bhyve9# find /tmp/foo -empty -delete > > find: -delete: /tmp/foo: relative path potentially not safe > > > Shouldn't this work? > > The "relative path" refers to a pathname that contains a slash other > than at the beginning or end and may therefore refer to somewhere else > if a directory is concurrently replaced by a symlink. > > When -L is not specified and "." can be opened, the fts(3) code > underlying find(1) is careful to avoid following symlinks or being > dropped in different locations by moving the directory fts is currently > traversing. If a problematic concurrent modification is detected, fts > will not enter the directory or abort. Files found in the search are > returned via the current working directory and a pathname not containing > a slash. > > For paranoia, find(1) verifies this when -delete is used. However, it is > too paranoid about the root of the traversal. It is already assumed that > the initial pathname does not refer to directories or symlinks that > might be replaced by untrusted users; otherwise, the whole traversal > would be unsafe. Therefore, it is not necessary to do the check for > fts_level == FTS_ROOTLEVEL. > > The below patch allows deleting the pathname given to find itself: > > Index: usr.bin/find/function.c > =================================================================== > --- usr.bin/find/function.c (revision 250661) > +++ usr.bin/find/function.c (working copy) > @@ -442,7 +442,8 @@ > errx(1, "-delete: forbidden when symlinks are followed"); > > /* Potentially unsafe - do not accept relative paths whatsoever */ > - if (strchr(entry->fts_accpath, '/') != NULL) > + if (entry->fts_level > FTS_ROOTLEVEL && > + strchr(entry->fts_accpath, '/') != NULL) > errx(1, "-delete: %s: relative path potentially not safe", > entry->fts_accpath); I'm curious, how would you instruct a patched find to avoid deleteing the /tmp/foo directory (e.g. if you wanted this to be a job that pruned empty dirs from /tmp/foo but never pruned the directory itself). Would -mindepth 1 do it? (Just asking. I have also found this message annoying but most of the jobs I have seen it on probably don't want to delete the root path, just descendants.) -- John Baldwin