Skip to content

Commit 9b2d762

Browse files
committed
Disallow execution of SPI functions during plperl function compilation.
Perl can be convinced to execute user-defined code during compilation of a plperl function (or at least a plperlu function). That's not such a big problem as long as the activity is confined within the Perl interpreter, and it's not clear we could do anything about that anyway. However, if such code tries to use plperl's SPI functions, we have a bigger problem. In the first place, those functions are likely to crash because current_call_data->prodesc isn't set up yet. In the second place, because it isn't set up, we lack critical info such as whether the function is supposed to be read-only. And in the third place, this path allows code execution during function validation, which is strongly discouraged because of the potential for security exploits. Hence, reject execution of the SPI functions until compilation is finished. While here, add check_spi_usage_allowed() calls to various functions that hadn't gotten the memo about checking that. I think that perhaps plperl_sv_to_literal may have been intentionally omitted on the grounds that it was safe at the time; but if so, the addition of transforms functionality changed that. The others are more recently added and seem to be flat-out oversights. Per report from Mark Murawski. Back-patch to all supported branches. Discussion: https://postgr.es/m/9acdf918-7fff-4f40-f750-2ffa84f083d2@intellasoft.net
1 parent 0b1020a commit 9b2d762

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

src/pl/plperl/plperl.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ static plperl_proc_desc *compile_plperl_function(Oid fn_oid,
264264

265265
static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc, bool include_generated);
266266
static SV *plperl_hash_from_datum(Datum attr);
267+
static void check_spi_usage_allowed(void);
267268
static SV *plperl_ref_from_pg_array(Datum arg, Oid typid);
268269
static SV *split_array(plperl_array_info *info, int first, int last, int nest);
269270
static SV *make_array_ref(plperl_array_info *info, int first, int last);
@@ -1432,13 +1433,15 @@ plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
14321433
char *
14331434
plperl_sv_to_literal(SV *sv, char *fqtypename)
14341435
{
1435-
Datum str = CStringGetDatum(fqtypename);
1436-
Oid typid = DirectFunctionCall1(regtypein, str);
1436+
Oid typid;
14371437
Oid typoutput;
14381438
Datum datum;
14391439
bool typisvarlena,
14401440
isnull;
14411441

1442+
check_spi_usage_allowed();
1443+
1444+
typid = DirectFunctionCall1(regtypein, CStringGetDatum(fqtypename));
14421445
if (!OidIsValid(typid))
14431446
ereport(ERROR,
14441447
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -3099,6 +3102,21 @@ check_spi_usage_allowed(void)
30993102
/* simple croak as we don't want to involve PostgreSQL code */
31003103
croak("SPI functions can not be used in END blocks");
31013104
}
3105+
3106+
/*
3107+
* Disallow SPI usage if we're not executing a fully-compiled plperl
3108+
* function. It might seem impossible to get here in that case, but there
3109+
* are cases where Perl will try to execute code during compilation. If
3110+
* we proceed we are likely to crash trying to dereference the prodesc
3111+
* pointer. Working around that might be possible, but it seems unwise
3112+
* because it'd allow code execution to happen while validating a
3113+
* function, which is undesirable.
3114+
*/
3115+
if (current_call_data == NULL || current_call_data->prodesc == NULL)
3116+
{
3117+
/* simple croak as we don't want to involve PostgreSQL code */
3118+
croak("SPI functions can not be used during function compilation");
3119+
}
31023120
}
31033121

31043122

@@ -3219,6 +3237,8 @@ plperl_return_next(SV *sv)
32193237
{
32203238
MemoryContext oldcontext = CurrentMemoryContext;
32213239

3240+
check_spi_usage_allowed();
3241+
32223242
PG_TRY();
32233243
{
32243244
plperl_return_next_internal(sv);
@@ -3963,6 +3983,8 @@ plperl_spi_commit(void)
39633983
{
39643984
MemoryContext oldcontext = CurrentMemoryContext;
39653985

3986+
check_spi_usage_allowed();
3987+
39663988
PG_TRY();
39673989
{
39683990
SPI_commit();
@@ -3988,6 +4010,8 @@ plperl_spi_rollback(void)
39884010
{
39894011
MemoryContext oldcontext = CurrentMemoryContext;
39904012

4013+
check_spi_usage_allowed();
4014+
39914015
PG_TRY();
39924016
{
39934017
SPI_rollback();
@@ -4025,6 +4049,11 @@ plperl_util_elog(int level, SV *msg)
40254049
MemoryContext oldcontext = CurrentMemoryContext;
40264050
char *volatile cmsg = NULL;
40274051

4052+
/*
4053+
* We intentionally omit check_spi_usage_allowed() here, as this seems
4054+
* safe to allow even in the contexts that that function rejects.
4055+
*/
4056+
40284057
PG_TRY();
40294058
{
40304059
cmsg = sv2cstr(msg);

0 commit comments

Comments
 (0)