James Youngman wrote: > On Mon, Nov 22, 2004 at 06:05:43PM -0800, Martin Buchholz wrote: > > >>I mean, >>- first go back to the parent directory >>- then lstat("foo"); check if it's a symlink or a real directory >>- if a symlink, then this is fishy, but it could happen non-maliciously. >> I would issue a warning, then continue, without chdir'ing into foo. >>- if a directory, then probably we've hit the automounter problem. >> Don't issue a warning; chdir("foo") again; this time it should work. > > > It sounds like this strategy, which is the same as we currently do, > but with a retry, is fairly sensible. > > The only problem that occurs to me is that we did not recheck "foo" to > see if it still matches the predictes specified on the find command > line (think about commands like > find /z -user fred -o -name baz -print > > ... here, if the original "foo" was owned by root but the "new" foo is > owned by fred, our retrying technique has ensured that we have > wandered into a place which we are not supposed to. It's possible > that we could simply reissue process_path() to retry instead of > directly trying the chdir("foo") again. I can't remember offhand if > that is likely to be a viable strategy. I don't know the details of find's implementation. Conceptually, I would want to forget everything I knew about "foo", except that we've already tried it, So re-process this path again in its entirety. This way, when find reports a file, it was at least reporting the true state of the file AT SOME POINT. E.g. if a file is changing from a regular file owned by Bob, to a directory owned by Alice, then find -user Bob -type d should never report that file. > >>Unlike replacing directories with symlinks, where the malicious >>possibilities are evident, I don't see any malicious possibilities >>arising out of mounted filesystems replaced by other filesystems. > > > Is there a consensus agreeing with this point of view? If so, that > would make the implementsation much simpler... > > > >>Hmmm... You're right. I guess you'd have to: >>FD=open("foo"); >>ST1=lstat("foo"); > > > I think find would have to use xstat() there because "-L" ("-follow") > might be in effect, problematic though it is security-wise. xstat in > GNU find is a function pointer that points to lstat() if the -P flag > is in effect (this is the default; the explicit -P is a BSD > invention), points to stat() if the -L flag is in effect, and points > to a more complex function optionh_stat() if -H is in effect > (optionh_stat() eventually calls either stat() or lstat()). My suggestion is very high-level pseudocode. There are a lot of details to get right, as you point out. > >>ST2=fstat(FD); >>compare(ST1,ST2); >>fchdir(FD); > > > I wonder what happens there if we're at an automount mount point. > Does the fchdir() provoke automount() into mounting the filesystem? > Would you be able to check this, Martin? It does. Here's a test program, and a sample run against an automounter mount point: ----------------------------------------------------------------- #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> void printID(char *file) { struct stat s; if (lstat(file,&s) < 0) exit(1); printf("file=\"%s\" dev=%ld ino=%ld\n", file, (long) s.st_dev, (long) s.st_ino); } int main (int argc, char *argv[]) { char *d = argv[1]; printID(d); int fdParent = open(".", O_RDONLY); int fdChild = open(d, O_RDONLY); if (fchdir(fdChild) < 0) exit(1); printID("."); printID(".."); if (fchdir(fdParent) < 0) exit(1); printID(d); } ----------------------------------------------------------------- $ ~/src/a.out make file="make" dev=81033283 ino=186105 file="." dev=80744820 ino=1353076 file=".." dev=81033281 ino=186097 file="make" dev=80744820 ino=1353076 $ ~/src/a.out make file="make" dev=80744820 ino=1353076 file="." dev=80744820 ino=1353076 file=".." dev=81033281 ino=186097 file="make" dev=80744820 ino=1353076 > >>On a related note, >>Solaris has some interesting non-standard functions: >> >> int openat(int fildes, const char *path, int oflag, /* >> mode_t mode */...); >> >> The openat() function is identical to the open() function >> except that the path argument is interpreted relative to the >> starting point implied by the fd argument. If the fd argu- >> ment has the special value AT_FDCWD, a relative path argu- >> ment will be resolved relative to the current working direc- >> tory. If the path argument is absolute, the fd argument is >> ignored. > > > So, with an absolute path or with AT_FDCWD, it's equivalent to > open(2)? If'a a shame that openat() doesn't have a flag to prevent it > following symbolic links. Or does it? > fstatat has such a flag, bug openat does not. Another interesting function is DIR *fdopendir(int fildes); The fdopendir() function opens a directory stream for the directory file descriptor fildes. The directory file discriptor should not be used or closed following a success- ful function call, as this might cause undefined results from future operations on the directory stream obtained from the call. Use closedir(3C) to close a directory stream. BTW, all the Sun man pages are easily googlable with a query like openat site:docs.sun.com Martin