pg.ddx.io pgsql-bugs@postgresql.org mailing list archive
help / color / mirror / Atom feedBug plperl.c
8+ messages / 2 participants
[nested] [flat]
Commits from this thread:
2022-02-25 4936747c47 638300fef5 ac910bb232 9b2d762a28 0f7b62f29d 31befa6be6 Disallow execution of SPI functions during plperl function compilation.
* Bug plperl.c
@ 2022-02-22 17:49 Mark Murawski <markm-lists@intellasoft.net>
0 siblings, 1 reply; 8+ messages in thread
From: Mark Murawski @ 2022-02-22 17:49 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org
Affects Versions: 12 (and probably all others)
Steps to Reproduce:
- Run a query during plperl validation -- ie: inside a warn handler
CREATE OR REPLACE FUNCTION foo() RETURNS text
LANGUAGE plperlu
AS $function$
use warnings;
use strict;
$SIG{'__WARN__'} = sub {
my $pid = main::spi_exec_query('SELECT
pg_backend_pid()')->{rows}[0]{pg_backend_pid};
};
my $foo;
my $foo; # <---- causes a warning
$function$
2022-02-22 12:17:04 EST - - - - 12950 - - 0 - LOG: server process
(PID 19702) was terminated by signal 11: Segmentation fault
#0 0x00007f32cfc33e65 in plperl_spi_exec (query=query@entry=0x55f7157b9290 "pg_backend_pid()", limit=limit@entry=0) at plperl.c:3184
#1 0x00007f32cfc36bbe in XS__spi_exec_query (my_perl=0x55f7157b7490, cv=<optimized out>) at SPI.xs:38
#2 0x00007f32cf9d85b1 in Perl_pp_entersub () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#3 0x00007f32cf9ce896 in Perl_runops_standard () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#4 0x00007f32cf943c85 in Perl_call_sv () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#5 0x00007f32cf9aff22 in ?? () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#6 0x00007f32cf9b0ce1 in Perl_vwarn () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#7 0x00007f32cf9b115f in Perl_warner () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#8 0x00007f32cf97df83 in Perl_pad_add_name_pvn () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#9 0x00007f32cf92582d in Perl_allocmy () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#10 0x00007f32cf96600b in Perl_yylex () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#11 0x00007f32cf978e80 in Perl_yyparse () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#12 0x00007f32cfa1240f in ?? () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#13 0x00007f32cfa1dbed in Perl_pp_entereval () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#14 0x00007f32cf9ce896 in Perl_runops_standard () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#15 0x00007f32cf943ea1 in Perl_call_sv () from /usr/lib/x86_64-linux-gnu/libperl.so.5.28
#16 0x00007f32cfc2dbf3 in plperl_create_sub (
s=s@entry=0x55f7158d7858 "\n\nuse strict;\nuse warnings;\n\nuse IntellaConfig { ProgramName =>
'PgLiveQueueCreateViews' };\nuse SimpleSPI;\nuse PostgresInfo;\nuse
UpgradeUtils;\n\nuse Data::Dumper;\nu se JSON;\n\nmy ($cmd) = $_[0] ||
'repla"..., fn_oid=fn_oid@entry=39623, prodesc=<optimized out>, prodesc=<optimized out>) at plperl.c:2135
#17 0x00007f32cfc2e5d5 in compile_plperl_function (fn_oid=fn_oid@entry=39623, is_trigger=is_trigger@entry=false, is_event_trigger=is_event_trigger@entry=false) at plperl.c:2989
#18 0x00007f32cfc33c98 in plperl_validator (fcinfo=<optimized out>) at plperl.c:2053
#19 0x000055f713965590 in FunctionCall1Coll (flinfo=0x7ffe96003c50, collation=<optimized out>, arg1=<optimized out>) at fmgr.c:1140
#20 0x000055f713965c4e in OidFunctionCall1Coll (functionId=functionId@entry=24589, collation=collation@entry=0, arg1=arg1@entry=39623) at fmgr.c:1418
#21 0x000055f7136228a5 in ProcedureCreate (procedureName=<optimized out>, procNamespace=procNamespace@entry=39605, replace=<optimized out>, returnsSet=returnsSet@entry=false,
returnType=returnType@entry=25, proowner=16385, languageObjectId=24590, languageValidator=24589,
prosrc=0x55f7157c1408 "\n\nuse strict;\nuse warnings;\n\nuse IntellaConfig { ProgramName =>
'PgLiveQueueCreateViews' };\nuse SimpleSPI;\nuse PostgresInfo;\nuse
UpgradeUtils;\n\nuse Data::Dumper;\nuse JSON;\n\nmy ($cmd) = $_[0] ||
'repla"..., probin=0x0, prokind=102 'f', security_definer=false, isLeakProof=false, isStrict=false, volatility=118 'v', parallel=117 'u', parameterTypes=0x55f7156f12d0,
allParameterTypes=0, parameterModes=0, parameterNames=94519704883840, parameterDefaults=0x0, trftypes=0, proconfig=0, prosupport=0, procost=procost@entry=100, prorows=prorows@entry=0)
at pg_proc.c:726
#22 0x000055f71369a3d0 in CreateFunction (pstate=pstate@entry=0x55f7156f0bf0, stmt=stmt@entry=0x55f7156d2e48) at functioncmds.c:1152
#23 0x000055f71384786e in ProcessUtilitySlow (pstate=pstate@entry=0x55f7156f0bf0, pstmt=pstmt@entry=0x55f7156d3188,
queryString=queryString@entry=0x7f32cfc3e048 "CREATE OR REPLACE FUNCTION live_queue.create_views(cmd text)\n RETURNS
text\n LANGUAGE plperlu\nAS $function$\n\nuse strict;\nuse
warnings;\n\nuse Intella Config { ProgramName =>
'PgLiveQueueCreateViews' };\nus"..., context=context@entry=PROCESS_UTILITY_TOPLEVEL, params=params@entry=0x0, queryEnv=queryEnv@entry=0x0, completionTag=0x7ffe96004620 "",
dest=0x55f7156d3268) at utility.c:1521
#24 0x000055f7138465d2 in standard_ProcessUtility (pstmt=0x55f7156d3188,
queryString=0x7f32cfc3e048 "CREATE OR REPLACE FUNCTION live_queue.create_views(cmd text)\n RETURNS
text\n LANGUAGE plperlu\nAS $function$\n\nuse strict;\nuse
warnings;\n\nuse IntellaConfig { ProgramNa --Type <RET> for more, q to
quit, c to continue without paging--
me => 'PgLiveQueueCreateViews' };\nus"..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x55f7156d3268, completionTag=0x7ffe96004620 "") at utility.c:927
#25 0x000055f7138449aa in PortalRunUtility (portal=portal@entry=0x55f7157666f0, pstmt=pstmt@entry=0x55f7156d3188, isTopLevel=isTopLevel@entry=true, setHoldSnapshot=setHoldSnapshot@entry=false, dest=0x55f7156d3268,
completionTag=0x7ffe96004620 "") at pquery.c:1171
#26 0x000055f713844af5 in PortalRunMulti (portal=portal@entry=0x55f7157666f0, isTopLevel=isTopLevel@entry=true, setHoldSnapshot=setHoldSnapshot@entry=false, dest=dest@entry=0x55f7156d3268,
altdest=altdest@entry=0x55f7156d3268, completionTag=completionTag@entry=0x7ffe96004620 "") at pquery.c:1327
#27 0x000055f713844fa1 in PortalRun (portal=portal@entry=0x55f7157666f0, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true, run_once=run_once@entry=true, dest=dest@entry=0x55f7156d3268,
altdest=altdest@entry=0x55f7156d3268, completionTag=0x7ffe96004620 "") at pquery.c:805
#28 0x000055f71384107d in exec_simple_query (
query_string=0x7f32cfc3e048 "CREATE OR REPLACE FUNCTION live_queue.create_views(cmd text)\n RETURNS
text\n LANGUAGE plperlu\nAS $function$\n\nuse strict;\nuse
warnings;\n\nuse IntellaConfig { ProgramName => 'PgLiveQueueCreateViews'
};\nus"...) at postgres.c:1215
#29 0x000055f7138429d1 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x55f715723a78, dbname=<optimized out>, username=<optimized out>) at postgres.c:4271
#30 0x000055f7137ce4d9 in BackendRun (port=0x55f715716ad0, port=0x55f715716ad0) at postmaster.c:4510
#31 BackendStartup (port=0x55f715716ad0) at postmaster.c:4193
#32 ServerLoop () at postmaster.c:1725
#33 0x000055f7137cf400 in PostmasterMain (argc=5, argv=0x55f7156cd030) at postmaster.c:1398
#34 0x000055f71355bcca in main (argc=5, argv=0x55f7156cd030) at main.c:228' Culprit: plperl_spi_exec(char *query, int limit)
....snip.... PG_TRY(); ...snip.... spi_rv = SPI_execute(query,
current_call_data->prodesc->fn_readonly, limit); Fix: bool read_only =
(current_call_data ? current_call_data->prodesc->fn_readonly : 0);
...snip... spi_rv = SPI_execute(query, read_only, limit); Attached patch
against 12.10
Attachments:
postgres-12.10-plperl-warn-handler-crash.patch (text/x-patch, 5.1K) download
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index f5738d0dc9..e4b7ce057f 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -3048,205 +3048,206 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc, bool include_generate
for (i = 0; i < tupdesc->natts; i++)
{
Datum attr;
bool isnull,
typisvarlena;
char *attname;
Oid typoutput;
Form_pg_attribute att = TupleDescAttr(tupdesc, i);
if (att->attisdropped)
continue;
if (att->attgenerated)
{
/* don't include unless requested */
if (!include_generated)
continue;
}
attname = NameStr(att->attname);
attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);
if (isnull)
{
/*
* Store (attname => undef) and move on. Note we can't use
* &PL_sv_undef here; see "AVs, HVs and undefined values" in
* perlguts for an explanation.
*/
hv_store_string(hv, attname, newSV(0));
continue;
}
if (type_is_rowtype(att->atttypid))
{
SV *sv = plperl_hash_from_datum(attr);
hv_store_string(hv, attname, sv);
}
else
{
SV *sv;
Oid funcid;
if (OidIsValid(get_base_element_type(att->atttypid)))
sv = plperl_ref_from_pg_array(attr, att->atttypid);
else if ((funcid = get_transform_fromsql(att->atttypid, current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, attr));
else
{
char *outputstr;
/* XXX should have a way to cache these lookups */
getTypeOutputInfo(att->atttypid, &typoutput, &typisvarlena);
outputstr = OidOutputFunctionCall(typoutput, attr);
sv = cstr2sv(outputstr);
pfree(outputstr);
}
hv_store_string(hv, attname, sv);
}
}
return newRV_noinc((SV *) hv);
}
static void
check_spi_usage_allowed(void)
{
/* see comment in plperl_fini() */
if (plperl_ending)
{
/* simple croak as we don't want to involve PostgreSQL code */
croak("SPI functions can not be used in END blocks");
}
}
HV *
plperl_spi_exec(char *query, int limit)
{
HV *ret_hv;
/*
* Execute the query inside a sub-transaction, so we can cope with errors
* sanely
*/
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
/* Want to run inside function's memory context */
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
int spi_rv;
+ /* current_call_data is not available during validation, */
+ bool read_only = (current_call_data ? current_call_data->prodesc->fn_readonly : 0);
pg_verifymbstr(query, strlen(query), false);
- spi_rv = SPI_execute(query, current_call_data->prodesc->fn_readonly,
- limit);
+ spi_rv = SPI_execute(query, read_only, limit);
ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
spi_rv);
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/* Punt the error to Perl */
croak_cstr(edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
return ret_hv;
}
static HV *
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed,
int status)
{
dTHX;
HV *result;
check_spi_usage_allowed();
result = newHV();
hv_store_string(result, "status",
cstr2sv(SPI_result_code_string(status)));
hv_store_string(result, "processed",
(processed > (uint64) UV_MAX) ?
newSVnv((NV) processed) :
newSVuv((UV) processed));
if (status > 0 && tuptable)
{
AV *rows;
SV *row;
uint64 i;
/* Prevent overflow in call to av_extend() */
if (processed > (uint64) AV_SIZE_MAX)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("query result has too many rows to fit in a Perl array")));
rows = newAV();
av_extend(rows, processed);
for (i = 0; i < processed; i++)
{
row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc, true);
av_push(rows, row);
}
hv_store_string(result, "rows",
newRV_noinc((SV *) rows));
}
SPI_freetuptable(tuptable);
return result;
}
/*
* plperl_return_next catches any error and converts it to a Perl error.
* We assume (perhaps without adequate justification) that we need not abort
* the current transaction if the Perl code traps the error.
*/
void
plperl_return_next(SV *sv)
{
MemoryContext oldcontext = CurrentMemoryContext;
PG_TRY();
{
plperl_return_next_internal(sv);
}
PG_CATCH();
{
ErrorData *edata;
/* Must reset elog.c's state */
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-02-22 19:48 Tom Lane <tgl@sss.pgh.pa.us>
parent: Mark Murawski <markm-lists@intellasoft.net>
0 siblings, 1 reply; 8+ messages in thread
From: Tom Lane @ 2022-02-22 19:48 UTC (permalink / raw)
To: Mark Murawski <markm-lists@intellasoft.net>; +Cc: pgsql-bugs@lists.postgresql.org
Mark Murawski <markm-lists@intellasoft.net> writes:
> Affects Versions: 12 (and probably all others)
> Steps to Reproduce:
> - Run a query during plperl validation -- ie: inside a warn handler
> 2022-02-22 12:17:04 EST - - - - 12950 - - 0 - LOG: server process
> (PID 19702) was terminated by signal 11: Segmentation fault
I couldn't reproduce this, either in HEAD or 12.10. However, maybe
there's something faulty about your example, because in my hands it
doesn't seem that plperl_spi_exec is reached at all.
If we do need to do something here, my inclination would be to
reject execution of any SPI operations during validation. That's
not a case that's supposed to have any side-effects.
regards, tom lane
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-02-22 20:06 Mark Murawski <markm-lists@intellasoft.net>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 1 reply; 8+ messages in thread
From: Mark Murawski @ 2022-02-22 20:06 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-bugs@lists.postgresql.org
Hi Tom,
Wow that was fast!
Upon further testing, my path isn't a full fix... there's other parts of
the flow that needs current_call_data
I trimmed down my example from the guts of a complex application. Sorry
I didn't re-test with the trimmed example. But the use-case is very
much the same... it has to do with running spi_exec_query during parse time.
I'll work on redoing the example to reproduce the crash.
On 2/22/22 14:48, Tom Lane wrote:
> Mark Murawski <markm-lists@intellasoft.net> writes:
>> Affects Versions: 12 (and probably all others)
>> Steps to Reproduce:
>> - Run a query during plperl validation -- ie: inside a warn handler
>> 2022-02-22 12:17:04 EST - - - - 12950 - - 0 - LOG: server process
>> (PID 19702) was terminated by signal 11: Segmentation fault
> I couldn't reproduce this, either in HEAD or 12.10. However, maybe
> there's something faulty about your example, because in my hands it
> doesn't seem that plperl_spi_exec is reached at all.
>
> If we do need to do something here, my inclination would be to
> reject execution of any SPI operations during validation. That's
> not a case that's supposed to have any side-effects.
>
> regards, tom lane
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-02-22 20:27 Mark Murawski <markm-lists@intellasoft.net>
parent: Mark Murawski <markm-lists@intellasoft.net>
0 siblings, 1 reply; 8+ messages in thread
From: Mark Murawski @ 2022-02-22 20:27 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-bugs@lists.postgresql.org
Hi Tom
Here you go:
CREATE OR REPLACE FUNCTION public.foo()
RETURNS text
LANGUAGE plperlu
AS $function$
use warnings;
use strict;
use lib '/tmp';
use foo;
my @a;
my @a;
$function$
---
/tmp/foo.pm
---
package foo;
use Data::Dumper;
$SIG{'__WARN__'} = sub {
my $pid = main::spi_exec_query('SELECT pg_backend_pid()')->{rows};
main::elog(main::NOTICE, 'Warning:' . Dumper(\@_));
main::elog(main::NOTICE, 'foo: ' . $pid);
};
1;
On 2/22/22 15:06, Mark Murawski wrote:
> Hi Tom,
>
> Wow that was fast!
>
> Upon further testing, my path isn't a full fix... there's other parts
> of the flow that needs current_call_data
>
>
> I trimmed down my example from the guts of a complex application.
> Sorry I didn't re-test with the trimmed example. But the use-case is
> very much the same... it has to do with running spi_exec_query during
> parse time.
>
> I'll work on redoing the example to reproduce the crash.
>
>
>
> On 2/22/22 14:48, Tom Lane wrote:
>> Mark Murawski <markm-lists@intellasoft.net> writes:
>>> Affects Versions: 12 (and probably all others)
>>> Steps to Reproduce:
>>> - Run a query during plperl validation -- ie: inside a warn handler
>>> 2022-02-22 12:17:04 EST - - - - 12950 - - 0 - LOG: server process
>>> (PID 19702) was terminated by signal 11: Segmentation fault
>> I couldn't reproduce this, either in HEAD or 12.10. However, maybe
>> there's something faulty about your example, because in my hands it
>> doesn't seem that plperl_spi_exec is reached at all.
>>
>> If we do need to do something here, my inclination would be to
>> reject execution of any SPI operations during validation. That's
>> not a case that's supposed to have any side-effects.
>>
>> regards, tom lane
>
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-02-25 20:15 Mark Murawski <markm-lists@intellasoft.net>
parent: Mark Murawski <markm-lists@intellasoft.net>
0 siblings, 1 reply; 8+ messages in thread
From: Mark Murawski @ 2022-02-25 20:15 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-bugs@lists.postgresql.org
HI Tom,
Were you able to reproduce using the updated example?
Thanks.
On 2/22/22 15:27, Mark Murawski wrote:
> Hi Tom
>
> Here you go:
>
> CREATE OR REPLACE FUNCTION public.foo()
> RETURNS text
> LANGUAGE plperlu
> AS $function$
>
> use warnings;
> use strict;
>
> use lib '/tmp';
> use foo;
>
> my @a;
> my @a;
>
> $function$
>
>
> ---
> /tmp/foo.pm
> ---
>
> package foo;
>
> use Data::Dumper;
>
> $SIG{'__WARN__'} = sub {
> my $pid = main::spi_exec_query('SELECT pg_backend_pid()')->{rows};
> main::elog(main::NOTICE, 'Warning:' . Dumper(\@_));
> main::elog(main::NOTICE, 'foo: ' . $pid);
> };
>
> 1;
>
>
>
>
> On 2/22/22 15:06, Mark Murawski wrote:
>> Hi Tom,
>>
>> Wow that was fast!
>>
>> Upon further testing, my path isn't a full fix... there's other parts
>> of the flow that needs current_call_data
>>
>>
>> I trimmed down my example from the guts of a complex application.
>> Sorry I didn't re-test with the trimmed example. But the use-case is
>> very much the same... it has to do with running spi_exec_query during
>> parse time.
>>
>> I'll work on redoing the example to reproduce the crash.
>>
>>
>>
>> On 2/22/22 14:48, Tom Lane wrote:
>>> Mark Murawski <markm-lists@intellasoft.net> writes:
>>>> Affects Versions: 12 (and probably all others)
>>>> Steps to Reproduce:
>>>> - Run a query during plperl validation -- ie: inside a warn handler
>>>> 2022-02-22 12:17:04 EST - - - - 12950 - - 0 - LOG: server process
>>>> (PID 19702) was terminated by signal 11: Segmentation fault
>>> I couldn't reproduce this, either in HEAD or 12.10. However, maybe
>>> there's something faulty about your example, because in my hands it
>>> doesn't seem that plperl_spi_exec is reached at all.
>>>
>>> If we do need to do something here, my inclination would be to
>>> reject execution of any SPI operations during validation. That's
>>> not a case that's supposed to have any side-effects.
>>>
>>> regards, tom lane
>>
>
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-02-25 21:36 Tom Lane <tgl@sss.pgh.pa.us>
parent: Mark Murawski <markm-lists@intellasoft.net>
0 siblings, 1 reply; 8+ messages in thread
From: Tom Lane @ 2022-02-25 21:36 UTC (permalink / raw)
To: Mark Murawski <markm-lists@intellasoft.net>; +Cc: pgsql-bugs@lists.postgresql.org
Mark Murawski <markm-lists@intellasoft.net> writes:
> Were you able to reproduce using the updated example?
Sorry, this wasn't at the top of my to-do queue. It does reproduce
for me, and I think what we need to do about it is the attached.
In the normal code paths, this change will disallow usage of SPI until
we have completed compile_plperl_function and have a valid "prodesc"
to look at. I didn't care for your proposed workaround because
(1) it'd allow execution of non-read-only code during compilation
of a supposedly read-only function;
(2) it didn't patch the dozen or so other places where plperl SPI
functions could try to dereference prodesc;
(3) allowing code execution during function validation is, if not
an actual security hole, certainly on the hairy edge of being one.
I'm somewhat comforted about (3) because it seems the problem is only
reachable from plperlu not plperl. It's still pretty scary though.
I realize that this solution might make your use-case rather awkward.
As far as function validation goes, you can still create your functions
by setting check_function_bodies = off. If you feel you need to have
Perl code that executes during compilation otherwise, I'm not sure
what to tell you, except that it doesn't seem like a great idea.
I also noticed while looking at this that the relatively-recently-added
plperl_spi_commit and plperl_spi_rollback functions neglected to do
check_spi_usage_allowed(), so this fixes that too.
regards, tom lane
Attachments:
prevent-spi-execution-during-plperl-compilation.patch (text/x-diff, 1.3K) download
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 81d9c46e00..3f221ee01b 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -3097,6 +3097,21 @@ check_spi_usage_allowed(void)
/* simple croak as we don't want to involve PostgreSQL code */
croak("SPI functions can not be used in END blocks");
}
+
+ /*
+ * Disallow SPI usage if we're not executing a fully-compiled plperl
+ * function. It might seem impossible to get here in that case, but there
+ * are cases where Perl will try to execute code during compilation. If
+ * we proceed we are likely to crash trying to dereference the prodesc
+ * pointer. Working around that might be possible, but it seems unwise
+ * because it'd allow code execution to happen while validating a
+ * function, which is undesirable.
+ */
+ if (current_call_data == NULL || current_call_data->prodesc == NULL)
+ {
+ /* simple croak as we don't want to involve PostgreSQL code */
+ croak("SPI functions can not be used during function compilation");
+ }
}
@@ -3961,6 +3976,8 @@ plperl_spi_commit(void)
{
MemoryContext oldcontext = CurrentMemoryContext;
+ check_spi_usage_allowed();
+
PG_TRY();
{
SPI_commit();
@@ -3986,6 +4003,8 @@ plperl_spi_rollback(void)
{
MemoryContext oldcontext = CurrentMemoryContext;
+ check_spi_usage_allowed();
+
PG_TRY();
{
SPI_rollback();
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-03-08 19:59 Mark Murawski <markm-lists@intellasoft.net>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 1 reply; 8+ messages in thread
From: Mark Murawski @ 2022-03-08 19:59 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-bugs@lists.postgresql.org
Hi Tom,
No rush on the bug fix, just making sure you don't need anything else
from me on the reproduction.
Yeah I realized my patch wasn't a full solution after sending it in...
My test environment was a little wiggity, and I compiled and tested...
but noticed I actually wasn't using the new build... (and thought that
it was fixed with my change)
Based on the side-effects I think it does make sense to block queries
entirely during parse
On 2/25/22 16:36, Tom Lane wrote:
> Mark Murawski <markm-lists@intellasoft.net> writes:
>> Were you able to reproduce using the updated example?
> Sorry, this wasn't at the top of my to-do queue. It does reproduce
> for me, and I think what we need to do about it is the attached.
> In the normal code paths, this change will disallow usage of SPI until
> we have completed compile_plperl_function and have a valid "prodesc"
> to look at. I didn't care for your proposed workaround because
>
> (1) it'd allow execution of non-read-only code during compilation
> of a supposedly read-only function;
>
> (2) it didn't patch the dozen or so other places where plperl SPI
> functions could try to dereference prodesc;
>
> (3) allowing code execution during function validation is, if not
> an actual security hole, certainly on the hairy edge of being one.
>
> I'm somewhat comforted about (3) because it seems the problem is only
> reachable from plperlu not plperl. It's still pretty scary though.
>
> I realize that this solution might make your use-case rather awkward.
> As far as function validation goes, you can still create your functions
> by setting check_function_bodies = off. If you feel you need to have
> Perl code that executes during compilation otherwise, I'm not sure
> what to tell you, except that it doesn't seem like a great idea.
>
> I also noticed while looking at this that the relatively-recently-added
> plperl_spi_commit and plperl_spi_rollback functions neglected to do
> check_spi_usage_allowed(), so this fixes that too.
>
> regards, tom lane
>
^ permalink raw reply [nested|flat] 8+ messages in thread
* Re: Bug plperl.c
@ 2022-03-08 21:19 Tom Lane <tgl@sss.pgh.pa.us>
parent: Mark Murawski <markm-lists@intellasoft.net>
0 siblings, 0 replies; 8+ messages in thread
From: Tom Lane @ 2022-03-08 21:19 UTC (permalink / raw)
To: Mark Murawski <markm-lists@intellasoft.net>; +Cc: pgsql-bugs@lists.postgresql.org
Mark Murawski <markm-lists@intellasoft.net> writes:
> No rush on the bug fix, just making sure you don't need anything else
> from me on the reproduction.
Nope, it's dealt with, see
https://git.postgresql.org/gitweb/?p=postgresql.git&a=commitdiff&h=638300fef
regards, tom lane
^ permalink raw reply [nested|flat] 8+ messages in thread
end of thread, other threads:[~2022-03-08 21:19 UTC | newest]
Thread overview: 8+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2022-02-22 17:49 Bug plperl.c Mark Murawski <markm-lists@intellasoft.net>
2022-02-22 19:48 ` Tom Lane <tgl@sss.pgh.pa.us>
2022-02-22 20:06 ` Mark Murawski <markm-lists@intellasoft.net>
2022-02-22 20:27 ` Mark Murawski <markm-lists@intellasoft.net>
2022-02-25 20:15 ` Mark Murawski <markm-lists@intellasoft.net>
2022-02-25 21:36 ` Tom Lane <tgl@sss.pgh.pa.us>
2022-03-08 19:59 ` Mark Murawski <markm-lists@intellasoft.net>
2022-03-08 21:19 ` Tom Lane <tgl@sss.pgh.pa.us>
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox