]> granicus.if.org Git - postgresql/commitdiff
Allow plugins to suppress inlining and hook function entry/exit/abort.
authorRobert Haas <rhaas@postgresql.org>
Mon, 13 Dec 2010 23:58:31 +0000 (18:58 -0500)
committerRobert Haas <rhaas@postgresql.org>
Tue, 14 Dec 2010 00:15:53 +0000 (19:15 -0500)
This is intended as infrastructure to allow an eventual SE-Linux plugin to
support trusted procedures.

KaiGai Kohei

src/backend/optimizer/util/clauses.c
src/backend/utils/fmgr/fmgr.c
src/include/fmgr.h

index 80dfaad736f09b96cce5542a3909d9c71a1c3684..fa84164b068f9ede9edc42806e024fb083ff18d8 100644 (file)
@@ -3726,6 +3726,10 @@ inline_function(Oid funcid, Oid result_type, List *args,
        if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)
                return NULL;
 
+       /* Check whether a plugin wants to hook function entry/exit */
+       if (FmgrHookIsNeeded(funcid))
+               return NULL;
+
        /*
         * Make a temporary memory context, so that we don't leak all the stuff
         * that parsing might create.
@@ -4158,6 +4162,10 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
        if (pg_proc_aclcheck(func_oid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)
                return NULL;
 
+       /* Check whether a plugin wants to hook function entry/exit */
+       if (FmgrHookIsNeeded(func_oid))
+               return NULL;
+
        /*
         * OK, let's take a look at the function's pg_proc entry.
         */
index 1c9d2c2fa7b21c8f33e7c74b9a7dd7c36418583e..e457af97647fa4e18aef26b833367f8989b3cae6 100644 (file)
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+/*
+ * Hooks for function calls
+ */
+PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook = NULL;
+PGDLLIMPORT fmgr_hook_type       fmgr_hook = NULL;
 
 /*
  * Declaration for old-style function pointer type.  This is now used only
@@ -216,9 +221,9 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
        finfo->fn_retset = procedureStruct->proretset;
 
        /*
-        * If it has prosecdef set, or non-null proconfig, use
-        * fmgr_security_definer call handler --- unless we are being called again
-        * by fmgr_security_definer.
+        * If it has prosecdef set, non-null proconfig, or if a plugin wants to
+        * hook function entry/exit, use fmgr_security_definer call handler ---
+        * unless we are being called again by fmgr_security_definer.
         *
         * When using fmgr_security_definer, function stats tracking is always
         * disabled at the outer level, and instead we set the flag properly in
@@ -230,7 +235,8 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
         */
        if (!ignore_security &&
                (procedureStruct->prosecdef ||
-                !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig)))
+                !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig) ||
+                FmgrHookIsNeeded(functionId)))
        {
                finfo->fn_addr = fmgr_security_definer;
                finfo->fn_stats = TRACK_FUNC_ALL;               /* ie, never track */
@@ -857,17 +863,18 @@ struct fmgr_security_definer_cache
        FmgrInfo        flinfo;                 /* lookup info for target function */
        Oid                     userid;                 /* userid to set, or InvalidOid */
        ArrayType  *proconfig;          /* GUC values to set, or NULL */
+       Datum           private;                /* private usage for plugin modules */
 };
 
 /*
- * Function handler for security-definer/proconfig functions.  We extract the
- * OID of the actual function and do a fmgr lookup again.  Then we fetch the
- * pg_proc row and copy the owner ID and proconfig fields.     (All this info
- * is cached for the duration of the current query.)  To execute a call,
- * we temporarily replace the flinfo with the cached/looked-up one, while
- * keeping the outer fcinfo (which contains all the actual arguments, etc.)
- * intact.     This is not re-entrant, but then the fcinfo itself can't be used
- * re-entrantly anyway.
+ * Function handler for security-definer/proconfig/plugin-hooked functions.
+ * We extract the OID of the actual function and do a fmgr lookup again.
+ * Then we fetch the pg_proc row and copy the owner ID and proconfig fields.
+ * (All this info is cached for the duration of the current query.)
+ * To execute a call, we temporarily replace the flinfo with the cached
+ * and looked-up one, while keeping the outer fcinfo (which contains all
+ * the actual arguments, etc.) intact. This is not re-entrant, but then
+ * the fcinfo itself can't be used re-entrantly anyway.
  */
 static Datum
 fmgr_security_definer(PG_FUNCTION_ARGS)
@@ -940,6 +947,10 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
                                                GUC_ACTION_SAVE);
        }
 
+       /* function manager hook */
+       if (fmgr_hook)
+               (*fmgr_hook)(FHET_START, &fcache->flinfo, &fcache->private);
+
        /*
         * We don't need to restore GUC or userid settings on error, because the
         * ensuing xact or subxact abort will do that.  The PG_TRY block is only
@@ -968,6 +979,8 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
        PG_CATCH();
        {
                fcinfo->flinfo = save_flinfo;
+               if (fmgr_hook)
+                       (*fmgr_hook)(FHET_ABORT, &fcache->flinfo, &fcache->private);
                PG_RE_THROW();
        }
        PG_END_TRY();
@@ -978,6 +991,8 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
                AtEOXact_GUC(true, save_nestlevel);
        if (OidIsValid(fcache->userid))
                SetUserIdAndSecContext(save_userid, save_sec_context);
+       if (fmgr_hook)
+               (*fmgr_hook)(FHET_END, &fcache->flinfo, &fcache->private);
 
        return result;
 }
index ca5a5eacf79b14dff7ab1c9c98f4e278f99d8dd6..99213bc1179b1a1df2a12e2602d9d76219453e69 100644 (file)
@@ -544,6 +544,32 @@ extern void **find_rendezvous_variable(const char *varName);
 extern int AggCheckCallContext(FunctionCallInfo fcinfo,
                                        MemoryContext *aggcontext);
 
+/*
+ * We allow plugin modules to hook function entry/exit.  This is intended
+ * as support for loadable security policy modules, which may want to
+ * perform additional privilege checks on function entry or exit, or to do
+ * other internal bookkeeping.  To make this possible, such modules must be
+ * able not only to support normal function entry and exit, but also to trap
+ * the case where we bail out due to an error; and they must also be able to
+ * prevent inlining.
+ */
+typedef enum FmgrHookEventType
+{
+       FHET_START,
+       FHET_END,
+       FHET_ABORT
+} FmgrHookEventType;
+
+typedef bool (*needs_fmgr_hook_type)(Oid fn_oid);
+
+typedef void (*fmgr_hook_type)(FmgrHookEventType event,
+                                                          FmgrInfo *flinfo, Datum *private);
+
+extern PGDLLIMPORT needs_fmgr_hook_type        needs_fmgr_hook;
+extern PGDLLIMPORT fmgr_hook_type              fmgr_hook;
+
+#define FmgrHookIsNeeded(fn_oid)                                                       \
+       (!needs_fmgr_hook ? false : (*needs_fmgr_hook)(fn_oid))
 
 /*
  * !!! OLD INTERFACE !!!