mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
Add context info to OAT_POST_CREATE security hook
... and have sepgsql use it to determine whether to check permissions during certain operations. Indexes that are being created as a result of REINDEX, for instance, do not need to have their permissions checked; they were already checked when the index was created. Author: KaiGai Kohei, slightly revised by me
This commit is contained in:
parent
4c9d0901f1
commit
f4c4335a4a
@ -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"
|
||||
|
@ -38,7 +38,6 @@ void _PG_init(void);
|
||||
static object_access_hook_type next_object_access_hook = NULL;
|
||||
static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
|
||||
static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
|
||||
static ExecutorStart_hook_type next_ExecutorStart_hook = NULL;
|
||||
|
||||
/*
|
||||
* Contextual information on DDL commands
|
||||
@ -97,53 +96,55 @@ sepgsql_object_access(ObjectAccessType access,
|
||||
switch (access)
|
||||
{
|
||||
case OAT_POST_CREATE:
|
||||
switch (classId)
|
||||
{
|
||||
case DatabaseRelationId:
|
||||
sepgsql_database_post_create(objectId,
|
||||
sepgsql_context_info.createdb_dtemplate);
|
||||
break;
|
||||
ObjectAccessPostCreate *pc_arg = arg;
|
||||
bool is_internal;
|
||||
|
||||
case NamespaceRelationId:
|
||||
sepgsql_schema_post_create(objectId);
|
||||
break;
|
||||
is_internal = pc_arg ? pc_arg->is_internal : false;
|
||||
|
||||
case RelationRelationId:
|
||||
if (subId == 0)
|
||||
{
|
||||
/*
|
||||
* All cases we want to apply permission checks on
|
||||
* creation of a new relation are invocation of the
|
||||
* heap_create_with_catalog via DefineRelation or
|
||||
* OpenIntoRel. Elsewhere, we need neither assignment
|
||||
* of security label nor permission checks.
|
||||
*/
|
||||
switch (sepgsql_context_info.cmdtype)
|
||||
switch (classId)
|
||||
{
|
||||
case DatabaseRelationId:
|
||||
Assert(!is_internal);
|
||||
sepgsql_database_post_create(objectId,
|
||||
sepgsql_context_info.createdb_dtemplate);
|
||||
break;
|
||||
|
||||
case NamespaceRelationId:
|
||||
Assert(!is_internal);
|
||||
sepgsql_schema_post_create(objectId);
|
||||
break;
|
||||
|
||||
case RelationRelationId:
|
||||
if (subId == 0)
|
||||
{
|
||||
case T_CreateStmt:
|
||||
case T_ViewStmt:
|
||||
case T_CreateSeqStmt:
|
||||
case T_CompositeTypeStmt:
|
||||
case T_CreateForeignTableStmt:
|
||||
case T_SelectStmt:
|
||||
sepgsql_relation_post_create(objectId);
|
||||
break;
|
||||
default:
|
||||
/* via make_new_heap() */
|
||||
/*
|
||||
* The cases in which we want to apply permission
|
||||
* checks on creation of a new relation correspond
|
||||
* to direct user invocation. For internal uses,
|
||||
* that is creation of toast tables, index rebuild
|
||||
* or ALTER TABLE commands, we need neither
|
||||
* assignment of security labels nor permission
|
||||
* checks.
|
||||
*/
|
||||
if (is_internal)
|
||||
break;
|
||||
|
||||
sepgsql_relation_post_create(objectId);
|
||||
}
|
||||
}
|
||||
else
|
||||
sepgsql_attribute_post_create(objectId, subId);
|
||||
break;
|
||||
else
|
||||
sepgsql_attribute_post_create(objectId, subId);
|
||||
break;
|
||||
|
||||
case ProcedureRelationId:
|
||||
sepgsql_proc_post_create(objectId);
|
||||
break;
|
||||
case ProcedureRelationId:
|
||||
Assert(!is_internal);
|
||||
sepgsql_proc_post_create(objectId);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ignore unsupported object classes */
|
||||
break;
|
||||
default:
|
||||
/* Ignore unsupported object classes */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -215,46 +216,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* sepgsql_executor_start
|
||||
*
|
||||
* It saves contextual information during ExecutorStart to distinguish
|
||||
* a case with/without permission checks later.
|
||||
*/
|
||||
static void
|
||||
sepgsql_executor_start(QueryDesc *queryDesc, int eflags)
|
||||
{
|
||||
sepgsql_context_info_t saved_context_info = sepgsql_context_info;
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
if (queryDesc->operation == CMD_SELECT)
|
||||
sepgsql_context_info.cmdtype = T_SelectStmt;
|
||||
else if (queryDesc->operation == CMD_INSERT)
|
||||
sepgsql_context_info.cmdtype = T_InsertStmt;
|
||||
else if (queryDesc->operation == CMD_DELETE)
|
||||
sepgsql_context_info.cmdtype = T_DeleteStmt;
|
||||
else if (queryDesc->operation == CMD_UPDATE)
|
||||
sepgsql_context_info.cmdtype = T_UpdateStmt;
|
||||
|
||||
/*
|
||||
* XXX - If queryDesc->operation is not above four cases, an error
|
||||
* shall be raised on the following executor stage soon.
|
||||
*/
|
||||
if (next_ExecutorStart_hook)
|
||||
(*next_ExecutorStart_hook) (queryDesc, eflags);
|
||||
else
|
||||
standard_ExecutorStart(queryDesc, eflags);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
sepgsql_context_info = saved_context_info;
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
sepgsql_context_info = saved_context_info;
|
||||
}
|
||||
|
||||
/*
|
||||
* sepgsql_utility_command
|
||||
*
|
||||
@ -425,10 +386,6 @@ _PG_init(void)
|
||||
next_ProcessUtility_hook = ProcessUtility_hook;
|
||||
ProcessUtility_hook = sepgsql_utility_command;
|
||||
|
||||
/* ExecutorStart hook */
|
||||
next_ExecutorStart_hook = ExecutorStart_hook;
|
||||
ExecutorStart_hook = sepgsql_executor_start;
|
||||
|
||||
/* init contextual info */
|
||||
memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
@ -229,6 +232,23 @@ sepgsql_relation_post_create(Oid relOid)
|
||||
|
||||
classForm = (Form_pg_class) GETSTRUCT(tuple);
|
||||
|
||||
/* ignore indexes on toast tables */
|
||||
if (classForm->relkind == RELKIND_INDEX &&
|
||||
classForm->relnamespace == PG_TOAST_NAMESPACE)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* check db_schema:{add_name} permission of the namespace
|
||||
*/
|
||||
object.classId = NamespaceRelationId;
|
||||
object.objectId = classForm->relnamespace;
|
||||
object.objectSubId = 0;
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
SEPG_DB_SCHEMA__ADD_NAME,
|
||||
getObjectDescription(&object),
|
||||
true);
|
||||
|
||||
switch (classForm->relkind)
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
@ -243,22 +263,15 @@ sepgsql_relation_post_create(Oid relOid)
|
||||
tclass = SEPG_CLASS_DB_VIEW;
|
||||
tclass_text = "view";
|
||||
break;
|
||||
case RELKIND_INDEX:
|
||||
/* deal with indexes specially; no need for tclass */
|
||||
sepgsql_index_modify(relOid);
|
||||
goto out;
|
||||
default:
|
||||
/* ignore other relkinds */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* check db_schema:{add_name} permission of the namespace
|
||||
*/
|
||||
object.classId = NamespaceRelationId;
|
||||
object.objectId = classForm->relnamespace;
|
||||
object.objectSubId = 0;
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
SEPG_DB_SCHEMA__ADD_NAME,
|
||||
getObjectDescription(&object),
|
||||
true);
|
||||
|
||||
/*
|
||||
* Compute a default security label when we create a new relation object
|
||||
* under the specified namespace.
|
||||
@ -342,6 +355,7 @@ sepgsql_relation_post_create(Oid relOid)
|
||||
heap_close(arel, AccessShareLock);
|
||||
}
|
||||
pfree(rcontext);
|
||||
|
||||
out:
|
||||
systable_endscan(sscan);
|
||||
heap_close(rel, AccessShareLock);
|
||||
@ -357,18 +371,31 @@ sepgsql_relation_drop(Oid relOid)
|
||||
{
|
||||
ObjectAddress object;
|
||||
char *audit_name;
|
||||
uint16_t tclass = 0;
|
||||
uint16_t tclass;
|
||||
char relkind;
|
||||
|
||||
relkind = get_rel_relkind(relOid);
|
||||
if (relkind == RELKIND_RELATION)
|
||||
tclass = SEPG_CLASS_DB_TABLE;
|
||||
else if (relkind == RELKIND_SEQUENCE)
|
||||
tclass = SEPG_CLASS_DB_SEQUENCE;
|
||||
else if (relkind == RELKIND_VIEW)
|
||||
tclass = SEPG_CLASS_DB_VIEW;
|
||||
else
|
||||
return;
|
||||
switch (relkind)
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
tclass = SEPG_CLASS_DB_TABLE;
|
||||
break;
|
||||
case RELKIND_SEQUENCE:
|
||||
tclass = SEPG_CLASS_DB_SEQUENCE;
|
||||
break;
|
||||
case RELKIND_VIEW:
|
||||
tclass = SEPG_CLASS_DB_VIEW;
|
||||
break;
|
||||
case RELKIND_INDEX:
|
||||
/* ignore indexes on toast tables */
|
||||
if (get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
|
||||
return;
|
||||
/* other indexes are handled specially below; no need for tclass */
|
||||
break;
|
||||
default:
|
||||
/* ignore other relkinds */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* check db_schema:{remove_name} permission
|
||||
@ -385,6 +412,13 @@ sepgsql_relation_drop(Oid relOid)
|
||||
true);
|
||||
pfree(audit_name);
|
||||
|
||||
/* deal with indexes specially */
|
||||
if (relkind == RELKIND_INDEX)
|
||||
{
|
||||
sepgsql_index_modify(relOid);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* check db_table/sequence/view:{drop} permission
|
||||
*/
|
||||
@ -486,3 +520,121 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
|
||||
true);
|
||||
pfree(audit_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* sepgsql_relation_setattr
|
||||
*
|
||||
* It checks privileges to set attribute of the supplied relation
|
||||
*/
|
||||
void
|
||||
sepgsql_relation_setattr(Oid relOid)
|
||||
{
|
||||
ObjectAddress object;
|
||||
char *audit_name;
|
||||
uint16_t tclass;
|
||||
|
||||
switch (get_rel_relkind(relOid))
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
tclass = SEPG_CLASS_DB_TABLE;
|
||||
break;
|
||||
case RELKIND_SEQUENCE:
|
||||
tclass = SEPG_CLASS_DB_SEQUENCE;
|
||||
break;
|
||||
case RELKIND_VIEW:
|
||||
tclass = SEPG_CLASS_DB_VIEW;
|
||||
break;
|
||||
case RELKIND_INDEX:
|
||||
/* deal with indexes specially */
|
||||
sepgsql_index_modify(relOid);
|
||||
return;
|
||||
default:
|
||||
/* other relkinds don't need additional work */
|
||||
return;
|
||||
}
|
||||
|
||||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectDescription(&object);
|
||||
|
||||
/*
|
||||
* XXX - we should add checks related to namespace stuff, when
|
||||
* object_access_hook get support for ALTER statement. Right now, there is
|
||||
* no invocation path on ALTER ... RENAME TO / SET SCHEMA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* check db_xxx:{setattr} permission
|
||||
*/
|
||||
sepgsql_avc_check_perms(&object,
|
||||
tclass,
|
||||
SEPG_DB_TABLE__SETATTR,
|
||||
audit_name,
|
||||
true);
|
||||
pfree(audit_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* sepgsql_relation_setattr_extra
|
||||
*
|
||||
* It checks permission of the relation being referenced by extra attributes,
|
||||
* such as pg_index entries. Like core PostgreSQL, sepgsql also does not deal
|
||||
* with such entries as individual "objects", thus, modification of these
|
||||
* entries shall be considered as setting an attribute of the underlying
|
||||
* relation.
|
||||
*/
|
||||
static void
|
||||
sepgsql_relation_setattr_extra(Relation catalog,
|
||||
Oid catindex_id,
|
||||
Oid extra_oid,
|
||||
AttrNumber anum_relation_id,
|
||||
AttrNumber anum_extra_id)
|
||||
{
|
||||
ScanKeyData skey;
|
||||
SysScanDesc sscan;
|
||||
HeapTuple tuple;
|
||||
Datum datum;
|
||||
bool isnull;
|
||||
|
||||
ScanKeyInit(&skey, anum_extra_id,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(extra_oid));
|
||||
|
||||
sscan = systable_beginscan(catalog, catindex_id, true,
|
||||
SnapshotSelf, 1, &skey);
|
||||
tuple = systable_getnext(sscan);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "catalog lookup failed for object %u in catalog \"%s\"",
|
||||
extra_oid, RelationGetRelationName(catalog));
|
||||
|
||||
datum = heap_getattr(tuple, anum_relation_id,
|
||||
RelationGetDescr(catalog), &isnull);
|
||||
Assert(!isnull);
|
||||
|
||||
sepgsql_relation_setattr(DatumGetObjectId(datum));
|
||||
|
||||
systable_endscan(sscan);
|
||||
}
|
||||
|
||||
/*
|
||||
* sepgsql_index_modify
|
||||
* Handle index create, update, drop
|
||||
*
|
||||
* Unlike other relation kinds, indexes do not have their own security labels,
|
||||
* so instead of doing checks directly, treat them as extra attributes of their
|
||||
* owning tables; so check 'setattr' permissions on the table.
|
||||
*/
|
||||
static void
|
||||
sepgsql_index_modify(Oid indexOid)
|
||||
{
|
||||
Relation catalog = heap_open(IndexRelationId, AccessShareLock);
|
||||
|
||||
/* check db_table:{setattr} permission of the table being indexed */
|
||||
sepgsql_relation_setattr_extra(catalog,
|
||||
IndexRelidIndexId,
|
||||
indexOid,
|
||||
Anum_pg_index_indrelid,
|
||||
Anum_pg_index_indexrelid);
|
||||
heap_close(catalog, AccessShareLock);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -59,6 +59,18 @@ CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql
|
||||
|
||||
RESET SESSION AUTHORIZATION;
|
||||
|
||||
--
|
||||
-- ALTER and CREATE/DROP extra attribute permissions
|
||||
--
|
||||
CREATE TABLE regtest_table_4 (x int primary key, y int, z int);
|
||||
CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
|
||||
CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
|
||||
ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
|
||||
DROP INDEX regtest_index_tbl4_y;
|
||||
ALTER TABLE regtest_table_4
|
||||
ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
|
||||
DROP TABLE regtest_table_4 CASCADE;
|
||||
|
||||
--
|
||||
-- DROP Permission checks (with clean-up)
|
||||
--
|
||||
|
@ -449,6 +449,12 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
|
||||
<literal>remove_name</> on the schema.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When objects that are subsidiary of other objects (such as a table's indexes
|
||||
or triggers) are created or dropped, <literal>setattr</> permission will be
|
||||
checked on the main object, instead of the subsidiary object itself.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
|
||||
and <literal>relabelfrom</> will be checked on the object being relabeled
|
||||
|
@ -247,7 +247,8 @@ Boot_CreateStmt:
|
||||
ONCOMMIT_NOOP,
|
||||
(Datum) 0,
|
||||
false,
|
||||
true);
|
||||
true,
|
||||
false);
|
||||
elog(DEBUG4, "relation created with OID %u", id);
|
||||
}
|
||||
do_end();
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -643,6 +643,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
|
||||
ONCOMMIT_NOOP,
|
||||
reloptions,
|
||||
false,
|
||||
true,
|
||||
true);
|
||||
Assert(OIDNewHeap != InvalidOid);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -30,6 +30,19 @@ typedef enum ObjectAccessType
|
||||
OAT_DROP,
|
||||
} ObjectAccessType;
|
||||
|
||||
/*
|
||||
* Arguments of OAT_POST_CREATE event
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*
|
||||
* This flag informs extensions whether the context of this creation
|
||||
* is invoked by user's operations, or not. E.g, it shall be dealt
|
||||
* as internal stuff on toast tables or indexes due to type changes.
|
||||
*/
|
||||
bool is_internal;
|
||||
} ObjectAccessPostCreate;
|
||||
|
||||
/*
|
||||
* Arguments of OAT_DROP event
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user