]> granicus.if.org Git - postgresql/commitdiff
Add context info to OAT_POST_CREATE security hook
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 23 Oct 2012 21:07:26 +0000 (18:07 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 23 Oct 2012 21:24:24 +0000 (18:24 -0300)
... and have sepgsql use it to determine whether to check permissions
during certain operations.  Indexes that are being created as a result
of REINDEX, for instance, do not need to have their permissions checked;
they were already checked when the index was created.

Author: KaiGai Kohei, slightly revised by me

16 files changed:
contrib/sepgsql/expected/ddl.out
contrib/sepgsql/hooks.c
contrib/sepgsql/relation.c
contrib/sepgsql/sepgsql.h
contrib/sepgsql/sql/ddl.sql
doc/src/sgml/sepgsql.sgml
src/backend/bootstrap/bootparse.y
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/toasting.c
src/backend/commands/cluster.c
src/backend/commands/indexcmds.c
src/backend/commands/tablecmds.c
src/include/catalog/heap.h
src/include/catalog/index.h
src/include/catalog/objectaccess.h

index e7a8d9c3012244368954c7bbedbace81105942d4..1f7ea886b00227b103680d427c14da12f082ef80 100644 (file)
@@ -34,6 +34,8 @@ LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column ctid"
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column x"
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column y"
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
 ALTER TABLE regtest_table ADD COLUMN z int;
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column z"
 CREATE TABLE regtest_table_2 (a int) WITH OIDS;
@@ -93,6 +95,55 @@ LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfine
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_func_2(integer)"
 RESET SESSION AUTHORIZATION;
 --
+-- ALTER and CREATE/DROP extra attribute permissions
+--
+CREATE TABLE regtest_table_4 (x int primary key, y int, z int);
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column tableoid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column cmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column xmax"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column cmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column xmin"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column ctid"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column x"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column y"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column z"
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
+DROP INDEX regtest_index_tbl4_y;
+LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+ALTER TABLE regtest_table_4
+      ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+DROP TABLE regtest_table_4 CASCADE;
+LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column tableoid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column cmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column xmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column cmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column xmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column ctid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column x"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column y"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column z"
+--
 -- DROP Permission checks (with clean-up)
 --
 DROP FUNCTION regtest_func(text,int[]);
@@ -115,6 +166,8 @@ DROP TABLE regtest_table;
 LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
 LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq"
 LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
+LOG:  SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
 LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
 LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column tableoid"
 LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmax"
index f3cf1c5f88c5551230f66a15fa1d14963ee6d81b..ab55d6ea4b82c2518eedefea0308608b3b3af46b 100644 (file)
@@ -38,7 +38,6 @@ void          _PG_init(void);
 static object_access_hook_type next_object_access_hook = NULL;
 static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
 static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
-static ExecutorStart_hook_type next_ExecutorStart_hook = NULL;
 
 /*
  * Contextual information on DDL commands
@@ -97,53 +96,55 @@ sepgsql_object_access(ObjectAccessType access,
        switch (access)
        {
                case OAT_POST_CREATE:
-                       switch (classId)
                        {
-                               case DatabaseRelationId:
-                                       sepgsql_database_post_create(objectId,
-                                                                       sepgsql_context_info.createdb_dtemplate);
-                                       break;
+                               ObjectAccessPostCreate *pc_arg = arg;
+                               bool    is_internal;
 
-                               case NamespaceRelationId:
-                                       sepgsql_schema_post_create(objectId);
-                                       break;
+                               is_internal = pc_arg ? pc_arg->is_internal : false;
 
-                               case RelationRelationId:
-                                       if (subId == 0)
-                                       {
-                                               /*
-                                                * 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)
+                               switch (classId)
+                               {
+                                       case DatabaseRelationId:
+                                               Assert(!is_internal);
+                                               sepgsql_database_post_create(objectId,
+                                                                                                        sepgsql_context_info.createdb_dtemplate);
+                                               break;
+
+                                       case NamespaceRelationId:
+                                               Assert(!is_internal);
+                                               sepgsql_schema_post_create(objectId);
+                                               break;
+
+                                       case RelationRelationId:
+                                               if (subId == 0)
                                                {
-                                                       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() */
+                                                       /*
+                                                        * The cases in which we want to apply permission
+                                                        * checks on creation of a new relation correspond
+                                                        * to direct user invocation.  For internal uses,
+                                                        * that is creation of toast tables, index rebuild
+                                                        * or ALTER TABLE commands, we need neither
+                                                        * assignment of security labels nor permission
+                                                        * checks.
+                                                        */
+                                                       if (is_internal)
                                                                break;
+
+                                                       sepgsql_relation_post_create(objectId);
                                                }
