]> granicus.if.org Git - postgresql/commitdiff
sepgsql: Move some code from hooks.c to label.c
authorRobert Haas <rhaas@postgresql.org>
Wed, 15 Feb 2012 18:54:26 +0000 (13:54 -0500)
committerRobert Haas <rhaas@postgresql.org>
Wed, 15 Feb 2012 18:54:26 +0000 (13:54 -0500)
This is some preliminary refactoring related to a pending patch
to allow sepgsql-enable sessions to make dynamic label transitions.
But this commit doesn't involve any functional change: it just puts
some bits of code in more logical places.

KaiGai Kohei

contrib/sepgsql/hooks.c
contrib/sepgsql/label.c
contrib/sepgsql/sepgsql.h

index 47437ba5b312eb344f40715e5663b9dccb55653c..70934950e51d32454df010cd0a43b8101d146f06 100644 (file)
@@ -18,7 +18,6 @@
 #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"
@@ -36,10 +35,7 @@ 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;
 
@@ -81,48 +77,6 @@ sepgsql_get_debug_audit(void)
        return sepgsql_debug_audit;
 }
 
-/*
- * 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
  *
@@ -220,121 +174,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
        return true;
 }
 
-/*
- * sepgsql_needs_fmgr_hook
- *
- * 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.
- */
-static bool
-sepgsql_needs_fmgr_hook(Oid functionId)
-{
-       ObjectAddress   object;
-
-       if (next_needs_fmgr_hook &&
-               (*next_needs_fmgr_hook) (functionId))
-               return true;
-
-       /*
-        * 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.
-        */
-       if (sepgsql_avc_trusted_proc(functionId) != NULL)
-               return true;
-
-       /*
-        * 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.
-        */
-       object.classId = ProcedureRelationId;
-       object.objectId = functionId;
-       object.objectSubId = 0;
-       if (!sepgsql_avc_check_perms(&object,
-                                                                SEPG_CLASS_DB_PROCEDURE,
-                                                                SEPG_DB_PROCEDURE__EXECUTE,
-                                                                SEPGSQL_AVC_NOAUDIT, false))
-               return true;
-
-       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)
-       {
-               case FHET_START:
-                       stack = (void *) DatumGetPointer(*private);
-                       if (!stack)
-                       {
-                               MemoryContext oldcxt;
-
-                               oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
-                               stack = palloc(sizeof(*stack));
-                               stack->old_label = NULL;
-                               stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
-                               stack->next_private = 0;
-
-                               MemoryContextSwitchTo(oldcxt);
-
-                               /*
-                                * process:transition permission between old and new label,
-                                * when user tries to switch security label of the client
-                                * on execution of trusted procedure.
-                                */
-                               if (stack->new_label)
-                                       sepgsql_avc_check_perms_label(stack->new_label,
-                                                                                                 SEPG_CLASS_PROCESS,
-                                                                                                 SEPG_PROCESS__TRANSITION,
-                                                                                                 NULL, true);
-
-                               *private = PointerGetDatum(stack);
-                       }
-                       Assert(!stack->old_label);
-                       if (stack->new_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);
-
-                       if (stack->old_label)
-                               sepgsql_set_client_label(stack->old_label);
-                       stack->old_label = NULL;
-                       break;
-
-               default:
-                       elog(ERROR, "unexpected event type: %d", (int) event);
-                       break;
-       }
-}
-
 /*
  * sepgsql_executor_start
  *
@@ -465,8 +304,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.
@@ -522,33 +359,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;
@@ -557,13 +377,6 @@ _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;
index 2ab7a6f20359b28bdbc98cf60cda0aef35da884f..340bec6864caaa81777e404bbea1457a16357425 100644 (file)
@@ -22,6 +22,7 @@
 #include "catalog/pg_proc.h"
 #include "commands/dbcommands.h"
 #include "commands/seclabel.h"
+#include "libpq/auth.h"
 #include "libpq/libpq-be.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
 
 #include <selinux/label.h>
 
+/*
+ * Saved hook entries (if stacked)
+ */
+static ClientAuthentication_hook_type next_client_auth_hook = NULL;
+static needs_fmgr_hook_type next_needs_fmgr_hook = NULL;
+static fmgr_hook_type next_fmgr_hook = NULL;
+
 /*
  * client_label
  *
@@ -47,14 +55,197 @@ sepgsql_get_client_label(void)
        return client_label;
 }
 
-char *
-sepgsql_set_client_label(char *new_label)
+/*
+ * 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)
+{
+       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, &client_label) < 0)
+               ereport(FATAL,
+                               (errcode(ERRCODE_INTERNAL_ERROR),
+                                errmsg("SELinux: unable to get peer label: %m")));
+
+       /*
+        * Switch the current performing mode from INTERNAL to either DEFAULT or
+        * PERMISSIVE.
+        */
+       if (sepgsql_get_permissive())
+               sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE);
+       else
+               sepgsql_set_mode(SEPGSQL_MODE_DEFAULT);
+}
+
+/*
+ * sepgsql_needs_fmgr_hook
+ *
+ * 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.
+ */
+static bool
+sepgsql_needs_fmgr_hook(Oid functionId)
 {
-       char       *old_label = client_label;
+       ObjectAddress   object;
+
+       if (next_needs_fmgr_hook &&
+               (*next_needs_fmgr_hook) (functionId))
+               return true;
+
+       /*
+        * 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.
+        */
+       if (sepgsql_avc_trusted_proc(functionId) != NULL)
+               return true;
+
+       /*
+        * 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.
+        */
+       object.classId = ProcedureRelationId;
+       object.objectId = functionId;
+       object.objectSubId = 0;
+       if (!sepgsql_avc_check_perms(&object,
+                                                                SEPG_CLASS_DB_PROCEDURE,
+                                                                SEPG_DB_PROCEDURE__EXECUTE,
+                                                                SEPGSQL_AVC_NOAUDIT, false))
+               return true;
+
+       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)
+       {
+               case FHET_START:
+                       stack = (void *) DatumGetPointer(*private);
+                       if (!stack)
+                       {
+                               MemoryContext oldcxt;
+
+                               oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
+                               stack = palloc(sizeof(*stack));
+                               stack->old_label = NULL;
+                               stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
+                               stack->next_private = 0;
+
+                               MemoryContextSwitchTo(oldcxt);
+
+                               /*
+                                * process:transition permission between old and new label,
+                                * when user tries to switch security label of the client
+                                * on execution of trusted procedure.
+                                */
+                               if (stack->new_label)
+                                       sepgsql_avc_check_perms_label(stack->new_label,
+                                                                                                 SEPG_CLASS_PROCESS,
+                                                                                                 SEPG_PROCESS__TRANSITION,
+                                                                                                 NULL, true);
+
+                               *private = PointerGetDatum(stack);
+                       }
+                       Assert(!stack->old_label);
+                       if (stack->new_label)
+                       {
+                               stack->old_label = client_label;
+                               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);
+
+                       if (stack->new_label)
+                       {
+                               client_label = stack->old_label;
+                               stack->old_label = NULL;
+                       }
+                       break;
+
+               default:
+                       elog(ERROR, "unexpected event type: %d", (int) event);
+                       break;
+       }
+}
+
+/*
+ * sepgsql_init_client_label
+ *
+ * This routine initialize security label of the client, and set up related
+ * hooks to be invoked later.
+ */
+void
+sepgsql_init_client_label(void)
+{
+       /*
+        * 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(&client_label) < 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INTERNAL_ERROR),
+                                errmsg("SELinux: failed to get server security label: %m")));
+
+       /* Client authentication hook */
+       next_client_auth_hook = ClientAuthentication_hook;
+       ClientAuthentication_hook = sepgsql_client_auth;
 
-       client_label = new_label;
+       /* Trusted procedure hooks */
+       next_needs_fmgr_hook = needs_fmgr_hook;
+       needs_fmgr_hook = sepgsql_needs_fmgr_hook;
 
-       return old_label;
+       next_fmgr_hook = fmgr_hook;
+       fmgr_hook = sepgsql_fmgr_hook;
 }
 
 /*
index c93da7ad70b172354b7e91ef7155ec72823d6cbb..9ce8d2d9c482abca928e88508a99d1486f3bda20 100644 (file)
@@ -267,7 +267,7 @@ extern void sepgsql_avc_init(void);
  * label.c
  */
 extern char *sepgsql_get_client_label(void);
-extern char *sepgsql_set_client_label(char *new_label);
+extern void  sepgsql_init_client_label(void);
 extern char *sepgsql_get_label(Oid relOid, Oid objOid, int32 subId);
 
 extern void sepgsql_object_relabel(const ObjectAddress *object,