in reply to safe method to execute perl code with user input?

You can interpolate regexes into substitutions just fine without having to fear code execution.

$string =~ s/$regex/$replacement/g;

will interpret $regex as a regex, which can be user input, and $replacement as a string. Note that this way $1, $2 is not available in the replacement.

There is a risk though: it is possible to craft a regex that takes ridiculous amounts of time to match against a string of moderate length. So if you plan to run this on a web server where people can enter aribrary regexes, don't do that.

However, my code editor (Smultron) does global subs using perl regex without any limitations of the expression input that I have yet discovered, so it would seem that there must be a safe way to do this.

The author of your code editor probably assumed correctly that if you are already running an editor on your machine, you wouldn't need to use a regex to slow down the computer - you could just launch another program which does that job for you.

Or formulated differently, if you try to hurt somebody by putting an "evil" regex into the search box, you'll only hurt yourself.

Note that Safe is a core module that is designed to safely execute foreign perl code, but is considered insecure by its authors, and doesn't offer any protection against slow regexes either.

Replies are listed 'Best First'.
Re^2: safe method to execute perl code with user input?
by Allasso (Monk) on Jun 21, 2011 at 14:05 UTC
    Note that this way $1, $2 is not available in the replacement.
    Yes, I know, that's the hitch... :-(
    The author of your code editor probably assumed correctly...
    Or formulated differently, if you try to hurt somebody by putting an "evil" regex into the search box, you'll only hurt yourself.
    Are you suggesting that it is possible for me to put destructive code (if even by mistake) in the box and reap the results?

    BTW, I Doubt it will ever be public.
      Are you suggesting that it is possible for me to put destructive code (if even by mistake) in the box and reap the results?

      It is very likely that it's possible to enter a regex that will make the editor (or at least the thread in the editor that does the search) hang. Just try the regex from the blog post I linked to, with the same test data as the blog post uses.

      But it is unlikely that you can execute arbitrary code from the search/substitution box, unless the author of the editor screwed it up.

      Maybe you can just run the substitution and limit it by time and/or number of replacements?
      Here's a quick'n dirty example:

      use strict; use warnings; { my $count; my $timeout; sub set_count { $count = shift; } sub set_timeout { $timeout = $_[0] ? time() + $_[0] : 0; } sub limited_subst { my ($from, $replacement) = @_; die "Too many replacements!" unless $count--; die "Time is up!" if $timeout and time() > $timeout; sleep(1); # just for demonstration! # warn "Replacing $from -> $replacement\n"; return $replacement; } } sub test_replace { my ($string, $from, $replacement, $limit, $timeout_epoch) = @_; my $rollback = $string; set_count( $limit ); set_timeout( $timeout_epoch ); eval { $string =~ s/ ($from) / limited_subst($1, $replacement ) /gxe; }; if ($@) { print "Oops! $@"; $string = $rollback; } return $string; } my $string = "la " x 30; print "Checking with no real limit:\n"; print "in : $string\nout: ", test_replace($string, 'la', 'ho!', -1, 0) +, "\n\n"; print "Checking with subst_limit 3:\n"; print "in : $string\nout: ", test_replace($string, 'la', 'ho!', 3, 0) +, "\n\n"; print "Checking with timeout 3:\n"; print "in : $string\nout :", test_replace($string, 'la', 'ho!', 30000, + 3), "\n\n"; __END__ Output: Checking with no real limit: in : la la la la la la la la la la la la la la la la la la la la la la + la la la la la la la la out: ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! h +o! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! ho! Checking with subst_limit 3: Oops! Too many replacements! at 910736.pl line 15. in : la la la la la la la la la la la la la la la la la la la la la la + la la la la la la la la out: la la la la la la la la la la la la la la la la la la la la la la + la la la la la la la la Checking with timeout 3: Oops! Time is up! at 910736.pl line 16. in : la la la la la la la la la la la la la la la la la la la la la la + la la la la la la la la out :la la la la la la la la la la la la la la la la la la la la la la + la la la la la la la la
      Another idea: Maybe, you can start a sub-process that operates in a limited shell?
      Important: I didn't scrutinized this for security holes!