-                                       }
-                                       else
-                                               sepgsql_attribute_post_create(objectId, subId);
-                                       break;
+                                               else
+                                                       sepgsql_attribute_post_create(objectId, subId);
+                                               break;
 
-                               case ProcedureRelationId:
-                                       sepgsql_proc_post_create(objectId);
-                                       break;
+                                       case ProcedureRelationId:
+                                               Assert(!is_internal);
+                                               sepgsql_proc_post_create(objectId);
+                                               break;
 
-                               default:
-                                       /* Ignore unsupported object classes */
-                                       break;
+                                       default:
+                                               /* Ignore unsupported object classes */
+                                               break;
+                               }
                        }
                        break;
 
@@ -215,46 +216,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
        return true;
 }
 
-/*
- * sepgsql_executor_start
- *
- * It saves contextual information during ExecutorStart to distinguish
- * a case with/without permission checks later.
- */
-static void
-sepgsql_executor_start(QueryDesc *queryDesc, int eflags)
-{
-       sepgsql_context_info_t saved_context_info = sepgsql_context_info;
-
-       PG_TRY();
-       {
-               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);
-       }
-       PG_CATCH();
-       {
-               sepgsql_context_info = saved_context_info;
-               PG_RE_THROW();
-       }
-       PG_END_TRY();
-       sepgsql_context_info = saved_context_info;
-}
-
 /*
  * sepgsql_utility_command
  *
@@ -425,10 +386,6 @@ _PG_init(void)
        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));
 }
index 4ab7fc8be94e039dfc60445a7de5dbab9fdfe626..783f330d1cec4310dae6c99bae07092a541ccdad 100644 (file)
 #include "utils/fmgroids.h"
 #include "utils/catcache.h"
 #include "utils/lsyscache.h"
+#include "utils/rel.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
 #include "sepgsql.h"
 
+static void            sepgsql_index_modify(Oid indexOid);
+
 /*
  * sepgsql_attribute_post_create
  *
@@ -229,6 +232,23 @@ sepgsql_relation_post_create(Oid relOid)
 
        classForm = (Form_pg_class) GETSTRUCT(tuple);
 
+       /* ignore indexes on toast tables */
+       if (classForm->relkind == RELKIND_INDEX &&
+               classForm->relnamespace == PG_TOAST_NAMESPACE)
+               goto out;
+
+       /*
+        * check db_schema:{add_name} permission of the namespace
+        */
+       object.classId = NamespaceRelationId;
+       object.objectId = classForm->relnamespace;
+       object.objectSubId = 0;
+       sepgsql_avc_check_perms(&object,
+                                                       SEPG_CLASS_DB_SCHEMA,
+                                                       SEPG_DB_SCHEMA__ADD_NAME,
+                                                       getObjectDescription(&object),
+                                                       true);
+
        switch (classForm->relkind)
        {
                case RELKIND_RELATION:
@@ -243,22 +263,15 @@ sepgsql_relation_post_create(Oid relOid)
                        tclass = SEPG_CLASS_DB_VIEW;
                        tclass_text = "view";
                        break;
+               case RELKIND_INDEX:
+                       /* deal with indexes specially; no need for tclass */
+                       sepgsql_index_modify(relOid);
+                       goto out;
                default:
+                       /* ignore other relkinds */
                        goto out;
        }
 
