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; + In case when an object that performs as extra attributes towards main + object, such as indexes or trigger, is created or dropped, + setattr permission will be checked on the main object, + instead of the extra attribute itself. + + + When is executed, setattr and relabelfrom will be checked on the object being relabeled with its old security label, then 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