Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Two-arg open() considered dangerous

by chip (Curate)
on Dec 12, 2001 at 02:35 UTC ( #131085=perlmeditation: print w/replies, xml ) Need Help??

It seems only prudent to avoid two-argument open() whenever the name of the file is in any way variable. The danger of sudden misbehavior when a filename begins with whitespace ... not to mention the danger of ">" and "|" ... urge the use of 3-arg open() at least. And of course there is great flexibility in sysopen().

Now, have I missed this particular boat, or are most uses of open() just plain dinghy?

    -- Chip Salzenberg, Free-Floating Agent of Chaos

Replies are listed 'Best First'.
Re (tilly) 1: Two-arg open() considered dangerous
by tilly (Archbishop) on Dec 12, 2001 at 02:46 UTC
    Careful thought about that venerable security hole:
    open(INPUT, param("input"));
    demonstrates the truth of what you say. Essentially any API which make data and metadata easily confused should be viewed with suspicion.

    But given that the 3 argument open is not documented as of 5.005_03, I would be cautious about suggesting that people use it in any code whose use is meant to be portable. People will have to use sysopen instead, but now you have to go through extra hoops to pull in the right values of your flags from Fcntl.

      Says Tilly:
      Essentially any API which make data and metadata easily confused should be viewed with suspicion.
      Dan Bernstein says something similar in his explanation of the design of qmail:

    • Don't parse.

      I have discovered that there are two types of command interfaces in the world of computing: good interfaces and user interfaces.

      The essence of user interfaces is parsing: converting an unstructured sequence of commands, in a format usually determined more by psychology than by solid engineering, into structured data.

      When another programmer wants to talk to a user interface, he has to quote: convert his structured data into an unstructured sequence of commands that the parser will, he hopes, convert back into the original structured data.

      This situation is a recipe for disaster. The parser often has bugs: it fails to handle some inputs according to the documented interface. The quoter often has bugs: it produces outputs that do not have the right meaning. Only on rare joyous occasions does it happen that the parser and the quoter both misinterpret the interface in the same way.

      When the original data is controlled by a malicious user, many of these bugs translate into security holes. Some examples: the Linux login -froot security hole; the classic find | xargs rm security hole; the Majordomo injection security hole. Even a simple parser like getopt is complicated enough for people to screw up the quoting.

      In qmail, all the internal file structures are incredibly simple: text0 lines beginning with single-character commands. (text0 format means that lines are separated by a 0 byte instead of line feed.) The program-level interfaces don't take options.

      All the complexity of parsing RFC 822 address lists and rewriting headers is in the qmail-inject program, which runs without privileges and is essentially part of the UA.

    • Looked at from Dan's point of view, the second argument of two-argument open is part of the user interface, a piece of unstructured data (a string) which Perl must parse into structured data (a record that lists the filename and the open mode). A program that wants to use open to open a certain filename with a certain mode must quote this information, turning it into a string, which is then given to open, which then parses it back into a name and a mode. As Dan predicts, the quoting and parsing processes don't always interpret the interface in the same way. Three-argument open allows the structured data to remain more structured throughout, because the mode and filename never need to be combined into a single unstructured string.

      Mark Dominus
      Perl Paraphernalia

      Incidentally, I'd say that this tilly quote deserves preservation:

      Any API which make data and metadata easily confused should be viewed with suspicion.
          -- tilly

          -- Chip Salzenberg, Free-Floating Agent of Chaos

      I agree that three-arg open is a bit new to depend on, but sysopen may not be inconvenient. Specifically, it's guaranteed{1} that O_RDONLY, O_WRONLY, and O_RDWR have the values zero, one, and two, respectively. So sysopen FOO, $file, 0 should work everywhere in the known universe.

      {1} This is OK to count on because the C function open() originates with Unix, and for backwards compatibility with ancient UNIX code, the second parameter of open() must accept zero/one/two.

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        It is not guaranteed. From 'perldoc -f sysopen' on 5.005_03 I get:
        =item sysopen FILEHANDLE,FILENAME,MODE =item sysopen FILEHANDLE,FILENAME,MODE,PERMS [ snip ] The possible values and flag bits of the MODE parameter are system-dependent; they are available via the standard module C<Fcntl>. For historical reasons, some values work on almost every system supported by perl: zero means read-only, one means write-only, and two means read/write. We know that these values do I<not> work under OS/390 & VM/ESA Unix and on the Macintosh; you probably don't want to use them in new code.
        So those values probably work. But not always.
Re: Two-arg open() considered dangerous
by rob_au (Abbot) on Dec 12, 2001 at 05:11 UTC
    For the most part, doesn't this "security danger" simply come down more to the vetting of parameters passed to functions, rather than the functions themselves? I mean, with the use of taint mode (-T), such an open statement would not be allowed as it (presumably) represents a passed parameter which has not been vetted prior to its passing onto open.

    I do however agree with you most heartedly on the matter of sysopen() - A most underused and useful function ...


    perl -e 's&&[@.]/&&s&.com.&_&&&print'

      Good engineering is sometimes about minimizing the likelihood of something bad happening. Compare the legal concept of "attractive nuisance": If you have a swimming pool in your back yard, you're responsible for putting a reasonable fence around it. Those who design programming languages and other interfaces aren't doing their work very well when they create new and easier opportunities for self-fornication.

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        I have to say that I disagree with you here chip - The concept that the language designers should limit an interface to shield even only potentially unfriendly arguments, particularly where such arguments may be perfectly valid (as described by merlyn above), is in itself flawed. Perl has always been described as "providing enough rope to hang yourself with" - I would much rather take those steps of good engineering than sacrifice any power within the underlying language interface.


        perl -e 's&&[@.]/&&s&.com.&_&&&print'

Re: Two-arg open() considered dangerous
by japhy (Canon) on Dec 12, 2001 at 03:50 UTC
    Um, that's why you should explicitly enter the mode yourself.
    open F, "< $f"; open F, "> $f"; open F, ">> $f"; # etc.

    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

      Japhy, you've fallen into the whitespace trap! How does "< $f" help you if $f starts with a space?

      If two-arg open() can mislead as esteemed a monk as japhy, surely we should urge less experienced monks to steer clear of it.

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        perlopentut covers anomolies. Anyway, that's why Perl 5.6 has the multi-arg open(). open(FH, '<', $file)

        Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
        s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

        I think anyone starting a filename with whitespace deserves to suffer. (Actually, I dislike any whitespace at all in a filename, but at least bash will tab-complete those cases. :)
Re: Two-arg open() considered dangerous
by demerphq (Chancellor) on Dec 12, 2001 at 17:55 UTC
    So I suppose the one arg open() is right out?


    our $FILE="d:/temp/the_dang_file.txt"; open FILE or die "$FILE:$!";


    Yves / DeMerphq
    This space for rent.

Re: Two-arg open() considered dangerous
by Anonymous Monk on Dec 13, 2001 at 01:09 UTC

    Dake Desu... cannot remember my pass, seeing as how I have not made a mental mnemoric for it yet, and I cannot check my email for it at school (Never write your passwords down).

    How 'bout 
    $filevar ~= s/>/&gt;/g;
    open FILE, "<mode>$filevar" or die "Could not open file: $!";

    If an end user decides to add those ">" to the variable, and be generally evil, it will blow up in their face...

    Also adds some security for CGI, if your doing something like a forum ^_^.

    Ps: I will never get use to HTML in forums ^_^

      Two major points off for your comment:
      1. Replacing ">" doesn't address "|" or leading spaces.
      2. Re-inventing HTML::Entities -- poorly -- is stupid.

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        You left out the meta point-off for "don't write down your passwords; send them in clear text through email."

        Update: This appears to be my 100th post. w00t!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://131085]
Approved by root
[Discipulus]: who make the invitation? the program?!?
[choroba]: it's historical
[erix]: pull requests
[choroba]: originally, you sent a pull request to someone by email, i.e. you asked them to pull from your repo
[Discipulus]: if is the author of a patch, is more like a 'request to push' into rather than a pull request..
[choroba]: as it's considered unpolite to push to someone else's repo
[choroba]: and in fact, you don't push into the target repo, you push into your branch of your fork
[choroba]: the maintainer of the upstream repo than "merges" the pull request, i.e. they pull from your fork into the upstream
[Discipulus]: ' i.e. you asked them to pull from your repo' =~ I (subj) want to push
[Discipulus]: chorobayour words are reasonable

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2017-05-27 20:12 GMT
Find Nodes?
    Voting Booth?