summaryrefslogtreecommitdiff
path: root/contrib/sepgsql/hooks.c
diff options
context:
space:
mode:
authorMichael Paquier2012-07-27 03:04:31 +0000
committerMichael Paquier2012-07-27 03:04:31 +0000
commitc1dd6cb5fdea86bbddfb471b1da56bb54b604c45 (patch)
tree117e5bd14e60fd107c2f39cab220b8379a612ccd /contrib/sepgsql/hooks.c
parentd03ea805cef9375bee9b751e65d698c07c138bf5 (diff)
parent80edfd76591fdb9beec061de3c05ef4e9d96ce56 (diff)
Merge commit '80edfd76591fdb9beec061de3c05ef4e9d96ce56' into postgres-xc/master
This is the merge of Postgres-XC master branch with the intersection of PostgreSQL master branch and 9.2 stable branch. All the manual conflicts are solved, please note that the code does not compile yet. All the compilation will be solved later. Conflicts: COPYRIGHT GNUmakefile.in configure configure.in contrib/pgbench/pgbench.c contrib/sepgsql/hooks.c src/backend/access/common/heaptuple.c src/backend/access/heap/heapam.c src/backend/access/transam/Makefile src/backend/access/transam/rmgr.c src/backend/access/transam/twophase.c src/backend/access/transam/varsup.c src/backend/access/transam/xact.c src/backend/catalog/Makefile src/backend/commands/comment.c src/backend/commands/copy.c src/backend/commands/explain.c src/backend/commands/indexcmds.c src/backend/commands/prepare.c src/backend/commands/tablecmds.c src/backend/commands/view.c src/backend/executor/functions.c src/backend/executor/spi.c src/backend/nodes/copyfuncs.c src/backend/nodes/makefuncs.c src/backend/optimizer/path/allpaths.c src/backend/optimizer/plan/createplan.c src/backend/optimizer/plan/planner.c src/backend/optimizer/plan/setrefs.c src/backend/optimizer/util/var.c src/backend/parser/analyze.c src/backend/parser/gram.y src/backend/parser/parse_agg.c src/backend/postmaster/postmaster.c src/backend/storage/ipc/procarray.c src/backend/storage/lmgr/proc.c src/backend/tcop/postgres.c src/backend/tcop/utility.c src/backend/utils/adt/dbsize.c src/backend/utils/adt/lockfuncs.c src/backend/utils/adt/misc.c src/backend/utils/adt/ruleutils.c src/backend/utils/cache/plancache.c src/backend/utils/misc/guc.c src/bin/initdb/initdb.c src/bin/pg_ctl/pg_ctl.c src/bin/pg_dump/pg_dump.c src/bin/psql/startup.c src/bin/psql/tab-complete.c src/include/Makefile src/include/access/rmgr.h src/include/access/xact.h src/include/catalog/catversion.h src/include/catalog/pg_aggregate.h src/include/catalog/pg_proc.h src/include/commands/explain.h src/include/commands/schemacmds.h src/include/nodes/parsenodes.h src/include/nodes/pg_list.h src/include/nodes/primnodes.h src/include/optimizer/pathnode.h src/include/optimizer/var.h src/include/pg_config.h.win32 src/include/storage/proc.h src/include/utils/plancache.h src/include/utils/snapshot.h src/include/utils/timestamp.h src/test/regress/expected/aggregates.out src/test/regress/expected/create_index.out src/test/regress/expected/inherit.out src/test/regress/expected/rangefuncs.out src/test/regress/expected/sanity_check.out src/test/regress/expected/sequence.out src/test/regress/expected/with.out src/test/regress/output/constraints.source src/test/regress/sql/inherit.sql src/test/regress/sql/rules.sql
Diffstat (limited to 'contrib/sepgsql/hooks.c')
-rw-r--r--contrib/sepgsql/hooks.c440
1 files changed, 206 insertions, 234 deletions
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 8c85c5d89c..fabd04b71d 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -4,20 +4,21 @@
*
* Entrypoints of the hooks in PostgreSQL, and dispatches the callbacks.
*
- * Copyright (c) 2010-2011, PostgreSQL Global Development Group
+ * Copyright (c) 2010-2012, PostgreSQL Global Development Group
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "catalog/dependency.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_class.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/seclabel.h"
#include "executor/executor.h"
#include "fmgr.h"
-#include "libpq/auth.h"
#include "miscadmin.h"
#include "tcop/utility.h"
#include "utils/guc.h"
@@ -35,11 +36,25 @@ void _PG_init(void);
* Saved hook entries (if stacked)
*/
static object_access_hook_type next_object_access_hook = NULL;
-static ClientAuthentication_hook_type next_client_auth_hook = NULL;
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
-static needs_fmgr_hook_type next_needs_fmgr_hook = NULL;
-static fmgr_hook_type next_fmgr_hook = NULL;
static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
+static ExecutorStart_hook_type next_ExecutorStart_hook = NULL;
+
+/*
+ * Contextual information on DDL commands
+ */
+typedef struct
+{
+ NodeTag cmdtype;
+
+ /*
+ * Name of the template database given by users on CREATE DATABASE
+ * command. Elsewhere (including the case of default) NULL.
+ */
+ const char *createdb_dtemplate;
+} sepgsql_context_info_t;
+
+static sepgsql_context_info_t sepgsql_context_info;
/*
* GUC: sepgsql.permissive = (on|off)
@@ -64,48 +79,6 @@ sepgsql_get_debug_audit(void)
}
/*
- * sepgsql_client_auth
- *
- * Entrypoint of the client authentication hook.
- * It switches the client label according to getpeercon(), and the current
- * performing mode according to the GUC setting.
- */
-static void
-sepgsql_client_auth(Port *port, int status)
-{
- char *context;
-
- if (next_client_auth_hook)
- (*next_client_auth_hook) (port, status);
-
- /*
- * In the case when authentication failed, the supplied socket shall be
- * closed soon, so we don't need to do anything here.
- */
- if (status != STATUS_OK)
- return;
-
- /*
- * Getting security label of the peer process using API of libselinux.
- */
- if (getpeercon_raw(port->sock, &context) < 0)
- ereport(FATAL,
- (errcode(ERRCODE_INTERNAL_ERROR),
- errmsg("SELinux: unable to get peer label: %m")));
-
- sepgsql_set_client_label(context);
-
- /*
- * Switch the current performing mode from INTERNAL to either DEFAULT or
- * PERMISSIVE.
- */
- if (sepgsql_permissive)
- sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE);
- else
- sepgsql_set_mode(SEPGSQL_MODE_DEFAULT);
-}
-
-/*
* sepgsql_object_access
*
* Entrypoint of the object_access_hook. This routine performs as
@@ -115,23 +88,51 @@ static void
sepgsql_object_access(ObjectAccessType access,
Oid classId,
Oid objectId,
- int subId)
+ int subId,
+ void *arg)
{
if (next_object_access_hook)
- (*next_object_access_hook) (access, classId, objectId, subId);
+ (*next_object_access_hook) (access, classId, objectId, subId, arg);
switch (access)
{
case OAT_POST_CREATE:
switch (classId)
{
+ case DatabaseRelationId:
+ sepgsql_database_post_create(objectId,
+ sepgsql_context_info.createdb_dtemplate);
+ break;
+
case NamespaceRelationId:
sepgsql_schema_post_create(objectId);
break;
case RelationRelationId:
if (subId == 0)
- sepgsql_relation_post_create(objectId);
+ {
+ /*
+ * All cases we want to apply permission checks on
+ * creation of a new relation are invocation of the
+ * heap_create_with_catalog via DefineRelation or
+ * OpenIntoRel. Elsewhere, we need neither assignment
+ * of security label nor permission checks.
+ */
+ switch (sepgsql_context_info.cmdtype)
+ {
+ case T_CreateStmt:
+ case T_ViewStmt:
+ case T_CreateSeqStmt:
+ case T_CompositeTypeStmt:
+ case T_CreateForeignTableStmt:
+ case T_SelectStmt:
+ sepgsql_relation_post_create(objectId);
+ break;
+ default:
+ /* via make_new_heap() */
+ break;
+ }
+ }
else
sepgsql_attribute_post_create(objectId, subId);
break;
@@ -146,6 +147,46 @@ sepgsql_object_access(ObjectAccessType access,
}
break;
+ case OAT_DROP:
+ {
+ ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
+
+ /*
+ * No need to apply permission checks on object deletion due
+ * to internal cleanups; such as removal of temporary database
+ * object on session closed.
+ */
+ if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
+ break;
+
+ switch (classId)
+ {
+ case DatabaseRelationId:
+ sepgsql_database_drop(objectId);
+ break;
+
+ case NamespaceRelationId:
+ sepgsql_schema_drop(objectId);
+ break;
+
+ case RelationRelationId:
+ if (subId == 0)
+ sepgsql_relation_drop(objectId);
+ else
+ sepgsql_attribute_drop(objectId, subId);
+ break;
+
+ case ProcedureRelationId:
+ sepgsql_proc_drop(objectId);
+ break;
+
+ default:
+ /* Ignore unsupported object classes */
+ break;
+ }
+ }
+ break;
+
default:
elog(ERROR, "unexpected object access type: %d", (int) access);
break;
@@ -175,129 +216,43 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
}
/*
- * sepgsql_needs_fmgr_hook
+ * sepgsql_executor_start
*
- * It informs the core whether the supplied function is trusted procedure,
- * or not. If true, sepgsql_fmgr_hook shall be invoked at start, end, and
- * abort time of function invocation.
+ * It saves contextual information during ExecutorStart to distinguish
+ * a case with/without permission checks later.
*/
-static bool
-sepgsql_needs_fmgr_hook(Oid functionId)
+static void
+sepgsql_executor_start(QueryDesc *queryDesc, int eflags)
{
- char *old_label;
- char *new_label;
- char *function_label;
-
- if (next_needs_fmgr_hook &&
- (*next_needs_fmgr_hook) (functionId))
- return true;
+ sepgsql_context_info_t saved_context_info = sepgsql_context_info;
- /*
- * SELinux needs the function to be called via security_definer wrapper,
- * if this invocation will take a domain-transition. We call these
- * functions as trusted-procedure, if the security policy has a rule that
- * switches security label of the client on execution.
- */
- old_label = sepgsql_get_client_label();
- new_label = sepgsql_proc_get_domtrans(functionId);
- if (strcmp(old_label, new_label) != 0)
- {
- pfree(new_label);
- return true;
- }
- pfree(new_label);
-
- /*
- * Even if not a trusted-procedure, this function should not be inlined
- * unless the client has db_procedure:{execute} permission. Please note
- * that it shall be actually failed later because of same reason with
- * ACL_EXECUTE.
- */
- function_label = sepgsql_get_label(ProcedureRelationId, functionId, 0);
- if (sepgsql_check_perms(sepgsql_get_client_label(),
- function_label,
- SEPG_CLASS_DB_PROCEDURE,
- SEPG_DB_PROCEDURE__EXECUTE,
- NULL, false) != true)
+ PG_TRY();
{
- pfree(function_label);
- return true;
+ if (queryDesc->operation == CMD_SELECT)
+ sepgsql_context_info.cmdtype = T_SelectStmt;
+ else if (queryDesc->operation == CMD_INSERT)
+ sepgsql_context_info.cmdtype = T_InsertStmt;
+ else if (queryDesc->operation == CMD_DELETE)
+ sepgsql_context_info.cmdtype = T_DeleteStmt;
+ else if (queryDesc->operation == CMD_UPDATE)
+ sepgsql_context_info.cmdtype = T_UpdateStmt;
+
+ /*
+ * XXX - If queryDesc->operation is not above four cases, an error
+ * shall be raised on the following executor stage soon.
+ */
+ if (next_ExecutorStart_hook)
+ (*next_ExecutorStart_hook) (queryDesc, eflags);
+ else
+ standard_ExecutorStart(queryDesc, eflags);
}
- pfree(function_label);
- return false;
-}
-
-/*
- * sepgsql_fmgr_hook
- *
- * It switches security label of the client on execution of trusted
- * procedures.
- */
-static void
-sepgsql_fmgr_hook(FmgrHookEventType event,
- FmgrInfo *flinfo, Datum *private)
-{
- struct
- {
- char *old_label;
- char *new_label;
- Datum next_private;
- } *stack;
-
- switch (event)
+ PG_CATCH();
{
- case FHET_START:
- stack = (void *) DatumGetPointer(*private);
- if (!stack)
- {
- MemoryContext oldcxt;
- const char *cur_label = sepgsql_get_client_label();
-
- oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
- stack = palloc(sizeof(*stack));
- stack->old_label = NULL;
- stack->new_label = sepgsql_proc_get_domtrans(flinfo->fn_oid);
- stack->next_private = 0;
-
- MemoryContextSwitchTo(oldcxt);
-
- if (strcmp(cur_label, stack->new_label) != 0)
- {
- /*
- * process:transition permission between old and new
- * label, when user tries to switch security label of the
- * client on execution of trusted procedure.
- */
- sepgsql_check_perms(cur_label, stack->new_label,
- SEPG_CLASS_PROCESS,
- SEPG_PROCESS__TRANSITION,
- NULL, true);
- }
-
- *private = PointerGetDatum(stack);
- }
- Assert(!stack->old_label);
- stack->old_label = sepgsql_set_client_label(stack->new_label);
-
- if (next_fmgr_hook)
- (*next_fmgr_hook) (event, flinfo, &stack->next_private);
- break;
-
- case FHET_END:
- case FHET_ABORT:
- stack = (void *) DatumGetPointer(*private);
-
- if (next_fmgr_hook)
- (*next_fmgr_hook) (event, flinfo, &stack->next_private);
-
- sepgsql_set_client_label(stack->old_label);
- stack->old_label = NULL;
- break;
-
- default:
- elog(ERROR, "unexpected event type: %d", (int) event);
- break;
+ sepgsql_context_info = saved_context_info;
+ PG_RE_THROW();
}
+ PG_END_TRY();
+ sepgsql_context_info = saved_context_info;
}
/*
@@ -317,52 +272,85 @@ sepgsql_utility_command(Node *parsetree,
#endif /* PGXC */
char *completionTag)
{
- if (next_ProcessUtility_hook)
- (*next_ProcessUtility_hook) (parsetree, queryString, params,
- isTopLevel, dest,
-#ifdef PGXC
- sentToRemote,
-#endif /* PGXC */
- completionTag);
+ sepgsql_context_info_t saved_context_info = sepgsql_context_info;
+ ListCell *cell;
- /*
- * Check command tag to avoid nefarious operations
- */
- switch (nodeTag(parsetree))
+ PG_TRY();
{
- case T_LoadStmt:
-
- /*
- * We reject LOAD command across the board on enforcing mode,
- * because a binary module can arbitrarily override hooks.
- */
- if (sepgsql_getenforce())
- {
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("SELinux: LOAD is not permitted")));
- }
- break;
- default:
+ /*
+ * Check command tag to avoid nefarious operations, and save the
+ * current contextual information to determine whether we should apply
+ * permission checks here, or not.
+ */
+ sepgsql_context_info.cmdtype = nodeTag(parsetree);
+
+ switch (nodeTag(parsetree))
+ {
+ case T_CreatedbStmt:
+
+ /*
+ * We hope to reference name of the source database, but it
+ * does not appear in system catalog. So, we save it here.
+ */
+ foreach(cell, ((CreatedbStmt *) parsetree)->options)
+ {
+ DefElem *defel = (DefElem *) lfirst(cell);
+
+ if (strcmp(defel->defname, "template") == 0)
+ {
+ sepgsql_context_info.createdb_dtemplate
+ = strVal(defel->arg);
+ break;
+ }
+ }
+ break;
- /*
- * Right now we don't check any other utility commands, because it
- * needs more detailed information to make access control decision
- * here, but we don't want to have two parse and analyze routines
- * individually.
- */
- break;
- }
+ case T_LoadStmt:
- /*
- * Original implementation
- */
- standard_ProcessUtility(parsetree, queryString, params,
- isTopLevel, dest,
+ /*
+ * We reject LOAD command across the board on enforcing mode,
+ * because a binary module can arbitrarily override hooks.
+ */
+ if (sepgsql_getenforce())
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: LOAD is not permitted")));
+ }
+ break;
+ default:
+
+ /*
+ * Right now we don't check any other utility commands,
+ * because it needs more detailed information to make access
+ * control decision here, but we don't want to have two parse
+ * and analyze routines individually.
+ */
+ break;
+ }
+
+ if (next_ProcessUtility_hook)
+ (*next_ProcessUtility_hook) (parsetree, queryString, params,
+ isTopLevel, dest,
#ifdef PGXC
- sentToRemote,
-#endif /* PGXC */
- completionTag);
+ sentToRemote,
+#endif
+ completionTag);
+ else
+ standard_ProcessUtility(parsetree, queryString, params,
+ isTopLevel, dest,
+#ifdef PGXC
+ sentToRemote,
+#endif
+ completionTag);
+ }
+ PG_CATCH();
+ {
+ sepgsql_context_info = saved_context_info;
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+ sepgsql_context_info = saved_context_info;
}
/*
@@ -371,8 +359,6 @@ sepgsql_utility_command(Node *parsetree,
void
_PG_init(void)
{
- char *context;
-
/*
* We allow to load the SE-PostgreSQL module on single-user-mode or
* shared_preload_libraries settings only.
@@ -428,30 +414,16 @@ _PG_init(void)
NULL,
NULL);
- /*
- * Set up dummy client label.
- *
- * XXX - note that PostgreSQL launches background worker process like
- * autovacuum without authentication steps. So, we initialize sepgsql_mode
- * with SEPGSQL_MODE_INTERNAL, and client_label with the security context
- * of server process. Later, it also launches background of user session.
- * In this case, the process is always hooked on post-authentication, and
- * we can initialize the sepgsql_mode and client_label correctly.
- */
- if (getcon_raw(&context) < 0)
- ereport(ERROR,
- (errcode(ERRCODE_INTERNAL_ERROR),
- errmsg("SELinux: failed to get server security label: %m")));
- sepgsql_set_client_label(context);
+ /* Initialize userspace access vector cache */
+ sepgsql_avc_init();
+
+ /* Initialize security label of the client and related stuff */
+ sepgsql_init_client_label();
/* Security label provider hook */
register_label_provider(SEPGSQL_LABEL_TAG,
sepgsql_object_relabel);
- /* Client authentication hook */
- next_client_auth_hook = ClientAuthentication_hook;
- ClientAuthentication_hook = sepgsql_client_auth;
-
/* Object access hook */
next_object_access_hook = object_access_hook;
object_access_hook = sepgsql_object_access;
@@ -460,14 +432,14 @@ _PG_init(void)
next_exec_check_perms_hook = ExecutorCheckPerms_hook;
ExecutorCheckPerms_hook = sepgsql_exec_check_perms;
- /* Trusted procedure hooks */
- next_needs_fmgr_hook = needs_fmgr_hook;
- needs_fmgr_hook = sepgsql_needs_fmgr_hook;
-
- next_fmgr_hook = fmgr_hook;
- fmgr_hook = sepgsql_fmgr_hook;
-
/* ProcessUtility hook */
next_ProcessUtility_hook = ProcessUtility_hook;
ProcessUtility_hook = sepgsql_utility_command;
+
+ /* ExecutorStart hook */
+ next_ExecutorStart_hook = ExecutorStart_hook;
+ ExecutorStart_hook = sepgsql_executor_start;
+
+ /* init contextual info */
+ memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
}