Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 May 2013 11:06:39 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-hackers@freebsd.org
Cc:        Kurt Lidl <lidl@pix.net>, Jilles Tjoelker <jilles@stack.nl>
Subject:   Re: find -delete broken, or just used improperly?
Message-ID:  <201305211106.39313.jhb@freebsd.org>
In-Reply-To: <20130520214731.GA43407@stack.nl>
References:  <20130520192316.GA32531@pix.net> <20130520214731.GA43407@stack.nl>

next in thread | previous in thread | raw e-mail | index | archive | help
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



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