bronto has asked for the wisdom of the Perl Monks concerning the following question:

Dear Fellow monks

I'm writing a small script to move a lot of data from a file server to another, and I plan to use two piped tars. I'm going to make the script run something like

( cd $sourcefs && tar cpsf - . ) | ( cd $destfs && tar xvpsf - )

The script will then continue and do some chown/chgrp here and there.

Even if I won't have to worry about this script's security, a question arose in my head

As we know, it's a good practice, when you have to chdir to a directory, to leave out any preliminary test on the existence of the directory before chdir; instead, it's better to chdir directly and check the return value to see if it succeeded; this helps to avoid race conditions.

But when you need to chdir and read data in one directory and pipe it to another process, that should chdir, read your data and write it back down to the disk, what would you do to stay on the safe side?

Thanks in advance for your wisdom

Ciao!
--bronto

PS: I know the -C option of GNU tar. Don't worry too much about tar, the question is general and not restricted to my script

# Another Perl edition of a song:
# The End, by The Beatles
END {
  $you->take($love) eq $you->made($love) ;
}

Replies are listed 'Best First'.
Re: chdir and security
by bluto (Curate) on Sep 10, 2002 at 17:55 UTC
    I guess this depends on what you mean by "safe side". There are usually better ways to do this than using this old idiom. For remote machine copies think seriously about using rsync or scp. For local/nfs copies, you can consider using 'cp -r' which is supported by many of the newer OSs. Of course, you could write a perl solution using a CPAN module...

    One problem I have with pipelines is that it is generally hard to check for and handle errors that occur. They are fine for quick and dirty things, but tend to break down if you really care about something working right (or handling errors right) each time.

    For example, what happens if you don't have write access to the target directory or read access to all of the files in the source tree, or you run out of disk space, or you are writing to an soft-mounted NFS filesystem and you have a network problem? If you are using a single command (like 'cp -r), you can examine one error code. In your case it is harder (though not impossible) to check for errors.

    Now if you are talking about security when you mention "safe side" the answer is "it depends". The only general thing I can think of offhand is that you need to be sure you are the only one able to write to the source tree or target directory during the actual copy operation. Of course there could be 100 other issues you have to worry about here (e.g. you are copying the files over a non-encrypted NFS mount between two machines and you decide you can't trust your network).

    bluto

Re: chdir and security
by sauoq (Abbot) on Sep 10, 2002 at 22:22 UTC
    . . .it's better to chdir directly and check the return value to see if it succeeded; this helps to avoid race conditions.

    Depending on your needs, you might also wish to check that the canonical absolute path to your current directory after the chdir() matches what you expect. You can do that with `pwd -P` or, presumably more portably:

    use Cwd; my $cwd = getcwd();

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: chdir and security
by belden (Friar) on Sep 10, 2002 at 21:13 UTC
    ...But when you need to chdir and read data in one directory and pipe it to another process, that should chdir, read your data and write it back down to the disk, what would you do to stay on the safe side?

    This caveat should make you leery of what follows: I'm not a security expert. I can't evaluate whether or where race conditions lie within the code below. What follows is simply how I would try to approach your chdir, tar in, chdir, tar out problem.

    I've tested the above sample; if you populate /tmp/from with some files, they'll be transferred over to /tmp/to as you'd expect.

    But... the description for open, and the existence of perlopentut and the "Safe pipe opens" section in perlipc all make me think that there's got to be problems with this code. If you haven't done so already, take a look through those man pages to see several safer and saner ways of doing the above.

    blyman
    setenv EXINIT 'set noai ts=2'