-       /*
-        * check db_schema:{add_name} permission of the namespace
-        */
-       object.classId = NamespaceRelationId;
-       object.objectId = classForm->relnamespace;
-       object.objectSubId = 0;
-       sepgsql_avc_check_perms(&object,
-                                                       SEPG_CLASS_DB_SCHEMA,
-                                                       SEPG_DB_SCHEMA__ADD_NAME,
-                                                       getObjectDescription(&object),
-                                                       true);
-
        /*
         * Compute a default security label when we create a new relation object
         * under the specified namespace.
@@ -342,6 +355,7 @@ sepgsql_relation_post_create(Oid relOid)
                heap_close(arel, AccessShareLock);
        }
        pfree(rcontext);
+
 out:
        systable_endscan(sscan);
        heap_close(rel, AccessShareLock);
@@ -357,18 +371,31 @@ sepgsql_relation_drop(Oid relOid)
 {
        ObjectAddress object;
        char       *audit_name;
-       uint16_t        tclass = 0;
+       uint16_t        tclass;
        char            relkind;
 
        relkind = get_rel_relkind(relOid);
-       if (relkind == RELKIND_RELATION)
-               tclass = SEPG_CLASS_DB_TABLE;
-       else if (relkind == RELKIND_SEQUENCE)
-               tclass = SEPG_CLASS_DB_SEQUENCE;
-       else if (relkind == RELKIND_VIEW)
-               tclass = SEPG_CLASS_DB_VIEW;
-       else
-               return;
+       switch (relkind)
+       {
+               case RELKIND_RELATION:
+                       tclass = SEPG_CLASS_DB_TABLE;
+                       break;
+               case RELKIND_SEQUENCE:
+                       tclass = SEPG_CLASS_DB_SEQUENCE;
+                       break;
+               case RELKIND_VIEW:
+                       tclass = SEPG_CLASS_DB_VIEW;
+                       break;
+               case RELKIND_INDEX:
+                       /* ignore indexes on toast tables */
+                       if (get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
+                               return;
+                       /* other indexes are handled specially below; no need for tclass */
+                       break;
+               default:
+                       /* ignore other relkinds */
+                       return;
+       }
 
        /*
         * check db_schema:{remove_name} permission
@@ -385,6 +412,13 @@ sepgsql_relation_drop(Oid relOid)
                                                        true);
        pfree(audit_name);
 
+       /* deal with indexes specially */
+       if (relkind == RELKIND_INDEX)
+       {
+               sepgsql_index_modify(relOid);
+               return;
+       }
+
        /*
         * check db_table/sequence/view:{drop} permission
         */
@@ -486,3 +520,121 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
                                                                  true);
        pfree(audit_name);
 }
+
+/*
+ * sepgsql_relation_setattr
+ *
+ * It checks privileges to set attribute of the supplied relation
+ */
+void
+sepgsql_relation_setattr(Oid relOid)
+{
+       ObjectAddress object;
+       char       *audit_name;
+       uint16_t        tclass;
+
+       switch (get_rel_relkind(relOid))
+       {
+               case RELKIND_RELATION:
+                       tclass = SEPG_CLASS_DB_TABLE;
+                       break;
+               case RELKIND_SEQUENCE:
+                       tclass = SEPG_CLASS_DB_SEQUENCE;
+                       break;
+               case RELKIND_VIEW:
+                       tclass = SEPG_CLASS_DB_VIEW;
+                       break;
+               case RELKIND_INDEX:
+                       /* deal with indexes specially */
+                       sepgsql_index_modify(relOid);
+                       return;
+               default:
+                       /* other relkinds don't need additional work */
+                       return;
+       }
+
+       object.classId = RelationRelationId;
+       object.objectId = relOid;
+       object.objectSubId = 0;
+       audit_name = getObjectDescription(&object);
+
+       /*
+        * XXX - we should add checks related to namespace stuff, when
+        * object_access_hook get support for ALTER statement.  Right now, there is
+        * no invocation path on ALTER ...  RENAME TO / SET SCHEMA.
+        */
+
+       /*
+        * check db_xxx:{setattr} permission
+        */
+       sepgsql_avc_check_perms(&object,
+                                                       tclass,
+                                                       SEPG_DB_TABLE__SETATTR,
+                                                       audit_name,
+                                                       true);
+       pfree(audit_name);
+}
+
+/*
+ * sepgsql_relation_setattr_extra
+ *
+ * It checks permission of the relation being referenced by extra attributes,
+ * such as pg_index entries. Like core PostgreSQL, sepgsql also does not deal
+ * with such entries as individual "objects", thus, modification of these
+ * entries shall be considered as setting an attribute of the underlying
+ * relation.
+ */
+static void
+sepgsql_relation_setattr_extra(Relation catalog,
+                                                          Oid catindex_id,
+                                                          Oid extra_oid,
+                                                          AttrNumber anum_relation_id,
+                                                          AttrNumber anum_extra_id)
+{
+       ScanKeyData     skey;
+       SysScanDesc     sscan;
+       HeapTuple       tuple;
+       Datum           datum;
+       bool            isnull;
+
+       ScanKeyInit(&skey, anum_extra_id,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(extra_oid));
+
+       sscan = systable_beginscan(catalog, catindex_id, true,
+                                                          SnapshotSelf, 1, &skey);
+       tuple = systable_getnext(sscan);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "catalog lookup failed for object %u in catalog \"%s\"",
+                        extra_oid, RelationGetRelationName(catalog));
+
+       datum = heap_getattr(tuple, anum_relation_id,
+                                                RelationGetDescr(catalog), &isnull);
+       Assert(!isnull);
+
+       sepgsql_relation_setattr(DatumGetObjectId(datum));
+
+       systable_endscan(sscan);
+}
+
+/*
+ * sepgsql_index_modify
+ *             Handle index create, update, drop
+ *
+ * Unlike other relation kinds, indexes do not have their own security labels,
+ * so instead of doing checks directly, treat them as extra attributes of their
+ * owning tables; so check 'setattr' permissions on the table.
+ */
+static void
+sepgsql_index_modify(Oid indexOid)
+{
+       Relation        catalog = heap_open(IndexRelationId, AccessShareLock);
+
+       /* check db_table:{setattr} permission of the table being indexed */
+       sepgsql_relation_setattr_extra(catalog,
+                                                                  IndexRelidIndexId,
+                                                                  indexOid,
+                                                                  Anum_pg_index_indrelid,
+                                                                  Anum_pg_index_indexrelid);
+       heap_close(catalog, AccessShareLock);
+}
index 9c89eaa8938ce7f3d341a86e607a0d609ef09bfe..b6dcb86e55a8bd78248c433ad79366710cd4c6d0 100644 (file)
 #define SEPG_DB_TABLE__INSERT                          (1<<8)
 #define SEPG_DB_TABLE__DELETE                          (1<<9)
 #define SEPG_DB_TABLE__LOCK                                    (1<<10)
-#define SEPG_DB_TABLE__INDEXON                         (1<<11)
 
 #define SEPG_DB_SEQUENCE__CREATE                       (SEPG_DB_DATABASE__CREATE)
 #define SEPG_DB_SEQUENCE__DROP                         (SEPG_DB_DATABASE__DROP)
@@ -312,6 +311,7 @@ extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 extern void sepgsql_relation_post_create(Oid relOid);
 extern void sepgsql_relation_drop(Oid relOid);
 extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
+extern void sepgsql_relation_setattr(Oid relOid);
 
 /*
  * proc.c
index 8dd57e0eaf4143107d784881a4171669297d4498..5afe1ba193cf4861b6b5786c8fb8020ca9a1118d 100644 (file)
@@ -59,6 +59,18 @@ CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql
 
 RESET SESSION AUTHORIZATION;
 
+--
+-- ALTER and CREATE/DROP extra attribute permissions
+--
+CREATE TABLE regtest_table_4 (x int primary key, y int, z int);
+CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
+CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
+ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
+DROP INDEX regtest_index_tbl4_y;
+ALTER TABLE regtest_table_4
+      ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
+DROP TABLE regtest_table_4 CASCADE;
+
 --
 -- DROP Permission checks (with clean-up)
 --
index ff083a06596be4313bda7c330523a205be27a5ce..522aa8b9903b72f959406f8e0f347bd58095f404 100644 (file)
@@ -449,6 +449,12 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
     <literal>remove_name</> on the schema.
    </para>
 
+   <para>
+    When objects that are subsidiary of other objects (such as a table's indexes
+    or triggers) are created or dropped, <literal>setattr</> permission will be
+    checked on the main object, instead of the subsidiary object itself.
+   </para>
+
    <para>
     When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
     and <literal>relabelfrom</> will be checked on the object being relabeled
index ec634f1660e0be883b451abbb380d6dc30e69b93..ec7786a2ae136e1caa98e5874eeead2036832a76 100644 (file)
@@ -247,7 +247,8 @@ Boot_CreateStmt:
                                                                                                          ONCOMMIT_NOOP,
                                                                                                          (Datum) 0,
                                                                                                          false,
-                                                                                                         true);
+                                                                                                         true,
+                                                                                                         false);
                                                elog(DEBUG4, "relation created with OID %u", id);
                                        }
                                        do_end();
index c80df418fafeff925e4687b0b2cb7dce92e75dd5..6edd11fb98679be7ddf138e224dbd43a8e63275d 100644 (file)
@@ -985,7 +985,8 @@ heap_create_with_catalog(const char *relname,
                                                 OnCommitAction oncommit,
                                                 Datum reloptions,
                                                 bool use_user_acl,
-                                                bool allow_system_table_mods)
+                                                bool allow_system_table_mods,
+                                                bool is_internal)
 {
        Relation        pg_class_desc;
        Relation        new_rel_desc;
@@ -1275,8 +1276,15 @@ heap_create_with_catalog(const char *relname,
        }
 
        /* Post creation hook for new relation */
