M
Matthew Braid
Hi all,
Not really a question, more of a pointer....
Now that RE's can contain executable code (via the experimental (?{...}) and a
few others) it is no longer safe to accept an RE as an argument (either to a
program or to a subroutine), since it could, for instance, have:
(?{system("rm -rf /")})
buried in it.
"no re 'eval'" is supposed to stop this, as it disallows use of these constructs
in an RE using variable interpolation at run-time, ie this:
no re 'eval';
chomp(my $chk = <STDIN>);
chomp(my $re = <STDIN>);
print "OK!\n" if eval { $chk =~ $re };
will result in (if the STDIN is "123\n(?{print "UHOH!\n"})123\n"):
Eval-group not allowed at runtime, use re 'eval' in regex m/(?{print
"UHOH!\n"})123/ at test.pl line 4, <STDIN> line 2.
This is good, as long as the data stays raw like that.
Unfortunately, no re 'eval' allows a backdoor - if the re variable was created
with qr//, all is deemed good.
In a contrived example:
no re 'eval';
chomp(my $chk = <STDIN>);
chomp(my $re = <STDIN>);
{
use re 'eval';
$re = qr/$re/;
}
test($chk, $re);
sub test {
my ($chk, $re) = @_;
no re 'eval';
print "OK!\n" if $chk =~ $re;
}
results in (with the same input as before):
UHOH!
OK!
Now while this can't happen in raw data from outside the program (because it
can't be qr'd by the external person), it does mean any subroutine that accepts
an RE as an argument can't rely on no re 'eval' as the supplied RE might have
been created using qr// in a block that had had use re 'eval' turned on.
The only way around this I have found is to use stringy eval and a dummy
variable. To use the test program again:
no re 'eval';
chomp(my $chk = <STDIN>);
chomp(my $re = <STDIN>);
{
use re 'eval';
$re = qr/$re/;
}
test($chk, $re);
sub test {
my ($chk, $re) = @_;
no re 'eval';
my $null = ''; # DUMMY VARIABLE
print "OK!\n" if eval "\$chk =~ /\${null}$re/";
print "ERROR IS $@\n";
}
With the same input as before this results in:
ERROR IS Eval-group not allowed at runtime, use re 'eval' in regex
m/(?-xism
?{print "UHOH!\n"})123)/ at (eval 2) line 1, <STDIN> line 2.
This is because of the $null variable - it hasn't been made by qr//, so it
triggers the no re 'eval' for you (its in the ${null} form because $re, which is
interpolated, may start with an alphanumeric and cause an unrelated error). no
re 'eval' was also included in the test sub so someone can't just use re 'eval'
before the sub is called.
It has to be a stringy eval because the no re 'eval' check is done at compile
time rather than run time (despite what the error message says....).
Its a very ugly kludge, but as I said its the only thing I've ever got to work
in a secure fashion. It would be fantastic if there was a pragma like no re
'eval_strict' or something that would stop embedded code entirely - I have
never, ever seen a need for it in everyday use.
MB
Not really a question, more of a pointer....
Now that RE's can contain executable code (via the experimental (?{...}) and a
few others) it is no longer safe to accept an RE as an argument (either to a
program or to a subroutine), since it could, for instance, have:
(?{system("rm -rf /")})
buried in it.
"no re 'eval'" is supposed to stop this, as it disallows use of these constructs
in an RE using variable interpolation at run-time, ie this:
no re 'eval';
chomp(my $chk = <STDIN>);
chomp(my $re = <STDIN>);
print "OK!\n" if eval { $chk =~ $re };
will result in (if the STDIN is "123\n(?{print "UHOH!\n"})123\n"):
Eval-group not allowed at runtime, use re 'eval' in regex m/(?{print
"UHOH!\n"})123/ at test.pl line 4, <STDIN> line 2.
This is good, as long as the data stays raw like that.
Unfortunately, no re 'eval' allows a backdoor - if the re variable was created
with qr//, all is deemed good.
In a contrived example:
no re 'eval';
chomp(my $chk = <STDIN>);
chomp(my $re = <STDIN>);
{
use re 'eval';
$re = qr/$re/;
}
test($chk, $re);
sub test {
my ($chk, $re) = @_;
no re 'eval';
print "OK!\n" if $chk =~ $re;
}
results in (with the same input as before):
UHOH!
OK!
Now while this can't happen in raw data from outside the program (because it
can't be qr'd by the external person), it does mean any subroutine that accepts
an RE as an argument can't rely on no re 'eval' as the supplied RE might have
been created using qr// in a block that had had use re 'eval' turned on.
The only way around this I have found is to use stringy eval and a dummy
variable. To use the test program again:
no re 'eval';
chomp(my $chk = <STDIN>);
chomp(my $re = <STDIN>);
{
use re 'eval';
$re = qr/$re/;
}
test($chk, $re);
sub test {
my ($chk, $re) = @_;
no re 'eval';
my $null = ''; # DUMMY VARIABLE
print "OK!\n" if eval "\$chk =~ /\${null}$re/";
print "ERROR IS $@\n";
}
With the same input as before this results in:
ERROR IS Eval-group not allowed at runtime, use re 'eval' in regex
m/(?-xism
This is because of the $null variable - it hasn't been made by qr//, so it
triggers the no re 'eval' for you (its in the ${null} form because $re, which is
interpolated, may start with an alphanumeric and cause an unrelated error). no
re 'eval' was also included in the test sub so someone can't just use re 'eval'
before the sub is called.
It has to be a stringy eval because the no re 'eval' check is done at compile
time rather than run time (despite what the error message says....).
Its a very ugly kludge, but as I said its the only thing I've ever got to work
in a secure fashion. It would be fantastic if there was a pragma like no re
'eval_strict' or something that would stop embedded code entirely - I have
never, ever seen a need for it in everyday use.
MB