|
1 | 1 |
|
2 | 2 |
|
3 |
| -# $PostgreSQL: pgsql/src/pl/plperl/plc_safe_ok.pl,v 1.4 2010/02/12 19:35:25 adunstan Exp $ |
| 3 | +# $PostgreSQL: pgsql/src/pl/plperl/plc_safe_ok.pl,v 1.5 2010/02/16 21:39:52 adunstan Exp $ |
4 | 4 |
|
| 5 | +package PostgreSQL::InServer::safe; |
| 6 | + |
5 | 7 | use strict;
|
6 |
| -use vars qw($PLContainer); |
| 8 | +use warnings; |
| 9 | +use Safe; |
| 10 | + |
| 11 | +# @EvalInSafe = ( [ "string to eval", "extra,opcodes,to,allow" ], ...) |
| 12 | +# @ShareIntoSafe = ( [ from_class => \@symbols ], ...) |
| 13 | + |
| 14 | +# these are currently declared "my" so they can't be monkeyed with using init |
| 15 | +# code. If we later decide to change that policy, we could change one or more |
| 16 | +# to make them visible by using "use vars". |
| 17 | +my($PLContainer,$SafeClass,@EvalInSafe,@ShareIntoSafe); |
| 18 | + |
| 19 | +# --- configuration --- |
| 20 | + |
| 21 | +# ensure we only alter the configuration variables once to avoid any |
| 22 | +# problems if this code is run multiple times due to an exception generated |
| 23 | +# from plperl.on_trusted_init code leaving the interp_state unchanged. |
| 24 | + |
| 25 | +if (not our $_init++) { |
| 26 | + |
| 27 | + # Load widely useful pragmas into the container to make them available. |
| 28 | + # These must be trusted to not expose a way to execute a string eval |
| 29 | + # or any kind of unsafe action that the untrusted code could exploit. |
| 30 | + # If in ANY doubt about a module then DO NOT add it to this list. |
| 31 | + |
| 32 | + unshift @EvalInSafe, |
| 33 | + [ 'require strict', 'caller' ], |
| 34 | + [ 'require Carp', 'caller,entertry' ], # load Carp before warnings |
| 35 | + [ 'require warnings', 'caller' ]; |
| 36 | + push @EvalInSafe, |
| 37 | + [ 'require feature' ] if $] >= 5.010000; |
| 38 | + |
| 39 | + push @ShareIntoSafe, [ |
| 40 | + main => [ qw( |
| 41 | + &elog &DEBUG &LOG &INFO &NOTICE &WARNING &ERROR |
| 42 | + &spi_query &spi_fetchrow &spi_cursor_close &spi_exec_query |
| 43 | + &spi_prepare &spi_exec_prepared &spi_query_prepared &spi_freeplan |
| 44 | + &return_next &_SHARED |
| 45 | + "e_literal "e_nullable "e_ident |
| 46 | + &encode_bytea &decode_bytea &looks_like_number |
| 47 | + &encode_array_literal &encode_array_constructor |
| 48 | + ) ], |
| 49 | + ]; |
| 50 | +} |
| 51 | + |
| 52 | +# --- create and initialize a new container --- |
| 53 | + |
| 54 | +$SafeClass ||= 'Safe'; |
| 55 | +$PLContainer = $SafeClass->new('PostgreSQL::InServer::safe_container'); |
7 | 56 |
|
8 |
| -$PLContainer = new Safe('PLPerl'); |
9 | 57 | $PLContainer->permit_only(':default');
|
10 | 58 | $PLContainer->permit(qw[:base_math !:base_io sort time require]);
|
11 | 59 |
|
12 |
| -$PLContainer->share(qw[&elog &return_next |
13 |
| - &spi_query &spi_fetchrow &spi_cursor_close &spi_exec_query |
14 |
| - &spi_prepare &spi_exec_prepared &spi_query_prepared &spi_freeplan |
15 |
| - &DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED |
16 |
| - "e_literal "e_nullable "e_ident |
17 |
| - &encode_bytea &decode_bytea |
18 |
| - &encode_array_literal &encode_array_constructor |
19 |
| - &looks_like_number |
20 |
| -]); |
21 |
| - |
22 |
| -# Load widely useful pragmas into the container to make them available. |
23 |
| -# (Temporarily enable caller here as work around for bug in perl 5.10, |
24 |
| -# which changed the way its Safe.pm works. It is quite safe, as caller is |
25 |
| -# informational only.) |
26 |
| -$PLContainer->permit(qw[caller]); |
27 |
| -::safe_eval(q{ |
28 |
| - require strict; |
29 |
| - require feature if $] >= 5.010000; |
30 |
| - 1; |
31 |
| -}) or die $@; |
32 |
| -$PLContainer->deny(qw[caller]); |
33 |
| - |
34 |
| -# called directly for plperl.on_plperl_init |
35 |
| -sub ::safe_eval { |
| 60 | +for my $do (@EvalInSafe) { |
| 61 | + my $perform = sub { # private closure |
| 62 | + my ($container, $src, $ops) = @_; |
| 63 | + my $mask = $container->mask; |
| 64 | + $container->permit(split /\s*,\s*/, $ops); |
| 65 | + my $ok = safe_eval("$src; 1"); |
| 66 | + $container->mask($mask); |
| 67 | + main::elog(main::ERROR(), "$src failed: $@") unless $ok; |
| 68 | + }; |
| 69 | + |
| 70 | + my $ops = $do->[1] || ''; |
| 71 | + # For old perls we add entereval if entertry is listed |
| 72 | + # due to http://rt.perl.org/rt3/Ticket/Display.html?id=70970 |
| 73 | + # Testing with a recent perl (>=5.11.4) ensures this doesn't |
| 74 | + # allow any use of actual entereval (eval "...") opcodes. |
| 75 | + $ops = "entereval,$ops" |
| 76 | + if $] < 5.011004 and $ops =~ /\bentertry\b/; |
| 77 | + |
| 78 | + $perform->($PLContainer, $do->[0], $ops); |
| 79 | +} |
| 80 | + |
| 81 | +$PLContainer->share_from(@$_) for @ShareIntoSafe; |
| 82 | + |
| 83 | + |
| 84 | +# --- runtime interface --- |
| 85 | + |
| 86 | +# called directly for plperl.on_trusted_init and @EvalInSafe |
| 87 | +sub safe_eval { |
36 | 88 | my $ret = $PLContainer->reval(shift);
|
37 | 89 | $@ =~ s/\(eval \d+\) //g if $@;
|
38 | 90 | return $ret;
|
39 | 91 | }
|
40 | 92 |
|
41 |
| -sub ::mksafefunc { |
42 |
| - return ::safe_eval(::mkfuncsrc(@_)); |
| 93 | +sub mksafefunc { |
| 94 | +! return safe_eval(PostgreSQL::InServer::mkfuncsrc(@_)); |
43 | 95 | }
|
0 commit comments