-       InvokeObjectAccessHook(OAT_POST_CREATE,
-                                                  RelationRelationId, relid, 0, NULL);
+       if (object_access_hook)
+       {
+               ObjectAccessPostCreate  post_create_args;
+
+               memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
+               post_create_args.is_internal = is_internal;
+               (*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
+                                                         relid, 0, &post_create_args);
+    }
 
        /*
         * Store any supplied constraints and defaults.
index 972a528aec5381a09a990a088d8e1fc97c86165b..756f6d918b00d8ec909229ae2e8b4a8cc210e2ff 100644 (file)
@@ -33,6 +33,7 @@
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_operator.h"
@@ -686,7 +687,8 @@ index_create(Relation heapRelation,
                         bool initdeferred,
                         bool allow_system_table_mods,
                         bool skip_build,
-                        bool concurrent)
+                        bool concurrent,
+                        bool is_internal)
 {
        Oid                     heapRelationId = RelationGetRelid(heapRelation);
        Relation        pg_class;
@@ -1018,6 +1020,17 @@ index_create(Relation heapRelation,
                Assert(!initdeferred);
        }
 
+       /* Post creation hook for new index */
+       if (object_access_hook)
+       {
+               ObjectAccessPostCreate  post_create_args;
+
+               memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
+               post_create_args.is_internal = is_internal;
+               (*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
+                                                         indexRelationId, 0, &post_create_args);
+       }
+
        /*
         * Advance the command counter so that we can see the newly-entered
         * catalog tuples for the index.
index 1feffd25efa149795619046b437c20364d853acb..2979819e966b2aed45f29a33be413962df18fcf9 100644 (file)
@@ -226,6 +226,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
                                                                                   ONCOMMIT_NOOP,
                                                                                   reloptions,
                                                                                   false,
+                                                                                  true,
                                                                                   true);
        Assert(toast_relid != InvalidOid);
 
@@ -279,7 +280,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
                                 rel->rd_rel->reltablespace,
                                 collationObjectId, classObjectId, coloptions, (Datum) 0,
                                 true, false, false, false,
-                                true, false, false);
+                                true, false, false, true);
 
        heap_close(toast_rel, NoLock);
 
index cfec413d54fbc94433d559390b96f349cf1df95b..de71a3594d48302b4b6be801ad383a2f509bdd6d 100644 (file)
@@ -643,6 +643,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
                                                                                  ONCOMMIT_NOOP,
                                                                                  reloptions,
                                                                                  false,
+                                                                                 true,
                                                                                  true);
        Assert(OIDNewHeap != InvalidOid);
 
index a58101ec6e5822d15b859c78bdf1585b11229562..dd46cf93dad8b32bfea63cf699a026c2f7f8681a 100644 (file)
@@ -596,7 +596,7 @@ DefineIndex(IndexStmt *stmt,
                                         stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
                                         allowSystemTableMods,
                                         skip_build || stmt->concurrent,
-                                        stmt->concurrent);
+                                        stmt->concurrent, !check_rights);
 
        /* Add any requested comment */
        if (stmt->idxcomment != NULL)
index 359d478592b2528211f1556a75900ffd77594a77..378b29d5250a640b4038a8025f73bd5e6f0aaf02 100644 (file)
@@ -630,7 +630,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
                                                                                  stmt->oncommit,
                                                                                  reloptions,
                                                                                  true,
-                                                                                 allowSystemTableMods);
+                                                                                 allowSystemTableMods,
+                                                                                 false);
 
        /* Store inheritance information for new rel. */
        StoreCatalogInheritance(relationId, inheritOids);
index bc8c63a15e1c72f3e999e021970919abc054636e..1465456cc7d1498d824745d5d500f1f4fac1c17d 100644 (file)
@@ -66,7 +66,8 @@ extern Oid heap_create_with_catalog(const char *relname,
                                                 OnCommitAction oncommit,
                                                 Datum reloptions,
                                                 bool use_user_acl,
-                                                bool allow_system_table_mods);
+                                                bool allow_system_table_mods,
+                                                bool is_internal);
 
 extern void heap_create_init_fork(Relation rel);
 
index eb417cecb7493b0386e9d47ae114242a2334e97f..298641baf7c1f3a8034df0161596a16efdaa0268 100644 (file)
@@ -50,7 +50,8 @@ extern Oid index_create(Relation heapRelation,
                         bool initdeferred,
                         bool allow_system_table_mods,
                         bool skip_build,
-                        bool concurrent);
+                        bool concurrent,
+                        bool is_internal);
 
 extern void index_constraint_create(Relation heapRelation,
                                                Oid indexRelationId,
index 3b40dbc492329b90e449df3386d154253ace570c..b4b84a64d05d15e2cecd2d2c4bd893f8dee1caac 100644 (file)
@@ -30,6 +30,19 @@ typedef enum ObjectAccessType
        OAT_DROP,
 } ObjectAccessType;
 
+/*
+ * Arguments of OAT_POST_CREATE event
+ */
+typedef struct
+{
+       /*
+        * This flag informs extensions whether the context of this creation
+        * is invoked by user's operations, or not. E.g, it shall be dealt
+        * as internal stuff on toast tables or indexes due to type changes.
+        */
+       bool            is_internal;
+} ObjectAccessPostCreate;
+
 /*
  * Arguments of OAT_DROP event
  */