New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safe reval bleeds local variable values #6735
Comments
From guy@albertelli.comCreated by guy@albertelli.comThe reval method of a Safe object bleeds the local variables into Example: Incorrectly prints: Rather than the correct: This occurs for all of the local variables in reval. I suggest modifying the reval Subroutine to be: sub reval { # Create anon sub ref in root of compartment. Perl Info
|
From ben.goldberg@hotpop.com"guy@albertelli.com (via RT)" wrote:
Not just those, but *all* lexicals that have been declared at that time. Including $default_root and $default_share. I can imagine someone
I don't think that changing the $evalsub variable from a lexical to a A correct solution would be to perform the eval at a point in time when I would suggest that we have near the beginning of package Safe, before sub _eval_no_lexicals_strict { use strict; eval shift } Then, later on, you'd have: my $evaler = $strict ? \&_eval_no_lexicals_strict : An even safer solution might be to get the code evaluated through perl's This could be done with something like: unshift @INC, sub { Alas, this would probably be too much overhead... Especially when putting -- |
From guy@albertelli.com
Dosen't seem to bleed default_root or default_share, and the bleed of Test script: foreach my $name ('default_root','default_share','expr','obj','strict','root','evalcode','evalsub') { 5.008001 5.008 5.006001 In theory I agree, but in practice it doesn't look to be an issue. (And what changed in 5.8.1 to make this "break" more?)
I understand why you say that, but it does succeed as $default_root,
I tried this, I doesn't seem to get it to work. I put the above subs in Safe.pm right about the default_root sub reval { # Create anon sub ref in root of compartment. return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub); With this test script: use strict; print("Test a is :".$safe->reval('$a=1;return $a;').":\n"); I get: 5.008001 I can't get it to generate any warning or errors.
I'll have to take your word for it. -- |
From @iabynOn Thu, Sep 04, 2003 at 01:32:57AM -0400, Guy Albertelli II wrote:
This is because 5.8.1 includes fixes that allow nested evals to still see As of 5.8.1, to code to be eval'ed will be able to see: * any lexical vars declared above it but within reval(); Having said that, I think Benjamin's suggestion of having an eval function Dave. -- |
From ben.goldberg@hotpop.com"guy@albertelli.com (via RT)" wrote:
Not just those, but *all* lexicals that have been declared at that time. Including $default_root and $default_share. I can imagine someone
I don't think that changing the $evalsub variable from a lexical to a A correct solution would be to perform the eval at a point in time when I would suggest that we have near the beginning of package Safe, before sub _eval_no_lexicals_strict { use strict; eval shift } Then, later on, you'd have: my $evaler = $strict ? \&_eval_no_lexicals_strict : An even safer solution might be to get the code evaluated through perl's This could be done with something like: unshift @INC, sub { Alas, this would probably be too much overhead... Especially when putting -- |
From guy@albertelli.com
Thanks, I hadn't noticed that change.
I agree completely, and in fact it was the first thing I tried. But I have been unable to get it to work at all. Once I implement the suggested change all reval's silently fail, and I -- |
From guy@albertelli.com
Okay, so I think I know why it continues to fail. my $evalcode = sprintf('package %s; sub { @_ = (); eval $expr; }',$root); This line depends upon the fact that the $expr is in scope when we do The naive: with test code Throws errors: So I guess I am out of my depth. -- |
From @iabynOkay, here's a patch. When Safe code is eval'ed now, there are no So its secure, but ever so slightly untidy. The one remaining lexical is needed because a closure is used to pass the So Safe.pm used to do the rough equivalent of sub reval { sub { eval 'my $__ExPr__;' . $__ExPr__ }; Given that this ia security patch, other eyes may want to give it Dave. -- Inline Patch--- ext/Opcode/Safe.pm- Sun Sep 7 17:24:51 2003
+++ ext/Opcode/Safe.pm Sun Sep 7 18:58:44 2003
@@ -5,6 +5,26 @@
$Safe::VERSION = "2.09";
+# *** Don't declare any lexicals above this point ***
+#
+# This function should return a closure which contains an eval that can't
+# see any lexicals in scope (apart from __ExPr__ which is unavoidable)
+
+sub lexless_anon_sub {
+ # $_[0] is package;
+ # $_[1] is strict flag;
+ my $__ExPr__ = $_[2]; # must be a lexical to create the closure that
+ # can be used to pass the value into the safe
+ # world
+
+ # Create anon sub ref in root of compartment.
+ # Uses a closure (on $__ExPr__) to pass in the code to be executed.
+ # (eval on one line to keep line numbers as expected by caller)
+ eval sprintf
+ 'package %s; %s strict; sub { @_=(); eval q[my $__ExPr__;] . $__ExPr__; }',
+ $_[0], $_[1] ? 'use' : 'no';
+}
+
use Carp;
use Opcode 1.01, qw(
@@ -211,15 +231,7 @@
my ($obj, $expr, $strict) = @_;
my $root = $obj->{Root};
- # Create anon sub ref in root of compartment.
- # Uses a closure (on $expr) to pass in the code to be executed.
- # (eval on one line to keep line numbers as expected by caller)
- my $evalcode = sprintf('package %s; sub { @_ = (); eval $expr; }', $root);
- my $evalsub;
-
- if ($strict) { use strict; $evalsub = eval $evalcode; }
- else { no strict; $evalsub = eval $evalcode; }
-
+ my $evalsub = lexless_anon_sub($root,$strict, $expr);
return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub);
}
|
From @rgsDave Mitchell wrote:
Thanks, applied as #21063. (I also incremented Safe's VERSION.) |
@rgs - Status changed from 'new' to 'resolved' |
From mjtg@cam.ac.ukDave Mitchell <davem@fdgroup.com> wrote
No need for an extra lexical - you've got the eval() and the sub {}
That should be written sub reval { (with of course error checking etc). Indeed, you only need do the eval() in the subroutine at the top of the code Mike Guy |
From @iabynOn Fri, Sep 12, 2003 at 03:47:31PM +0100, Mike Guy wrote:
No, because then the eval is executed outside the sandbox, eg reval(' BEGIN { system "rm -rf /" }' ); or reval( '1 } system "rm -rf /"; { 1' ); -- |
@iabyn - Status changed from 'open' to 'resolved' |
Migrated from rt.perl.org#23656 (status was 'resolved')
Searchable as RT23656$
The text was updated successfully, but these errors were encountered: