summaryrefslogtreecommitdiff
path: root/t/041SafeEval.t
diff options
context:
space:
mode:
Diffstat (limited to 't/041SafeEval.t')
-rw-r--r--t/041SafeEval.t191
1 files changed, 191 insertions, 0 deletions
diff --git a/t/041SafeEval.t b/t/041SafeEval.t
new file mode 100644
index 0000000..41dc313
--- /dev/null
+++ b/t/041SafeEval.t
@@ -0,0 +1,191 @@
+########################################################################
+# Test Suite for Log::Log4perl::Config (Safe compartment functionality)
+# James FitzGibbon, 2003 (james.fitzgibbon@target.com)
+# Mike Schilli, 2003 (log4perl@perlmeister.com)
+########################################################################
+
+BEGIN {
+ if($ENV{INTERNAL_DEBUG}) {
+ require Log::Log4perl::InternalDebug;
+ Log::Log4perl::InternalDebug->enable();
+ }
+}
+
+use Test;
+BEGIN { plan tests => 23 };
+
+use Log::Log4perl;
+
+ok(1); # If we made it this far, we're ok.
+
+my $example_log = "example" . (stat($0))[9] . ".log";
+unlink($example_log);
+
+Log::Log4perl::Config->vars_shared_with_safe_compartment(
+ main => [ '$0' ],
+);
+
+# test that unrestricted code works properly
+Log::Log4perl::Config::allow_code(1);
+my $config = <<'END';
+ log4perl.logger = INFO, Main
+ log4perl.appender.Main = Log::Log4perl::Appender::File
+ log4perl.appender.Main.filename = sub { "example" . (stat($0))[9] . ".log" }
+ log4perl.appender.Main.layout = Log::Log4perl::Layout::SimpleLayout
+END
+eval { Log::Log4perl->init( \$config ) };
+my $failed = $@ ? 1 : 0;
+ok($failed, 0, 'config file with code initializes successfully');
+
+# test that disallowing code works properly
+Log::Log4perl::Config->allow_code(0);
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 1, 'config file with code fails if ALLOW_CODE_IN_CONFIG_FILE is false');
+
+# test that providing an explicit mask causes illegal code to fail
+Log::Log4perl::Config->allow_code(1);
+Log::Log4perl::Config->allowed_code_ops(':default');
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 1, 'config file with code fails if ALLOW_CODE_IN_CONFIG_FILE is true and an explicit mask is set');
+
+# test that providing an restrictive convenience mask causes illegal code to fail
+Log::Log4perl::Config::allow_code('restrictive');
+undef @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 1, 'config file with code fails if ALLOW_CODE_IN_CONFIG_FILE is true and a restrictive convenience mask is set');
+
+# test that providing an restrictive convenience mask causes illegal code to fail
+Log::Log4perl::Config->allow_code('safe');
+undef @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 0, 'config file with code succeeds if ALLOW_CODE_IN_CONFIG_FILE is true and a safe convenience mask is set');
+
+##################################################
+# Test allowed_code_ops_convenience_map accessors
+###################################################
+
+# get entire map as hashref
+my $map = Log::Log4perl::Config->allowed_code_ops_convenience_map();
+ok(ref $map, 'HASH', 'entire map is returned as a hashref');
+my $numkeys = keys %{ $map };
+
+# get entire map as hash
+my %map = Log::Log4perl::Config->allowed_code_ops_convenience_map();
+ok(keys %map, $numkeys, 'entire map returned as hash has same number of keys as hashref');
+
+# replace entire map
+Log::Log4perl::Config->allowed_code_ops_convenience_map( {} );
+ok(keys %{ Log::Log4perl::Config->allowed_code_ops_convenience_map() }, 0,
+ 'can replace entire map with an empty one');
+Log::Log4perl::Config->allowed_code_ops_convenience_map( \%map );
+ok(keys %{ Log::Log4perl::Config->allowed_code_ops_convenience_map() }, $numkeys,
+ 'can replace entire map with an populated one');
+
+# Add a new name/mask to the map
+Log::Log4perl::Config->allowed_code_ops_convenience_map( foo => [ ':default' ] );
+ok( keys %{ Log::Log4perl::Config->allowed_code_ops_convenience_map() },
+ $numkeys + 1, 'can add a new name/mask to the map');
+
+# get the mask we just added back
+my $mask = Log::Log4perl::Config->allowed_code_ops_convenience_map( 'foo' );
+ok( $mask->[0], ':default', 'can retrieve a single mask');
+
+###################################################
+# Test vars_shared_with_safe_compartment accessors
+###################################################
+
+# get entire varlist as hashref
+$map = Log::Log4perl::Config->vars_shared_with_safe_compartment();
+ok(ref $map, 'HASH', 'entire map is returned as a hashref');
+$numkeys = keys %{ $map };
+
+# get entire map as hash
+%map = Log::Log4perl::Config->vars_shared_with_safe_compartment();
+ok(keys %map, $numkeys, 'entire map returned as hash has same number of keys as hashref');
+
+# replace entire map
+Log::Log4perl::Config->vars_shared_with_safe_compartment( {} );
+ok(keys %{ Log::Log4perl::Config->vars_shared_with_safe_compartment() }, 0,
+ 'can replace entire map with an empty one');
+Log::Log4perl::Config->vars_shared_with_safe_compartment( \%map );
+ok(keys %{ Log::Log4perl::Config->vars_shared_with_safe_compartment() }, $numkeys,
+ 'can replace entire map with an populated one');
+
+# Add a new name/mask to the map
+$Foo::foo = 1;
+@Foo::bar = ( 1, 2, 3 );
+push @Foo::bar, $Foo::foo; # Some nonsense to avoid 'used only once' warning
+Log::Log4perl::Config->vars_shared_with_safe_compartment( Foo => [ '$foo', '@bar' ] );
+ok( keys %{ Log::Log4perl::Config->vars_shared_with_safe_compartment() },
+ $numkeys + 1, 'can add a new name/mask to the map');
+
+# get the varlist we just added back
+my $varlist = Log::Log4perl::Config->vars_shared_with_safe_compartment( 'Foo' );
+ok( $varlist->[0], '$foo', 'can retrieve a single varlist');
+ok( $varlist->[1], '@bar', 'can retrieve a single varlist');
+
+
+############################################
+# Now the some tests with restricted cspecs
+############################################
+
+# Global cspec with illegal code
+$config = <<'END';
+ log4perl.logger = INFO, Main
+ #'U' a global user-defined cspec
+ log4j.PatternLayout.cspec.U = sub { unlink 'quackquack'; }
+ log4perl.appender.Main = Log::Log4perl::Appender::Screen
+ log4perl.appender.Main.layout = Log::Log4perl::Layout::SimpleLayout
+END
+Log::Log4perl::Config::allow_code('restrictive');
+undef @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 1,
+ 'global cspec with harmful code rejected on restrictive setting');
+
+# Global cspec with legal code
+$config = <<'END';
+ log4perl.logger = INFO, Main
+ #'U' a global user-defined cspec
+ log4j.PatternLayout.cspec.U = sub { 1; }
+ log4perl.appender.Main = Log::Log4perl::Appender::Screen
+ log4perl.appender.Main.layout = Log::Log4perl::Layout::SimpleLayout
+END
+Log::Log4perl::Config->allow_code('restrictive');
+undef @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 0, 'global cspec with legal code allowed on restrictive setting');
+
+# Local cspec with illegal code
+$config = <<'END';
+ log4perl.logger = INFO, Main
+ log4perl.appender.Main = Log::Log4perl::Appender::Screen
+ log4perl.appender.Main.layout = Log::Log4perl::Layout::PatternLayout
+ log4perl.appender.Main.layout.cspec.K = sub { symlink("a", "b"); }
+END
+Log::Log4perl::Config::allow_code('restrictive');
+undef @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 1, 'local cspec with harmful code rejected on restrictive setting');
+
+# Global cspec with legal code
+$config = <<'END';
+ log4perl.logger = INFO, Main
+ log4perl.appender.Main = Log::Log4perl::Appender::Screen
+ log4perl.appender.Main.layout = Log::Log4perl::Layout::PatternLayout
+ log4perl.appender.Main.layout.cspec.K = sub { return sprintf "%1x", $$}
+END
+Log::Log4perl::Config::allow_code('restrictive');
+undef @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
+eval { Log::Log4perl->init( \$config ) };
+$failed = $@ ? 1 : 0;
+ok($failed, 0, 'local cspec with legal code allowed on restrictive setting');
+
+unlink($example_log);