From 581992ed36da490f52d5eb31b7cd0e2303233318 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Tue, 17 May 2022 13:28:17 -0700 Subject: [PATCH v1 2/3] Allow building only trusted or untrusted PL/Perl. Presently, when the --with-perl configuration option is used, both trusted and untrusted PL/Perl are built. However, some users may only want to build one or the other. This change introduces an optional argument that can be used to do so. If --with-perl='trusted' is specified, only trusted PL/Perl is built. If --with-perl='untrusted' is specified, only untrusted PL/Perl is built. If --with-perl is given without an argument, both trusted and untrusted PL/Perl are built. --- configure | 47 ++++++++++++++++++++++--- configure.ac | 32 ++++++++++++++++- contrib/bool_plperl/Makefile | 24 ++++++++++--- contrib/hstore_plperl/Makefile | 24 ++++++++++--- contrib/jsonb_plperl/Makefile | 24 ++++++++++--- doc/src/sgml/installation.sgml | 23 +++++++++++- src/Makefile.global.in | 2 ++ src/include/pg_config.h.in | 6 ++++ src/pl/plperl/GNUmakefile | 37 +++++++++++++------ src/pl/plperl/expected/plperl_setup.out | 15 +++----- src/pl/plperl/expected/plperlu.out | 27 ++++++++++++++ src/pl/plperl/plperl.c | 10 ++++++ src/pl/plperl/sql/plperl_setup.sql | 11 +++--- src/pl/plperl/sql/plperlu.sql | 29 +++++++++++++++ 14 files changed, 265 insertions(+), 46 deletions(-) diff --git a/configure b/configure index 7dec6b7bf9..faa8b1a2e3 100755 --- a/configure +++ b/configure @@ -723,6 +723,8 @@ with_krb_srvnam krb_srvtab with_gssapi with_python +PERL_UNTRUSTED +PERL_TRUSTED with_perl with_tcl ICU_LIBS @@ -1563,7 +1565,8 @@ Optional Packages: --with-icu build with ICU support --with-tcl build Tcl modules (PL/Tcl) --with-tclconfig=DIR tclConfig.sh is in DIR - --with-perl build Perl modules (PL/Perl) + --with-perl[=TRUSTWORTHINESS] + build Perl modules (PL/Perl) --with-python build Python modules (PL/Python) --with-gssapi build with GSSAPI support --with-krb-srvnam=NAME default service principal name in Kerberos (GSSAPI) @@ -8152,26 +8155,62 @@ if test "${with_perl+set}" = set; then : withval=$with_perl; case $withval in yes) - : + + PERL_TRUSTED=yes + PERL_UNTRUSTED=yes + ;; no) : ;; *) - as_fn_error $? "no argument expected for --with-perl option" "$LINENO" 5 + with_perl=yes + + if test "$withval" = trusted ; then + PERL_TRUSTED=yes + PERL_UNTRUSTED=no + elif test "$withval" = untrusted ; then + PERL_TRUSTED=no + PERL_UNTRUSTED=yes + else + as_fn_error $? "invalid --with-perl value: argument must be omitted or specified as 'trusted' or 'untrusted'" "$LINENO" 5 + fi + ;; esac else with_perl=no - fi + +if test "$with_perl" = yes; then + + if test "$PERL_TRUSTED" = yes ; then + +$as_echo "#define USE_PERL 1" >>confdefs.h + + fi + if test "$PERL_UNTRUSTED" = yes ; then + +$as_echo "#define USE_PERLU 1" >>confdefs.h + + fi + +else + + PERL_TRUSTED=no + PERL_UNTRUSTED=no + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_perl" >&5 $as_echo "$with_perl" >&6; } + + # # Optionally build Python modules (PL/Python) # diff --git a/configure.ac b/configure.ac index d093fb88dd..0dd440131b 100644 --- a/configure.ac +++ b/configure.ac @@ -823,9 +823,39 @@ PGAC_ARG_REQ(with, tclconfig, [DIR], [tclConfig.sh is in DIR]) # Optionally build Perl modules (PL/Perl) # AC_MSG_CHECKING([whether to build Perl modules]) -PGAC_ARG_BOOL(with, perl, no, [build Perl modules (PL/Perl)]) +PGAC_ARG_OPTARG(with, perl, +[TRUSTWORTHINESS], [build Perl modules (PL/Perl)], +[ + PERL_TRUSTED=yes + PERL_UNTRUSTED=yes +], +[ + if test "$withval" = trusted ; then + PERL_TRUSTED=yes + PERL_UNTRUSTED=no + elif test "$withval" = untrusted ; then + PERL_TRUSTED=no + PERL_UNTRUSTED=yes + else + AC_MSG_ERROR([invalid --with-perl value: argument must be omitted or specified as 'trusted' or 'untrusted']) + fi +], +[ + if test "$PERL_TRUSTED" = yes ; then + AC_DEFINE([USE_PERL], 1, [Define to 1 to build with trusted Perl support. (--with-perl='trusted')]) + fi + if test "$PERL_UNTRUSTED" = yes ; then + AC_DEFINE([USE_PERLU], 1, [Define to 1 to build with untrusted Perl support. (--with-perl='untrusted')]) + fi +], +[ + PERL_TRUSTED=no + PERL_UNTRUSTED=no +]) AC_MSG_RESULT([$with_perl]) AC_SUBST(with_perl) +AC_SUBST(PERL_TRUSTED) +AC_SUBST(PERL_UNTRUSTED) # # Optionally build Python modules (PL/Python) diff --git a/contrib/bool_plperl/Makefile b/contrib/bool_plperl/Makefile index efe1de986b..ae23e7e3f1 100644 --- a/contrib/bool_plperl/Makefile +++ b/contrib/bool_plperl/Makefile @@ -8,10 +8,12 @@ PGFILEDESC = "bool_plperl - bool transform for plperl" PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plperl -EXTENSION = bool_plperlu bool_plperl -DATA = bool_plperlu--1.0.sql bool_plperl--1.0.sql - -REGRESS = bool_plperl bool_plperlu +# We do not yet know whether we are building with trusted PL/Perl, untrusted +# PL/Perl, or both, so for now we assume we are just building trusted PL/Perl. +# We'll adjust these later on if this assumption was accurate. +EXTENSION = bool_plperl +DATA = bool_plperl--1.0.sql +REGRESS = bool_plperl ifdef USE_PGXS PG_CONFIG = pg_config @@ -37,3 +39,17 @@ endif # As with plperl we need to include the perl_includespec directory last. override CPPFLAGS := $(CPPFLAGS) $(perl_embed_ccflags) $(perl_includespec) + +# Since we now know whether we are building trusted PL/Perl, untrusted PL/Perl, +# or both, we should adjust the relevant variables accordingly. +ifeq ($(PERL_TRUSTED), no) + override undefine EXTENSION + override undefine DATA + override undefine REGRESS +endif + +ifeq ($(PERL_UNTRUSTED), yes) + override EXTENSION += bool_plperlu + override DATA += bool_plperlu--1.0.sql + override REGRESS += bool_plperlu +endif diff --git a/contrib/hstore_plperl/Makefile b/contrib/hstore_plperl/Makefile index 9065f16408..32af5049a9 100644 --- a/contrib/hstore_plperl/Makefile +++ b/contrib/hstore_plperl/Makefile @@ -6,11 +6,13 @@ OBJS = \ hstore_plperl.o PGFILEDESC = "hstore_plperl - hstore transform for plperl" +# We do not yet know whether we are building with trusted PL/Perl, untrusted +# PL/Perl, or both, so for now we assume we are just building trusted PL/Perl. +# We'll adjust these later on if this assumption was accurate. +EXTENSION = hstore_plperl +DATA = hstore_plperl--1.0.sql +REGRESS = hstore_plperl create_transform -EXTENSION = hstore_plperl hstore_plperlu -DATA = hstore_plperl--1.0.sql hstore_plperlu--1.0.sql - -REGRESS = hstore_plperl hstore_plperlu create_transform EXTRA_INSTALL = contrib/hstore ifdef USE_PGXS @@ -39,3 +41,17 @@ endif # As with plperl we need to include the perl_includespec directory last. override CPPFLAGS := $(CPPFLAGS) $(perl_embed_ccflags) $(perl_includespec) + +# Since we now know whether we are building trusted PL/Perl, untrusted PL/Perl, +# or both, we should adjust the relevant variables accordingly. +ifeq ($(PERL_TRUSTED), no) + override undefine EXTENSION + override undefine DATA + override undefine REGRESS +endif + +ifeq ($(PERL_UNTRUSTED), yes) + override EXTENSION += hstore_plperlu + override DATA += hstore_plperlu--1.0.sql + override REGRESS += hstore_plperlu +endif diff --git a/contrib/jsonb_plperl/Makefile b/contrib/jsonb_plperl/Makefile index ba9480e819..218bd51c9e 100644 --- a/contrib/jsonb_plperl/Makefile +++ b/contrib/jsonb_plperl/Makefile @@ -8,10 +8,12 @@ PGFILEDESC = "jsonb_plperl - jsonb transform for plperl" PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plperl -EXTENSION = jsonb_plperlu jsonb_plperl -DATA = jsonb_plperlu--1.0.sql jsonb_plperl--1.0.sql - -REGRESS = jsonb_plperl jsonb_plperlu +# We do not yet know whether we are building with trusted PL/Perl, untrusted +# PL/Perl, or both, so for now we assume we are just building trusted PL/Perl. +# We'll adjust these later on if this assumption was accurate. +EXTENSION = jsonb_plperl +DATA = jsonb_plperl--1.0.sql +REGRESS = jsonb_plperl SHLIB_LINK += $(filter -lm, $(LIBS)) @@ -39,3 +41,17 @@ endif # As with plperl we need to include the perl_includespec directory last. override CPPFLAGS := $(CPPFLAGS) $(perl_embed_ccflags) $(perl_includespec) + +# Since we now know whether we are building trusted PL/Perl, untrusted PL/Perl, +# or both, we should adjust the relevant variables accordingly. +ifeq ($(PERL_TRUSTED), no) + override undefine EXTENSION + override undefine DATA + override undefine REGRESS +endif + +ifeq ($(PERL_UNTRUSTED), yes) + override EXTENSION += jsonb_plperlu + override DATA += jsonb_plperlu--1.0.sql + override REGRESS += jsonb_plperlu +endif diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index c585078029..4377e9d51a 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -873,10 +873,31 @@ build-postgresql: - + Build the PL/Perl server-side language. + TRUSTWORTHINESS is an optional argument and, + if provided, must be one of: + + + + + to build only trusted + PL/Perl + + + + + to build only untrusted + PL/Perl + (PL/PerlU) + + + + + If TRUSTWORTHINESS is not specified, both + trusted and untrusted PL/Perl will be built. diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 051718e4fe..53f367ca7a 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -526,6 +526,8 @@ GENHTML = @GENHTML@ DEF_PGPORT = @default_port@ WANTED_LANGUAGES = @WANTED_LANGUAGES@ +PERL_TRUSTED = @PERL_TRUSTED@ +PERL_UNTRUSTED = @PERL_UNTRUSTED@ ########################################################################## diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index cdd742cb55..2779f5f671 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -931,6 +931,12 @@ /* Define to 1 to build with PAM support. (--with-pam) */ #undef USE_PAM +/* Define to 1 to build with trusted Perl support. (--with-perl='trusted') */ +#undef USE_PERL + +/* Define to 1 to build with untrusted Perl support. (--with-perl='untrusted') */ +#undef USE_PERLU + /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */ #undef USE_SLICING_BY_8_CRC32C diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile index a2e6410f53..d01201bbac 100644 --- a/src/pl/plperl/GNUmakefile +++ b/src/pl/plperl/GNUmakefile @@ -27,8 +27,13 @@ NAME = plperl OBJS = plperl.o SPI.o Util.o $(WIN32RES) -DATA = plperl.control plperl--1.0.sql \ - plperlu.control plperlu--1.0.sql +ifeq ($(PERL_TRUSTED), yes) + DATA += plperl.control plperl--1.0.sql +endif + +ifeq ($(PERL_UNTRUSTED), yes) + DATA += plperlu.control plperlu--1.0.sql +endif PERLCHUNKS = plc_perlboot.pl plc_trusted.pl @@ -56,14 +61,26 @@ endif # win32 SHLIB_LINK = $(perl_embed_ldflags) REGRESS_OPTS = --dbname=$(PL_TESTDB) -REGRESS = plperl_setup plperl plperl_lc plperl_trigger plperl_shared \ - plperl_elog plperl_util plperl_init plperlu plperl_array \ - plperl_call plperl_transaction -# if Perl can support two interpreters in one backend, -# test plperl-and-plperlu cases -ifneq ($(PERL),) -ifeq ($(shell $(PERL) -V:usemultiplicity), usemultiplicity='define';) - REGRESS += plperl_plperlu + +ifeq ($(PERL_TRUSTED), yes) + REGRESS = plperl_setup plperl plperl_lc plperl_trigger plperl_shared \ + plperl_elog plperl_util plperl_init plperl_array plperl_call \ + plperl_transaction +endif + +ifeq ($(PERL_UNTRUSTED), yes) + REGRESS += plperlu +endif + +ifeq ($(PERL_TRUSTED), yes) +ifeq ($(PERL_UNTRUSTED), yes) + # if Perl can support two interpreters in one backend, + # test plperl-and-plperlu cases + ifneq ($(PERL),) + ifeq ($(shell $(PERL) -V:usemultiplicity), usemultiplicity='define';) + REGRESS += plperl_plperlu + endif + endif endif endif diff --git a/src/pl/plperl/expected/plperl_setup.out b/src/pl/plperl/expected/plperl_setup.out index 5234febefd..d0682325b2 100644 --- a/src/pl/plperl/expected/plperl_setup.out +++ b/src/pl/plperl/expected/plperl_setup.out @@ -1,18 +1,15 @@ -- --- Install the plperl and plperlu extensions +-- Install plperl -- -- Before going ahead with the to-be-tested installations, verify that --- a non-superuser is allowed to install plperl (but not plperlu) when --- suitable permissions have been granted. +-- a non-superuser is allowed to install plperl when suitable permissions +-- have been granted. CREATE USER regress_user1; CREATE USER regress_user2; SET ROLE regress_user1; CREATE EXTENSION plperl; -- fail ERROR: permission denied to create extension "plperl" HINT: Must have CREATE privilege on current database to create this extension. -CREATE EXTENSION plperlu; -- fail -ERROR: permission denied to create extension "plperlu" -HINT: Must be superuser to create this extension. RESET ROLE; DO $$ begin @@ -22,9 +19,6 @@ end; $$; SET ROLE regress_user1; CREATE EXTENSION plperl; -CREATE EXTENSION plperlu; -- fail -ERROR: permission denied to create extension "plperlu" -HINT: Must be superuser to create this extension. CREATE SCHEMA plperl_setup_scratch; SET search_path = plperl_setup_scratch; GRANT ALL ON SCHEMA plperl_setup_scratch TO regress_user2; @@ -68,6 +62,5 @@ RESET ROLE; DROP OWNED BY regress_user1; DROP USER regress_user1; DROP USER regress_user2; --- Now install the versions that will be used by subsequent test scripts. +-- Now install the version that will be used by subsequent test scripts. CREATE EXTENSION plperl; -CREATE EXTENSION plperlu; diff --git a/src/pl/plperl/expected/plperlu.out b/src/pl/plperl/expected/plperlu.out index a3edb38497..f759466a90 100644 --- a/src/pl/plperl/expected/plperlu.out +++ b/src/pl/plperl/expected/plperlu.out @@ -1,5 +1,32 @@ +-- Before going ahead with the to-be-tested installations, verify that +-- only superusers can install plperlu. +CREATE USER regress_user1; +SET ROLE regress_user1; +CREATE EXTENSION plperlu; -- fail +ERROR: permission denied to create extension "plperlu" +HINT: Must be superuser to create this extension. +RESET ROLE; +DO $$ +begin + execute format('grant create on database %I to regress_user1', + current_database()); +end; +$$; +SET ROLE regress_user1; +CREATE EXTENSION plperlu; -- fail +ERROR: permission denied to create extension "plperlu" +HINT: Must be superuser to create this extension. +RESET ROLE; +DO $$ +begin + execute format('revoke create on database %I from regress_user1', + current_database()); +end; +$$; +DROP ROLE regress_user1; -- Use ONLY plperlu tests here. For plperl/plerlu combined tests -- see plperl_plperlu.sql +CREATE EXTENSION plperlu; -- This test tests setting on_plperlu_init after loading plperl LOAD 'plperl'; -- Test plperl.on_plperlu_init gets run diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 9bc6793a30..ff5f9641d5 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -445,6 +445,7 @@ _PG_init(void) * OK since the worst result would be an error. Your code oughta pass * use_strict anyway ;-) */ +#ifdef USE_PERL DefineCustomStringVariable("plperl.on_plperl_init", gettext_noop("Perl initialization code to execute once when plperl is first used."), NULL, @@ -452,7 +453,9 @@ _PG_init(void) NULL, PGC_SUSET, 0, NULL, NULL, NULL); +#endif /* USE_PERL */ +#ifdef USE_PERLU DefineCustomStringVariable("plperl.on_plperlu_init", gettext_noop("Perl initialization code to execute once when plperlu is first used."), NULL, @@ -460,6 +463,7 @@ _PG_init(void) NULL, PGC_SUSET, 0, NULL, NULL, NULL); +#endif /* USE_PERLU */ MarkGUCPrefixReserved("plperl"); @@ -2039,6 +2043,7 @@ plperl_validator_internal(PG_FUNCTION_ARGS, bool trusted) * There are three externally visible pieces to plperl: plperl_call_handler, * plperl_inline_handler, and plperl_validator. */ +#ifdef USE_PERL PG_FUNCTION_INFO_V1(plperl_call_handler); @@ -2064,11 +2069,14 @@ plperl_validator(PG_FUNCTION_ARGS) return plperl_validator_internal(fcinfo, true); } +#endif /* USE_PERL */ + /* * plperlu likewise requires three externally visible functions: * plperlu_call_handler, plperlu_inline_handler, and plperlu_validator. */ +#ifdef USE_PERLU PG_FUNCTION_INFO_V1(plperlu_call_handler); @@ -2095,6 +2103,8 @@ plperlu_validator(PG_FUNCTION_ARGS) return plperl_validator_internal(fcinfo, false); } +#endif /* USE_PERLU */ + /* * Uses mkfunc to create a subroutine whose text is diff --git a/src/pl/plperl/sql/plperl_setup.sql b/src/pl/plperl/sql/plperl_setup.sql index a89cf56617..eb29cacdac 100644 --- a/src/pl/plperl/sql/plperl_setup.sql +++ b/src/pl/plperl/sql/plperl_setup.sql @@ -1,10 +1,10 @@ -- --- Install the plperl and plperlu extensions +-- Install plperl -- -- Before going ahead with the to-be-tested installations, verify that --- a non-superuser is allowed to install plperl (but not plperlu) when --- suitable permissions have been granted. +-- a non-superuser is allowed to install plperl when suitable permissions +-- have been granted. CREATE USER regress_user1; CREATE USER regress_user2; @@ -12,7 +12,6 @@ CREATE USER regress_user2; SET ROLE regress_user1; CREATE EXTENSION plperl; -- fail -CREATE EXTENSION plperlu; -- fail RESET ROLE; @@ -26,7 +25,6 @@ $$; SET ROLE regress_user1; CREATE EXTENSION plperl; -CREATE EXTENSION plperlu; -- fail CREATE SCHEMA plperl_setup_scratch; SET search_path = plperl_setup_scratch; GRANT ALL ON SCHEMA plperl_setup_scratch TO regress_user2; @@ -68,6 +66,5 @@ DROP OWNED BY regress_user1; DROP USER regress_user1; DROP USER regress_user2; --- Now install the versions that will be used by subsequent test scripts. +-- Now install the version that will be used by subsequent test scripts. CREATE EXTENSION plperl; -CREATE EXTENSION plperlu; diff --git a/src/pl/plperl/sql/plperlu.sql b/src/pl/plperl/sql/plperlu.sql index be43df5d90..1e050e8237 100644 --- a/src/pl/plperl/sql/plperlu.sql +++ b/src/pl/plperl/sql/plperlu.sql @@ -1,5 +1,34 @@ +-- Before going ahead with the to-be-tested installations, verify that +-- only superusers can install plperlu. +CREATE USER regress_user1; + +SET ROLE regress_user1; +CREATE EXTENSION plperlu; -- fail +RESET ROLE; + +DO $$ +begin + execute format('grant create on database %I to regress_user1', + current_database()); +end; +$$; + +SET ROLE regress_user1; +CREATE EXTENSION plperlu; -- fail +RESET ROLE; + +DO $$ +begin + execute format('revoke create on database %I from regress_user1', + current_database()); +end; +$$; + +DROP ROLE regress_user1; + -- Use ONLY plperlu tests here. For plperl/plerlu combined tests -- see plperl_plperlu.sql +CREATE EXTENSION plperlu; -- This test tests setting on_plperlu_init after loading plperl LOAD 'plperl'; -- 2.25.1