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

Now, I know you should not just stick user input into an eval() where it could run as code:
my $x = <STDIN>; eval($x);
However, it seems to me that this is okay:
my $x = <STDIN>; eval{ (my $s = "blah blah") =~ /$x/ }
For the purpose of testing a regexp (otherwise, "hey[" will crash the process), since even if you try inputing

hey/; print "now look...";

This does not work as an exploit AFAICT. Am I wrong?

I'd kind of prefer, if you think it is not safe, a demonstration of how it is not, but all thoughts are welcome.

Replies are listed 'Best First'.
Re: eval() and security
by ikegami (Patriarch) on Nov 24, 2009 at 18:20 UTC
    my $x = <STDIN>; eval($x); <-- eval EXPR
    my $x = <STDIN>; eval{ (my $s = "blah blah") =~ /$x/ } <-- eval BLOCK
    Despite the similarity in names, those are very different functions. You're really comparing
    eval($x)
    with
    '' =~ /$x/

    The regex engine has checks in place to prevents the execution of Perl code in interpolated variables, so it's pretty safe. (use re 'eval'; removes the checks. no re 'eval'; adds them.)

    However, there is another class of problems you have to worry about. $x could contain a pattern that takes longer the life of the Universe to execute. This could be used to mount a denial of service attack.

      However, there is another class of problems you have to worry about. $x could contain a pattern that takes longer the life of the Universe to execute. This could be used to mount a denial of service attack.

      Okay, thanks much ikegami.
Re: eval() and security
by almut (Canon) on Nov 24, 2009 at 19:25 UTC
    $ perl -e 'print q{(}x20000' | perl -e 'my $x=<STDIN>; eval{q{bla} =~ +/$x/}' Segmentation fault

    ("works" with 5.8.4, 5.8.8, 5.10.0, 5.10.1, on Linux)

    Sure, a segfault isn't necessarily an exploit in itself, but skilled crackers can sometimes turn it into one, depending on the execution context of the program... In other words, although you could easily take care of this particular one by limiting the length of the input, I wouldn't feel all that sure someone determined couldn't come up with a shorter one.

Re: eval() and security
by SuicideJunkie (Vicar) on Nov 24, 2009 at 17:25 UTC
    Consider the case of $x = "(?{ code })"
    Where code is something of the flavor "unlink *.*"
      That ("unlink...") will not work from inside the /regexp/ which is the only place the $userinput will appear inside eval{}. I did test it, but I'm no expert on exploitation.

      Running in taint mode, the first version:
      eval($s);
      will throw an error, whereas the second does not (for what that is worth). The first form is the only one I can actually get code to execute in (via the input). Perhaps I am being a little paranoid suddenly.
        $ perl -e " $x = shift; /$x/" "(?{ die 666 })" Eval-group not allowed at runtime, use re 'eval' in regex m/(?{ die 66 +6 })/ at -e line 1. $ perl -Mre=eval -e " $x = shift; /$x/" "(?{ die 666 })" 666 at (re_eval 1) line 1. $ perl -Mre=eval -Te " $x = shift; /$x/" "(?{ die 666 })" Eval-group in insecure regular expression in regex m/(?{ die 666 })/ a +t -e line 1.

        I did not mean it as a literal runnable example, or I would have put it in code tags.

        The key point is that you can run arbitrary code (provided it parses) inside a regex match. If you allow user data into the regex match, then the sky is the limit for exploits. (As anonymonk shows above, Taint mode is smart enough to hate that sort of thing)

      Eval-group not allowed at runtime, use re 'eval'