http://www.perlmonks.org?node_id=549355


in reply to Re^3: Small examples of string eval
in thread Small examples of string eval

These discussion typically start with "only I run the script", and that's just a lack of imagination. You know better than that. And, it's not just a script you're running. You're telling the world it's a good idea to follow your example. You know that's not the right thing to do, and you know it's hazardous.

The expression code is easily handled by Math::Expression (on CPAN), like everything else you want to do. This is what I use when I need this, although I had to modify the source to add ** as an operator (but that's really easy and I'm sure you'll figure it out as easily as you could have found this module, but I'll include the patch for everyone else).

#!/usr/bin/perl use Math::Expression; my $expr = Math::Expression->new; my $tree = $expr->Parse( "8*1024**3" ); my $answer = $expr->EvalTree( $tree, 0 ); print "My answer is $answer\n";

And, as you know, security is subverted by a combination of factors. You know that you've taken a shortcut and you know what the problem is. If someone can coerce your code to running as your userid (perhaps through changing the file mode, or even just changing a shell script that uses this script), they have their in. Again, as you know, security happens in layers and you do what you can to prevent unintended uses. You know that your eval shortcut can do a lot more than you want, and you also don't care to make the easy (and re-usable) fix. That's why some people have to be paranoid. :)

58,59c58,59 < my $HighestOperPrec = 15; < my $PrecTerminal = 16; # Precedence of terminal (or l +ist) - ie operand --- > my $HighestOperPrec = 14; > my $PrecTerminal = 15; # Precedence of terminal (or l +ist) - ie operand 61,65c61,64 < '(' => [17, 17], < 'var' => [16, 16], < 'const' => [16, 16], < 'func' => [16, 16], < '**'=> [15, 15], --- > '(' => [16, 16], > 'var' => [15, 15], > 'const' => [15, 15], > 'func' => [15, 15], 170c169 < --- > 180c179 < elsif($expr =~ s@^(:=|>=|<=|==|<>|!=|&&|\|\||lt|gt|le| +ge|eq|ne|\ *{2}|[-./*%+,<>\?:\(\);])@@) { --- > elsif($expr =~ s@^(:=|>=|<=|==|<>|!=|&&|\|\||lt|gt|le| +ge|eq|ne|[ -./*%+,<>\?:\(\);])@@) { 480d478 < return $left ** $right if($oper eq '**');

Maybe you don't want to use a module, though, and that's fine. That's a better reason than "that will never happen". There are all sorts of other things you can do to harden your code, but you have to want to do that. At the very least, turn on taint checking and scrub the input.

--
brian d foy <brian@stonehenge.com>
Subscribe to The Perl Review