[PATCH] untrusted plperl
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
(well, change the name in the To: line :)
Hope someone finds that useful and maybe even merged :)
-alex
Attachments:
plperlu.difftext/plain; charset=US-ASCII; name=plperlu.diffDownload
Index: bin/scripts/createlang.sh
===================================================================
RCS file: /cvs/pgsql/pgsql/src/bin/scripts/createlang.sh,v
retrieving revision 1.27
retrieving revision 1.27.1000.1
diff --unified -r1.27 -r1.27.1000.1
--- bin/scripts/createlang.sh 2001/05/24 00:13:13 1.27
+++ bin/scripts/createlang.sh 2001/06/16 23:44:31 1.27.1000.1
@@ -207,6 +207,12 @@
plperl)
lancomp="PL/Perl"
trusted="TRUSTED "
+ handler="plperl_call_handler"
+ object="plperl"
+ ;;
+ plperlu)
+ lancomp="PL/Perl (untrusted)"
+ trusted=""
handler="plperl_call_handler"
object="plperl"
;;
Index: pl/plperl/Makefile.PL
===================================================================
RCS file: /cvs/pgsql/pgsql/src/pl/plperl/Makefile.PL,v
retrieving revision 1.12
diff --unified -r1.12 Makefile.PL
--- pl/plperl/Makefile.PL 2000/06/10 18:02:12 1.12
+++ pl/plperl/Makefile.PL 2001/06/16 23:46:25
@@ -29,33 +29,8 @@
exit(0);
}
-
-#
-# get the location of the Opcode module
-#
-my $opcode = '';
-{
-
- $modname = 'Opcode';
-
- my $dir;
- foreach (@INC) {
- if (-d "$_/auto/$modname") {
- $dir = "$_/auto/$modname";
- last;
- }
- }
-
- if (defined $dir) {
- $opcode = DynaLoader::dl_findfile("-L$dir", $modname);
- }
-
-}
-
-my $perllib = "-L$Config{archlibexp}/CORE -lperl";
-
WriteMakefile( 'NAME' => 'plperl',
- dynamic_lib => { 'OTHERLDFLAGS' => "$opcode $perllib" } ,
+ dynamic_lib => { 'OTHERLDFLAGS' => ldopts() } ,
INC => "$ENV{EXTRA_INCLUDES}",
XS => { 'SPI.xs' => 'SPI.c' },
OBJECT => 'plperl.o eloglvl.o SPI.o',
Index: pl/plperl/plperl.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/pl/plperl/plperl.c,v
retrieving revision 1.21
retrieving revision 1.21.1000.1
diff --unified -r1.21 -r1.21.1000.1
--- pl/plperl/plperl.c 2001/06/09 02:19:07 1.21
+++ pl/plperl/plperl.c 2001/06/16 23:18:04 1.21.1000.1
@@ -95,6 +95,7 @@
Oid arg_out_elem[FUNC_MAX_ARGS];
int arg_out_len[FUNC_MAX_ARGS];
int arg_is_rel[FUNC_MAX_ARGS];
+ bool lanpltrusted;
SV *reference;
} plperl_proc_desc;
@@ -121,7 +122,7 @@
static int plperl_firstcall = 1;
static int plperl_call_level = 0;
static int plperl_restart_in_progress = 0;
-static PerlInterpreter *plperl_safe_interp = NULL;
+static PerlInterpreter *plperl_interp = NULL;
static HV *plperl_proc_hash = NULL;
#if REALLYHAVEITONTHEBALL
@@ -133,7 +134,7 @@
* Forward declarations
**********************************************************************/
static void plperl_init_all(void);
-static void plperl_init_safe_interp(void);
+static void plperl_init_interp(void);
Datum plperl_call_handler(PG_FUNCTION_ARGS);
@@ -201,11 +202,11 @@
/************************************************************
* Destroy the existing safe interpreter
************************************************************/
- if (plperl_safe_interp != NULL)
+ if (plperl_interp != NULL)
{
- perl_destruct(plperl_safe_interp);
- perl_free(plperl_safe_interp);
- plperl_safe_interp = NULL;
+ perl_destruct(plperl_interp);
+ perl_free(plperl_interp);
+ plperl_interp = NULL;
}
/************************************************************
@@ -229,7 +230,7 @@
/************************************************************
* Now recreate a new safe interpreter
************************************************************/
- plperl_init_safe_interp();
+ plperl_init_interp();
plperl_firstcall = 0;
return;
@@ -237,32 +238,33 @@
/**********************************************************************
- * plperl_init_safe_interp() - Create the safe Perl interpreter
+ * plperl_init_interp() - Create the safe Perl interpreter
**********************************************************************/
static void
-plperl_init_safe_interp(void)
+plperl_init_interp(void)
{
char *embedding[3] = {
"", "-e",
/*
- * no commas between the next 4 please. They are supposed to be
+ * no commas between the next 5 please. They are supposed to be
* one string
*/
"require Safe; SPI::bootstrap();"
"sub ::mksafefunc { my $x = new Safe; $x->permit_only(':default');$x->permit(':base_math');"
"$x->share(qw[&elog &DEBUG &NOTICE &ERROR]);"
" return $x->reval(qq[sub { $_[0] }]); }"
+ "sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }"
};
- plperl_safe_interp = perl_alloc();
- if (!plperl_safe_interp)
- elog(ERROR, "plperl_init_safe_interp(): could not allocate perl interpreter");
-
- perl_construct(plperl_safe_interp);
- perl_parse(plperl_safe_interp, plperl_init_shared_libs, 3, embedding, NULL);
- perl_run(plperl_safe_interp);
+ plperl_interp = perl_alloc();
+ if (!plperl_interp)
+ elog(ERROR, "plperl_init_interp(): could not allocate perl interpreter");
+
+ perl_construct(plperl_interp);
+ perl_parse(plperl_interp, plperl_init_shared_libs, 3, embedding, NULL);
+ perl_run(plperl_interp);
@@ -336,7 +338,7 @@
**********************************************************************/
static
SV *
-plperl_create_sub(char *s)
+plperl_create_sub(char *s, bool trusted)
{
dSP;
@@ -348,7 +350,8 @@
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(s, 0)));
PUTBACK;
- count = perl_call_pv("mksafefunc", G_SCALAR | G_EVAL | G_KEEPERR);
+ count = perl_call_pv( (trusted?"mksafefunc":"mkunsafefunc"),
+ G_SCALAR | G_EVAL | G_KEEPERR);
SPAGAIN;
if (SvTRUE(ERRSV))
@@ -397,7 +400,7 @@
*
**********************************************************************/
-extern void boot_Opcode _((CV * cv));
+extern void boot_DynaLoader _((CV * cv));
extern void boot_SPI _((CV * cv));
static void
@@ -405,7 +408,7 @@
{
char *file = __FILE__;
- newXS("Opcode::bootstrap", boot_Opcode, file);
+ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
newXS("SPI::bootstrap", boot_SPI, file);
}
@@ -529,8 +532,10 @@
* Then we load the procedure into the safe interpreter.
************************************************************/
HeapTuple procTup;
+ HeapTuple langTup;
HeapTuple typeTup;
Form_pg_proc procStruct;
+ Form_pg_language langStruct;
Form_pg_type typeStruct;
char *proc_source;
@@ -541,6 +546,7 @@
prodesc->proname = malloc(strlen(internal_proname) + 1);
strcpy(prodesc->proname, internal_proname);
+
/************************************************************
* Lookup the pg_proc tuple by Oid
************************************************************/
@@ -557,6 +563,24 @@
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
/************************************************************
+ * Lookup the pg_language tuple by Oid
+ ************************************************************/
+ langTup = SearchSysCache(LANGOID,
+ ObjectIdGetDatum(procStruct->prolang),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(langTup))
+ {
+ free(prodesc->proname);
+ free(prodesc);
+ elog(ERROR, "plperl: cache lookup for language %u failed",
+ procStruct->prolang);
+ }
+ langStruct = (Form_pg_language) GETSTRUCT(langTup);
+
+ prodesc->lanpltrusted = langStruct->lanpltrusted;
+ ReleaseSysCache(langTup);
+
+ /************************************************************
* Get the required information for input conversion of the
* return value.
************************************************************/
@@ -634,7 +658,7 @@
/************************************************************
* Create the procedure in the interpreter
************************************************************/
- prodesc->reference = plperl_create_sub(proc_source);
+ prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);
pfree(proc_source);
if (!prodesc->reference)
{
Alex Pilosov <alex@pilosoft.com> writes:
Hope someone finds that useful and maybe even merged :)
It looks great to me (except you forgot the documentation updates ;)).
But it'd be nice to get a Perl expert to comment on the thing,
particularly on the safe/unsafe-in-one-interpreter business.
One thought that comes to mind: seems like it'd be possible to
communicate via Perl global variables, functions, etc between
safe and unsafe functions. This might be good, or it might be
a vehicle for bypassing the safety restrictions. We should
think hard about that.
regards, tom lane
On Sat, 16 Jun 2001, Tom Lane wrote:
Alex Pilosov <alex@pilosoft.com> writes:
Hope someone finds that useful and maybe even merged :)
It looks great to me (except you forgot the documentation updates ;)).
My bad! I'll find whereever plperl is mentioned and note plperlu
existance.
But it'd be nice to get a Perl expert to comment on the thing,
particularly on the safe/unsafe-in-one-interpreter business.
I'm no expert, and biased since I wrote it this way, but here's the
skinny:
1) safe functions has a unique namespace, and may not escape from it.
(or should not, if Safe module works right).
2) there were attacks on Safe module that resulted in ability to set
variables outside of your namespace. None known now.
3) There's an existing problem with AUTOLOAD and Safe, which doesn't apply
to us, since you can't 'use' a module in a Safe compartment.
To be truly paranoid, one must have separate interpreters, but that kills
the idea of sharing variables. (Actually, when PgSPI is done (see next
email), it would be possible to do so via SPI).
I'm awaiting opinion of a real perl expert, tho ;)
One thought that comes to mind: seems like it'd be possible to
communicate via Perl global variables, functions, etc between
safe and unsafe functions. This might be good, or it might be
a vehicle for bypassing the safety restrictions. We should
think hard about that.
Yeah. I thought about that. Thing is, you have to predeclare all variables
you want to share with safe functions. I think it would make sense to have
a global hash, named $safe_info (well, $main::safe_info) which would be
shared. Unfortunately, there's no way to have 'readonly' share, so
safe functions should not rely on $safe_info, as it could be corrupted by
unsafe functions...
-alex
Alex, seems you have done sufficient research to be sure this is OK.
Your patch has been added to the PostgreSQL unapplied patches list at:
http://candle.pha.pa.us/cgi-bin/pgpatches
I will try to apply it within the next 48 hours.
On Sat, 16 Jun 2001, Tom Lane wrote:
Alex Pilosov <alex@pilosoft.com> writes:
Hope someone finds that useful and maybe even merged :)
It looks great to me (except you forgot the documentation updates ;)).
My bad! I'll find whereever plperl is mentioned and note plperlu
existance.But it'd be nice to get a Perl expert to comment on the thing,
particularly on the safe/unsafe-in-one-interpreter business.I'm no expert, and biased since I wrote it this way, but here's the
skinny:1) safe functions has a unique namespace, and may not escape from it.
(or should not, if Safe module works right).2) there were attacks on Safe module that resulted in ability to set
variables outside of your namespace. None known now.3) There's an existing problem with AUTOLOAD and Safe, which doesn't apply
to us, since you can't 'use' a module in a Safe compartment.To be truly paranoid, one must have separate interpreters, but that kills
the idea of sharing variables. (Actually, when PgSPI is done (see next
email), it would be possible to do so via SPI).I'm awaiting opinion of a real perl expert, tho ;)
One thought that comes to mind: seems like it'd be possible to
communicate via Perl global variables, functions, etc between
safe and unsafe functions. This might be good, or it might be
a vehicle for bypassing the safety restrictions. We should
think hard about that.Yeah. I thought about that. Thing is, you have to predeclare all variables
you want to share with safe functions. I think it would make sense to have
a global hash, named $safe_info (well, $main::safe_info) which would be
shared. Unfortunately, there's no way to have 'readonly' share, so
safe functions should not rely on $safe_info, as it could be corrupted by
unsafe functions...-alex
---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Patch applied. Thanks. Waiting for doc updates.
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';(well, change the name in the To: line :)
Hope someone finds that useful and maybe even merged :)
-alex
Content-Description: plperlu.diff
[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026