From 3884072329bd1ad7d41bf7582c5d60e969365634 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 4 Jul 2018 09:26:19 +0200 Subject: [PATCH] Prohibit transaction commands in security definer procedures Starting and aborting transactions in security definer procedures doesn't work. StartTransaction() insists that the security context stack is empty, so this would currently cause a crash, and AbortTransaction() resets it. This could be made to work by reorganizing the code, but right now we just prohibit it. Reported-by: amul sul Discussion: https://www.postgresql.org/message-id/flat/CAAJ_b96Gupt_LFL7uNyy3c50-wbhA68NUjiK5%3DrF6_w%3Dpq_T%3DQ%40mail.gmail.com --- doc/src/sgml/ref/create_procedure.sgml | 6 ++++++ src/backend/commands/functioncmds.c | 9 +++++++++ src/pl/plpgsql/src/expected/plpgsql_transaction.out | 12 ++++++++++++ src/pl/plpgsql/src/sql/plpgsql_transaction.sql | 13 +++++++++++++ 4 files changed, 40 insertions(+) diff --git a/doc/src/sgml/ref/create_procedure.sgml b/doc/src/sgml/ref/create_procedure.sgml index f3c3bb006c..6c1de34b01 100644 --- a/doc/src/sgml/ref/create_procedure.sgml +++ b/doc/src/sgml/ref/create_procedure.sgml @@ -203,6 +203,12 @@ CREATE [ OR REPLACE ] PROCEDURE conformance, but it is optional since, unlike in SQL, this feature applies to all procedures not only external ones. + + + A SECURITY DEFINER procedure cannot execute + transaction control statements (for example, COMMIT + and ROLLBACK, depending on the language). + diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 84daa19e06..68109bfda0 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -2245,6 +2245,15 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver if (!heap_attisnull(tp, Anum_pg_proc_proconfig, NULL)) callcontext->atomic = true; + /* + * In security definer procedures, we can't allow transaction commands. + * StartTransaction() insists that the security context stack is empty, + * and AbortTransaction() resets the security context. This could be + * reorganized, but right now it doesn't work. + */ + if (((Form_pg_proc )GETSTRUCT(tp))->prosecdef) + callcontext->atomic = true; + /* * Expand named arguments, defaults, etc. */ diff --git a/src/pl/plpgsql/src/expected/plpgsql_transaction.out b/src/pl/plpgsql/src/expected/plpgsql_transaction.out index 274b2c6f17..0b5a039b89 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_transaction.out +++ b/src/pl/plpgsql/src/expected/plpgsql_transaction.out @@ -130,6 +130,18 @@ $$; CALL transaction_test5(); ERROR: invalid transaction termination CONTEXT: PL/pgSQL function transaction_test5() line 3 at COMMIT +-- SECURITY DEFINER currently disallow transaction statements +CREATE PROCEDURE transaction_test5b() +LANGUAGE plpgsql +SECURITY DEFINER +AS $$ +BEGIN + COMMIT; +END; +$$; +CALL transaction_test5b(); +ERROR: invalid transaction termination +CONTEXT: PL/pgSQL function transaction_test5b() line 3 at COMMIT TRUNCATE test1; -- nested procedure calls CREATE PROCEDURE transaction_test6(c text) diff --git a/src/pl/plpgsql/src/sql/plpgsql_transaction.sql b/src/pl/plpgsql/src/sql/plpgsql_transaction.sql index 1624aed6ec..236db9bf2b 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_transaction.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_transaction.sql @@ -116,6 +116,19 @@ $$; CALL transaction_test5(); +-- SECURITY DEFINER currently disallow transaction statements +CREATE PROCEDURE transaction_test5b() +LANGUAGE plpgsql +SECURITY DEFINER +AS $$ +BEGIN + COMMIT; +END; +$$; + +CALL transaction_test5b(); + + TRUNCATE test1; -- nested procedure calls