Extend argument of OAT_POST_CREATE
The attached patch adds argument of OAT_POST_CREATE hook;
to inform extensions type of the context of this object creation. It allows
extensions to know whether the new object is indirectly created apart
from user's operations, or not.
I found out this flag is necessary to add feature to support selinux
checks on ALTER statement (with reasonably simple code) during
my investigation.
A table has various kind of properties; some of them are inlined in
pg_class but others are stored in extra catalogs such as pg_trigger,
pg_constraint and so on.
It might take an extra discussion whether trigger or constraint is
an independent object or an attribute of table. But, anyway, the
default permission checks table's ownership or ACLs when we
create or drop them. I don't think sepgsql should establish its own
object model here.
So, I want sepgsql to check table's "setattr" permission when user
create, drop or alter these objects.
In case of index creation, here are two cases a) user's operation
intend to create index, thus, checks permission of the table being
indexed on b) index is indirectly created as a result of other
operations like change of column's data type.
Due to same reason why we don't check permissions for cleanup
of temporary object, I don't want to apply checks on the later case.
Right now, sepgsql determines the current context using command
tag being saved at ProceddUtility_hook; to avoid permission checks
on table creation due to CLUSTER command for example.
But, it is not easy to apply this approach for the case of index
creation because it can be defined as a part of ALTER TABLE
which may have multiple sub-commands.
So, I want OAT_POST_CREATE hook to inform the current context
of the object creation; whether it is internal / indirect creation, or not.
This patch includes hook enhancement and "setattr" permission checks
on index creation / deletion.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-extend-post-create-hook.v1.patchapplication/octet-stream; name=sepgsql-v9.3-extend-post-create-hook.v1.patchDownload
contrib/sepgsql/expected/ddl.out | 53 ++++++++++++++
contrib/sepgsql/hooks.c | 82 +++++----------------
contrib/sepgsql/relation.c | 146 ++++++++++++++++++++++++++++++++++++-
contrib/sepgsql/sepgsql.h | 2 +-
contrib/sepgsql/sql/ddl.sql | 12 +++
doc/src/sgml/sepgsql.sgml | 7 ++
src/backend/bootstrap/bootparse.y | 1 +
src/backend/catalog/heap.c | 14 +++-
src/backend/catalog/index.c | 15 +++-
src/backend/catalog/toasting.c | 3 +-
src/backend/commands/cluster.c | 1 +
src/backend/commands/indexcmds.c | 2 +-
src/backend/commands/tablecmds.c | 3 +-
src/include/catalog/heap.h | 3 +-
src/include/catalog/index.h | 3 +-
src/include/catalog/objectaccess.h | 13 ++++
16 files changed, 284 insertions(+), 76 deletions(-)
diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out
index e7a8d9c..1f7ea88 100644
--- a/contrib/sepgsql/expected/ddl.out
+++ b/contrib/sepgsql/expected/ddl.out
@@ -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"
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index f3cf1c5..0c3feb4 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -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,14 +96,23 @@ sepgsql_object_access(ObjectAccessType access,
switch (access)
{
case OAT_POST_CREATE:
+ {
+ ObjectAccessPostCreate *post_create_arg = arg;
+ bool is_internal = false;
+
+ if (post_create_arg)
+ is_internal = post_create_arg->is_internal;
+
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;
@@ -113,25 +121,16 @@ sepgsql_object_access(ObjectAccessType access,
{
/*
* 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.
+ * creation of a new relation are invocation in the
+ * context being intended by users. Elsewhere, we
+ * need neither assignment of security label nor
+ * permission checks towards the case of toast
+ * relation or index rebuild due to ALTER TABLE.
*/
- 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;
- }
+ if (is_internal)
+ break;
+
+ sepgsql_relation_post_create(objectId);
}
else
sepgsql_attribute_post_create(objectId, subId);
@@ -145,6 +144,7 @@ sepgsql_object_access(ObjectAccessType access,
/* Ignore unsupported object classes */
break;
}
+ }
break;
case OAT_DROP:
@@ -216,46 +216,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
}
/*
- * 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
*
* It tries to rough-grained control on utility commands; some of them can
@@ -425,10 +385,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));
}
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 4ab7fc8..02b0af9 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -23,11 +23,14 @@
#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
*
@@ -201,8 +204,8 @@ sepgsql_relation_post_create(Oid relOid)
HeapTuple tuple;
Form_pg_class classForm;
ObjectAddress object;
- uint16 tclass;
- const char *tclass_text;
+ uint16 tclass = 0;
+ const char *tclass_text = NULL;
char *scontext; /* subject */
char *tcontext; /* schema */
char *rcontext; /* relation */
@@ -243,6 +246,9 @@ sepgsql_relation_post_create(Oid relOid)
tclass = SEPG_CLASS_DB_VIEW;
tclass_text = "view";
break;
+ case RELKIND_INDEX:
+ if (classForm->relnamespace != PG_TOAST_NAMESPACE)
+ break;
default:
goto out;
}
@@ -258,6 +264,17 @@ sepgsql_relation_post_create(Oid relOid)
SEPG_DB_SCHEMA__ADD_NAME,
getObjectDescription(&object),
true);
+ /*
+ * Index shall be handled as an extra attribute of the tables being
+ * indexed on, so it does not have its own security label and 'setattr'
+ * permission should be applied on the table, instead of 'create' on
+ * the index itself.
+ */
+ if (classForm->relkind == RELKIND_INDEX)
+ {
+ sepgsql_index_modify(relOid);
+ goto out;
+ }
/*
* Compute a default security label when we create a new relation object
@@ -367,7 +384,8 @@ sepgsql_relation_drop(Oid relOid)
tclass = SEPG_CLASS_DB_SEQUENCE;
else if (relkind == RELKIND_VIEW)
tclass = SEPG_CLASS_DB_VIEW;
- else
+ else if (relkind != RELKIND_INDEX ||
+ get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
return;
/*
@@ -386,6 +404,16 @@ sepgsql_relation_drop(Oid relOid)
pfree(audit_name);
/*
+ * We consider deletion of index should be handled as modifying extra
+ * attribute of the table being indexed.
+ */
+ if (relkind == RELKIND_INDEX)
+ {
+ sepgsql_index_modify(relOid);
+ return;
+ }
+
+ /*
* check db_table/sequence/view:{drop} permission
*/
object.classId = RelationRelationId;
@@ -486,3 +514,115 @@ 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;
+ char relkind;
+ uint16_t tclass = 0;
+
+ 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
+ {
+ if (relkind == RELKIND_INDEX)
+ sepgsql_index_modify(relOid);
+ return;
+ }
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectDescription(&object);
+
+ /*
+ * XXX - we should add check related to namespace stuff,
+ * when object_access_hook get support ALTER statement.
+ * Right now, here 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 entries of pg_index. As core PostgreSQL doing,
+ * sepgsql also does not deal with the entries as individual "object",
+ * thus, modification of these entries shall be considered as setting
+ * a particular attribute of 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
+ *
+ * handler when an index was created, dropped or updated; that checks
+ * setattr permission of the table being indexed on.
+ */
+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);
+}
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 9c89eaa..b6dcb86 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -145,7 +145,6 @@
#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
diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql
index 8dd57e0..5afe1ba 100644
--- a/contrib/sepgsql/sql/ddl.sql
+++ b/contrib/sepgsql/sql/ddl.sql
@@ -60,6 +60,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)
--
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index ff083a0..cd99ed1 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -450,6 +450,13 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
</para>
<para>
+ In case when an object that performs as extra attributes towards main
+ object, such as indexes or trigger, is created or dropped,
+ <literal>setattr</> permission will be checked on the main object,
+ instead of the extra attribute itself.
+ </para>
+
+ <para>
When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
and <literal>relabelfrom</> will be checked on the object being relabeled
with its old security label, then <literal>relabelto</> with the supplied
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index ec634f1..fd681dc 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -247,6 +247,7 @@ Boot_CreateStmt:
ONCOMMIT_NOOP,
(Datum) 0,
false,
+ true,
true);
elog(DEBUG4, "relation created with OID %u", id);
}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index c80df41..6edd11f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -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.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 464950b..f2a3a06 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -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.
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 1feffd2..2979819 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -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);
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index cfec413..de71a35 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -643,6 +643,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
ONCOMMIT_NOOP,
reloptions,
false,
+ true,
true);
Assert(OIDNewHeap != InvalidOid);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index a58101e..dd46cf9 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -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)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 359d478..378b29d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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);
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index bc8c63a..1465456 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -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);
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index eb417ce..298641b 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -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,
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 3b40dbc..b4b84a6 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -31,6 +31,19 @@ typedef enum ObjectAccessType
} 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
*/
typedef struct
Kohei KaiGai escribió:
The attached patch adds argument of OAT_POST_CREATE hook;
to inform extensions type of the context of this object creation. It allows
extensions to know whether the new object is indirectly created apart
from user's operations, or not.
Can we add Assert(!is_internal) to the ProcedureRelationId case in
sepgsql_object_access() too? I don't see any caller that would set it
true anywhere, but maybe you have a good reason for omitting it.
I'm not clear on what's sepgsql_relation_setattr for; it doesn't seem to
be called anywhere (other than sepgsql_relation_setattr_extra, but
that's static, so why isn't sepgsql_relation_setattr also static?). But
I notice that it calls sepgsql_index_modify without first checking for
the toast namespace like the other callers do. Is this okay or an
oversight?
I admit the new RELKIND_INDEX cases in various places make for strange
flow. Not sure how it can be improved though.
I didn't find anything wrong with the changes to src/backend. One thing
that I noticed is that when bootstrapping, all relation creation is
considered internal. I am sure this is okay fo the normal case, but I
wonder if a malicious superuser could get a hold of things that he
shouldn't by starting a bootstrapping backend and run relation creation
there.
Note: I can compile sepgsql but not run the regression tests.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Thanks for your reviews.
2012/10/10 Alvaro Herrera <alvherre@2ndquadrant.com>:
Kohei KaiGai escribió:
The attached patch adds argument of OAT_POST_CREATE hook;
to inform extensions type of the context of this object creation. It allows
extensions to know whether the new object is indirectly created apart
from user's operations, or not.Can we add Assert(!is_internal) to the ProcedureRelationId case in
sepgsql_object_access() too? I don't see any caller that would set it
true anywhere, but maybe you have a good reason for omitting it.
No, I just missed to add Assert() here.
I'm not clear on what's sepgsql_relation_setattr for; it doesn't seem to
be called anywhere (other than sepgsql_relation_setattr_extra, but
that's static, so why isn't sepgsql_relation_setattr also static?). But
I notice that it calls sepgsql_index_modify without first checking for
the toast namespace like the other callers do. Is this okay or an
oversight?
I assume sepgsql_relation_setattr is also called on ALTER TABLE
command; to check privilege to modify properties of the target table.
Entrypoint of the object_access_hook is at sepgsql/hooks.c, so this
function was declared without static for (near) future usage.
Regarding to toast relation/index, as default permission mechanism
doing, sepgsql handles toast is a pure-internal semantics, thus, no
security label is assigned and no permission checks are applied.
(Also, please check check_relation_privileges at sepgsql/dml.c.
It does not allow to reference toast relation using regular SQL
with hardwired rule, because of the nature of "internal stuff".)
I admit the new RELKIND_INDEX cases in various places make for strange
flow. Not sure how it can be improved though.
The idea is not so complicated. This code considers index is an
property of a certain table like as individual field of pg_class.
Relation is the most complex object in PostgreSQL. Its property
is not only ones in pg_class, but some extra catalogs such as
pg_trigger, pg_rewrite and so on.
The default permission checks ownership of the table, instead
of triggers, rules or indexes, when user tries to alter them.
Here is no good reason why sepgsql needs to give its own
definition of relation, so I just followed this manner.
I didn't find anything wrong with the changes to src/backend. One thing
that I noticed is that when bootstrapping, all relation creation is
considered internal. I am sure this is okay fo the normal case, but I
wonder if a malicious superuser could get a hold of things that he
shouldn't by starting a bootstrapping backend and run relation creation
there.
Yes, you are right. Even though it is harmless right now because we have
no way to load extension prior to initdb, it makes confusion if some built-in
feature used object access hook. The "internal" flag means the given SQL
statement does not intend creation itself of the target object, but bootstrap
command definitely intend to create initial objects.
On the other hand, I don't care about the scenario with malicious superuser
that runs initdb, because it is an assumption of sepgsql to set up initial
database on environment without something malicious.
If we try to prevent to create an initial database by malicious users, it should
be a responsibility of operating system and its policy.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-extend-post-create-hook.v2.patchapplication/octet-stream; name=sepgsql-v9.3-extend-post-create-hook.v2.patchDownload
contrib/sepgsql/expected/ddl.out | 53 ++++++++++++++
contrib/sepgsql/hooks.c | 83 +++++----------------
contrib/sepgsql/relation.c | 146 ++++++++++++++++++++++++++++++++++++-
contrib/sepgsql/sepgsql.h | 2 +-
contrib/sepgsql/sql/ddl.sql | 12 +++
doc/src/sgml/sepgsql.sgml | 7 ++
src/backend/bootstrap/bootparse.y | 3 +-
src/backend/catalog/heap.c | 14 +++-
src/backend/catalog/index.c | 15 +++-
src/backend/catalog/toasting.c | 3 +-
src/backend/commands/cluster.c | 1 +
src/backend/commands/indexcmds.c | 2 +-
src/backend/commands/tablecmds.c | 3 +-
src/include/catalog/heap.h | 3 +-
src/include/catalog/index.h | 3 +-
src/include/catalog/objectaccess.h | 13 ++++
16 files changed, 286 insertions(+), 77 deletions(-)
diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out
index e7a8d9c..1f7ea88 100644
--- a/contrib/sepgsql/expected/ddl.out
+++ b/contrib/sepgsql/expected/ddl.out
@@ -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"
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index f3cf1c5..b816812 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -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,14 +96,23 @@ sepgsql_object_access(ObjectAccessType access,
switch (access)
{
case OAT_POST_CREATE:
+ {
+ ObjectAccessPostCreate *post_create_arg = arg;
+ bool is_internal = false;
+
+ if (post_create_arg)
+ is_internal = post_create_arg->is_internal;
+
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;
@@ -113,31 +121,23 @@ sepgsql_object_access(ObjectAccessType access,
{
/*
* 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.
+ * creation of a new relation are invocation in the
+ * context being intended by users. Elsewhere, we
+ * need neither assignment of security label nor
+ * permission checks towards the case of toast
+ * relation or index rebuild due to ALTER TABLE.
*/
- 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;
- }
+ if (is_internal)
+ break;
+
+ sepgsql_relation_post_create(objectId);
}
else
sepgsql_attribute_post_create(objectId, subId);
break;
case ProcedureRelationId:
+ Assert(!is_internal);
sepgsql_proc_post_create(objectId);
break;
@@ -145,6 +145,7 @@ sepgsql_object_access(ObjectAccessType access,
/* Ignore unsupported object classes */
break;
}
+ }
break;
case OAT_DROP:
@@ -216,46 +217,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
}
/*
- * 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
*
* It tries to rough-grained control on utility commands; some of them can
@@ -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));
}
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 4ab7fc8..02b0af9 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -23,11 +23,14 @@
#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
*
@@ -201,8 +204,8 @@ sepgsql_relation_post_create(Oid relOid)
HeapTuple tuple;
Form_pg_class classForm;
ObjectAddress object;
- uint16 tclass;
- const char *tclass_text;
+ uint16 tclass = 0;
+ const char *tclass_text = NULL;
char *scontext; /* subject */
char *tcontext; /* schema */
char *rcontext; /* relation */
@@ -243,6 +246,9 @@ sepgsql_relation_post_create(Oid relOid)
tclass = SEPG_CLASS_DB_VIEW;
tclass_text = "view";
break;
+ case RELKIND_INDEX:
+ if (classForm->relnamespace != PG_TOAST_NAMESPACE)
+ break;
default:
goto out;
}
@@ -258,6 +264,17 @@ sepgsql_relation_post_create(Oid relOid)
SEPG_DB_SCHEMA__ADD_NAME,
getObjectDescription(&object),
true);
+ /*
+ * Index shall be handled as an extra attribute of the tables being
+ * indexed on, so it does not have its own security label and 'setattr'
+ * permission should be applied on the table, instead of 'create' on
+ * the index itself.
+ */
+ if (classForm->relkind == RELKIND_INDEX)
+ {
+ sepgsql_index_modify(relOid);
+ goto out;
+ }
/*
* Compute a default security label when we create a new relation object
@@ -367,7 +384,8 @@ sepgsql_relation_drop(Oid relOid)
tclass = SEPG_CLASS_DB_SEQUENCE;
else if (relkind == RELKIND_VIEW)
tclass = SEPG_CLASS_DB_VIEW;
- else
+ else if (relkind != RELKIND_INDEX ||
+ get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
return;
/*
@@ -386,6 +404,16 @@ sepgsql_relation_drop(Oid relOid)
pfree(audit_name);
/*
+ * We consider deletion of index should be handled as modifying extra
+ * attribute of the table being indexed.
+ */
+ if (relkind == RELKIND_INDEX)
+ {
+ sepgsql_index_modify(relOid);
+ return;
+ }
+
+ /*
* check db_table/sequence/view:{drop} permission
*/
object.classId = RelationRelationId;
@@ -486,3 +514,115 @@ 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;
+ char relkind;
+ uint16_t tclass = 0;
+
+ 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
+ {
+ if (relkind == RELKIND_INDEX)
+ sepgsql_index_modify(relOid);
+ return;
+ }
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectDescription(&object);
+
+ /*
+ * XXX - we should add check related to namespace stuff,
+ * when object_access_hook get support ALTER statement.
+ * Right now, here 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 entries of pg_index. As core PostgreSQL doing,
+ * sepgsql also does not deal with the entries as individual "object",
+ * thus, modification of these entries shall be considered as setting
+ * a particular attribute of 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
+ *
+ * handler when an index was created, dropped or updated; that checks
+ * setattr permission of the table being indexed on.
+ */
+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);
+}
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 9c89eaa..b6dcb86 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -145,7 +145,6 @@
#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
diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql
index 8dd57e0..5afe1ba 100644
--- a/contrib/sepgsql/sql/ddl.sql
+++ b/contrib/sepgsql/sql/ddl.sql
@@ -60,6 +60,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)
--
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index ff083a0..cd99ed1 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -450,6 +450,13 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
</para>
<para>
+ In case when an object that performs as extra attributes towards main
+ object, such as indexes or trigger, is created or dropped,
+ <literal>setattr</> permission will be checked on the main object,
+ instead of the extra attribute itself.
+ </para>
+
+ <para>
When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
and <literal>relabelfrom</> will be checked on the object being relabeled
with its old security label, then <literal>relabelto</> with the supplied
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index ec634f1..ec7786a 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -247,7 +247,8 @@ Boot_CreateStmt:
ONCOMMIT_NOOP,
(Datum) 0,
false,
- true);
+ true,
+ false);
elog(DEBUG4, "relation created with OID %u", id);
}
do_end();
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index c80df41..6edd11f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -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.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 464950b..f2a3a06 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -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.
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 1feffd2..2979819 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -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);
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index cfec413..de71a35 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -643,6 +643,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
ONCOMMIT_NOOP,
reloptions,
false,
+ true,
true);
Assert(OIDNewHeap != InvalidOid);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index a58101e..dd46cf9 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -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)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 359d478..378b29d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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);
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index bc8c63a..1465456 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -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);
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index eb417ce..298641b 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -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,
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 3b40dbc..b4b84a6 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -31,6 +31,19 @@ typedef enum ObjectAccessType
} 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
*/
typedef struct
Kohei KaiGai escribió:
2012/10/10 Alvaro Herrera <alvherre@2ndquadrant.com>:
I admit the new RELKIND_INDEX cases in various places make for strange
flow. Not sure how it can be improved though.The idea is not so complicated. This code considers index is an
property of a certain table like as individual field of pg_class.
Relation is the most complex object in PostgreSQL. Its property
is not only ones in pg_class, but some extra catalogs such as
pg_trigger, pg_rewrite and so on.
I have pushed this patch with some slight changes in the way
the RELKIND_INDEX case is handled in various places, to make it
clearer. I may have broken some cases; please have a look.
Thanks.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services