contrib/sepgsql/database.c | 27 ++++++ contrib/sepgsql/expected/create.out | 80 ------------------ contrib/sepgsql/expected/ddl.out | 152 +++++++++++++++++++++++++++++++++++ contrib/sepgsql/hooks.c | 24 ++++++ contrib/sepgsql/proc.c | 42 ++++++++++ contrib/sepgsql/relation.c | 119 +++++++++++++++++++++++++++ contrib/sepgsql/schema.c | 27 ++++++ contrib/sepgsql/sepgsql.h | 5 + contrib/sepgsql/sql/create.sql | 46 ----------- contrib/sepgsql/sql/ddl.sql | 81 +++++++++++++++++++ contrib/sepgsql/test_sepgsql | 2 +- doc/src/sgml/sepgsql.sgml | 14 +++ src/backend/catalog/pg_shdepend.c | 5 + src/backend/commands/dbcommands.c | 3 + src/backend/commands/dropcmds.c | 5 + src/backend/commands/tablecmds.c | 7 ++ src/backend/commands/tablespace.c | 3 + src/include/catalog/objectaccess.h | 4 + 18 files changed, 519 insertions(+), 127 deletions(-) diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index be3a7be..0c395c4 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -119,6 +119,33 @@ sepgsql_database_post_create(Oid databaseId, const char *dtemplate) } /* + * sepgsql_database_drop + * + * It checks privileges to drop the supplied database + */ +void +sepgsql_database_drop(Oid databaseId) +{ + ObjectAddress object; + char *audit_name; + + /* + * check db_database:{drop} permission + */ + object.classId = DatabaseRelationId; + object.objectId = databaseId; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_DATABASE, + SEPG_DB_DATABASE__DROP, + audit_name, + true); + pfree(audit_name); +} + +/* * sepgsql_database_relabel * * It checks privileges to relabel the supplied database with the `seclabel' diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out deleted file mode 100644 index 0f04a3e..0000000 --- a/contrib/sepgsql/expected/create.out +++ /dev/null @@ -1,80 +0,0 @@ --- --- Regression Test for Creation of Object Permission Checks --- --- confirm required permissions using audit messages -SELECT sepgsql_getcon(); -- confirm client privilege - sepgsql_getcon -------------------------------------------- - unconfined_u:unconfined_r:unconfined_t:s0 -(1 row) - -SET sepgsql.debug_audit = true; -SET client_min_messages = LOG; -CREATE DATABASE regtest_sepgsql_test_database; -LOG: SELinux: allowed { getattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database template1" -LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database" -CREATE SCHEMA regtest_schema; -LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" -SET search_path = regtest_schema, public; -CREATE TABLE regtest_table (x serial primary key, y text); -NOTICE: CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x" -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_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq" -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" -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 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 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 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 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 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 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" -NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for 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; -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_2" -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_2 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_2 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_2 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_2 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_2 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_2 column oid" -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_2 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_2 column a" --- corresponding toast table should not have label and permission checks -ALTER TABLE regtest_table_2 ADD COLUMN b text; -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_2 column b" --- VACUUM FULL internally create a new table and swap them later. -VACUUM FULL regtest_table; -CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100; -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_view_t:s0 tclass=db_view name="view regtest_view" -CREATE SEQUENCE regtest_seq; -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_seq_t:s0 tclass=db_sequence name="sequence regtest_seq" -CREATE TYPE regtest_comptype AS (a int, b text); -CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql - AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END'; -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_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text,integer[])" -CREATE AGGREGATE regtest_agg ( - sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0' -); -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_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg(integer)" --- --- clean-up --- -DROP DATABASE IF EXISTS regtest_sepgsql_test_database; -DROP SCHEMA IF EXISTS regtest_schema CASCADE; -NOTICE: drop cascades to 7 other objects -DETAIL: drop cascades to table regtest_table -drop cascades to table regtest_table_2 -drop cascades to view regtest_view -drop cascades to sequence regtest_seq -drop cascades to type regtest_comptype -drop cascades to function regtest_func(text,integer[]) -drop cascades to function regtest_agg(integer) diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out new file mode 100644 index 0000000..8b42255 --- /dev/null +++ b/contrib/sepgsql/expected/ddl.out @@ -0,0 +1,152 @@ +-- +-- Regression Test for DDL of Object Permission Checks +-- +-- confirm required permissions using audit messages +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +------------------------------------------- + unconfined_u:unconfined_r:unconfined_t:s0 +(1 row) + +SET sepgsql.debug_audit = true; +SET client_min_messages = LOG; +-- +-- CREATE Permission checks +-- +CREATE DATABASE regtest_sepgsql_test_database; +LOG: SELinux: allowed { getattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database template1" +LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database" +CREATE USER regtest_sepgsql_test_user; +CREATE SCHEMA regtest_schema; +LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +GRANT ALL ON SCHEMA regtest_schema TO regtest_sepgsql_test_user; +SET search_path = regtest_schema, public; +CREATE TABLE regtest_table (x serial primary key, y text); +NOTICE: CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x" +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_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq" +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" +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 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 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 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 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 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 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" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for 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; +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_2" +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_2 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_2 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_2 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_2 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_2 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_2 column oid" +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_2 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_2 column a" +-- corresponding toast table should not have label and permission checks +ALTER TABLE regtest_table_2 ADD COLUMN b text; +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_2 column b" +-- VACUUM FULL internally create a new table and swap them later. +VACUUM FULL regtest_table; +CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100; +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_view_t:s0 tclass=db_view name="view regtest_view" +CREATE SEQUENCE regtest_seq; +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_seq_t:s0 tclass=db_sequence name="sequence regtest_seq" +CREATE TYPE regtest_comptype AS (a int, b text); +CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql + AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END'; +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_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text,integer[])" +CREATE AGGREGATE regtest_agg ( + sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0' +); +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_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg(integer)" +-- CREATE objects owned by others +SET SESSION AUTHORIZATION regtest_sepgsql_test_user; +SET search_path = regtest_schema, public; +CREATE TABLE regtest_table_3 (x int, y serial); +NOTICE: CREATE TABLE will create implicit sequence "regtest_table_3_y_seq" for serial column "regtest_table_3.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 { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_3_y_seq" +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_3" +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_3 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_3 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_3 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_3 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_3 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_3 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_3 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_3 column y" +CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < 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 { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_2" +CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql + AS 'BEGIN RETURN $1 * $1 < 100; END'; +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_proc_exec_t:s0 tclass=db_procedure name="function regtest_func_2(integer)" +RESET SESSION AUTHORIZATION; +-- +-- DROP Permission checks (with clean-up) +-- +DROP FUNCTION regtest_func(text,int[]); +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_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text,integer[])" +DROP AGGREGATE regtest_agg(int); +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_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg(integer)" +DROP SEQUENCE regtest_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq" +DROP VIEW regtest_view; +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_view_t:s0 tclass=db_view name="view regtest_view" +ALTER TABLE regtest_table DROP 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 column y" +ALTER TABLE regtest_table_2 SET WITHOUT OIDS; +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_2 column oid" +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_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" +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 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 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 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 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 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 column z" +DROP OWNED BY regtest_sepgsql_test_user; +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_proc_exec_t:s0 tclass=db_procedure name="function regtest_func_2(integer)" +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_view_t:s0 tclass=db_view name="view regtest_view_2" +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_3" +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_3 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_3 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_3 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_3 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_3 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_3 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_3 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_3 column 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 { 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_3_y_seq" +DROP DATABASE regtest_sepgsql_test_database; +LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database" +DROP USER regtest_sepgsql_test_user; +DROP SCHEMA IF EXISTS regtest_schema CASCADE; +LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table regtest_table_2 +drop cascades to type regtest_comptype diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c index 47437ba..5ba78c4 100644 --- a/contrib/sepgsql/hooks.c +++ b/contrib/sepgsql/hooks.c @@ -192,6 +192,30 @@ sepgsql_object_access(ObjectAccessType access, } break; + case OAT_DROP: + switch (classId) + { + case DatabaseRelationId: + sepgsql_database_drop(objectId); + break; + case NamespaceRelationId: + sepgsql_schema_drop(objectId); + break; + case RelationRelationId: + if (subId == 0) + sepgsql_relation_drop(objectId); + else + sepgsql_attribute_drop(objectId, subId); + break; + case ProcedureRelationId: + sepgsql_proc_drop(objectId); + break; + default: + /* Ignore unsupported object classes */ + break; + } + break; + default: elog(ERROR, "unexpected object access type: %d", (int) access); break; diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index b902797..1efbc90 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -131,6 +131,48 @@ sepgsql_proc_post_create(Oid functionId) } /* + * sepgsql_proc_drop + * + * It checks privileges to drop the supplied function. + */ +void +sepgsql_proc_drop(Oid functionId) +{ + ObjectAddress object; + char *audit_name; + + /* + * check db_schema:{remove_name} permission + */ + object.classId = NamespaceRelationId; + object.objectId = get_func_namespace(functionId); + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_SCHEMA, + SEPG_DB_SCHEMA__REMOVE_NAME, + audit_name, + true); + pfree(audit_name); + + /* + * check db_procedure:{drop} permission + */ + object.classId = ProcedureRelationId; + object.objectId = functionId; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_PROCEDURE, + SEPG_DB_PROCEDURE__DROP, + audit_name, + true); + pfree(audit_name); +} + +/* * sepgsql_proc_relabel * * It checks privileges to relabel the supplied function diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index efce914..259be49 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -21,6 +21,7 @@ #include "commands/seclabel.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" +#include "utils/syscache.h" #include "utils/tqual.h" #include "sepgsql.h" @@ -110,6 +111,36 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) } /* + * sepgsql_attribute_drop + * + * It checks privileges to drop the supplied column. + */ +void +sepgsql_attribute_drop(Oid relOid, AttrNumber attnum) +{ + ObjectAddress object; + char *audit_name; + + if (get_rel_relkind(relOid) != RELKIND_RELATION) + return; + + /* + * check db_column:{drop} permission + */ + object.classId = RelationRelationId; + object.objectId = relOid; + object.objectSubId = attnum; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_COLUMN, + SEPG_DB_COLUMN__DROP, + audit_name, + true); + pfree(audit_name); +} + +/* * sepgsql_attribute_relabel * * It checks privileges to relabel the supplied column @@ -310,6 +341,94 @@ out: } /* + * sepgsql_relation_drop + * + * It checks privileges to drop the supplied relation. + */ +void +sepgsql_relation_drop(Oid relOid) +{ + ObjectAddress object; + char *audit_name; + uint16_t tclass = 0; + 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; + + /* + * check db_schema:{remove_name} permission + */ + object.classId = NamespaceRelationId; + object.objectId = get_rel_namespace(relOid); + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_SCHEMA, + SEPG_DB_SCHEMA__REMOVE_NAME, + audit_name, + true); + pfree(audit_name); + + /* + * check db_table/sequence/view:{drop} permission + */ + object.classId = RelationRelationId; + object.objectId = relOid; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + tclass, + SEPG_DB_TABLE__DROP, + audit_name, + true); + pfree(audit_name); + + /* + * check db_column:{drop} permission + */ + if (relkind == RELKIND_RELATION) + { + Form_pg_attribute attForm; + CatCList *attrList; + HeapTuple atttup; + int i; + + attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid)); + for (i=0; i < attrList->n_members; i++) + { + atttup = &attrList->members[i]->tuple; + attForm = (Form_pg_attribute) GETSTRUCT(atttup); + + if (attForm->attisdropped) + continue; + + object.classId = RelationRelationId; + object.objectId = relOid; + object.objectSubId = attForm->attnum; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_COLUMN, + SEPG_DB_COLUMN__DROP, + audit_name, + true); + pfree(audit_name); + } + ReleaseCatCacheList(attrList); + } +} + +/* * sepgsql_relation_relabel * * It checks privileges to relabel the supplied relation by the `seclabel'. diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index 90dca1d..31d60ef 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -97,6 +97,33 @@ sepgsql_schema_post_create(Oid namespaceId) } /* + * sepgsql_schema_drop + * + * It checks privileges to drop the supplied schema object. + */ +void +sepgsql_schema_drop(Oid namespaceId) +{ + ObjectAddress object; + char *audit_name; + + /* + * check db_schema:{drop} permission + */ + object.classId = NamespaceRelationId; + object.objectId = namespaceId; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_SCHEMA, + SEPG_DB_SCHEMA__DROP, + audit_name, + true); + pfree(audit_name); +} + +/* * sepgsql_schema_relabel * * It checks privileges to relabel the supplied schema diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index c93da7a..a7a4532 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -288,27 +288,32 @@ extern bool sepgsql_dml_privileges(List *rangeTabls, bool abort); */ extern void sepgsql_database_post_create(Oid databaseId, const char *dtemplate); +extern void sepgsql_database_drop(Oid databaseId); extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel); /* * schema.c */ extern void sepgsql_schema_post_create(Oid namespaceId); +extern void sepgsql_schema_drop(Oid namespaceId); extern void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel); /* * relation.c */ extern void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum); +extern void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum); extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, const char *seclabel); 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); /* * proc.c */ extern void sepgsql_proc_post_create(Oid functionId); +extern void sepgsql_proc_drop(Oid functionId); extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel); #endif /* SEPGSQL_H */ diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql deleted file mode 100644 index b0695b4..0000000 --- a/contrib/sepgsql/sql/create.sql +++ /dev/null @@ -1,46 +0,0 @@ --- --- Regression Test for Creation of Object Permission Checks --- - --- confirm required permissions using audit messages --- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0 -SET sepgsql.debug_audit = true; -SET client_min_messages = LOG; - -CREATE DATABASE regtest_sepgsql_test_database; - -CREATE SCHEMA regtest_schema; - -SET search_path = regtest_schema, public; - -CREATE TABLE regtest_table (x serial primary key, y text); - -ALTER TABLE regtest_table ADD COLUMN z int; - -CREATE TABLE regtest_table_2 (a int) WITH OIDS; - --- corresponding toast table should not have label and permission checks -ALTER TABLE regtest_table_2 ADD COLUMN b text; - --- VACUUM FULL internally create a new table and swap them later. -VACUUM FULL regtest_table; - -CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100; - -CREATE SEQUENCE regtest_seq; - -CREATE TYPE regtest_comptype AS (a int, b text); - -CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql - AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END'; - -CREATE AGGREGATE regtest_agg ( - sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0' -); - --- --- clean-up --- -DROP DATABASE IF EXISTS regtest_sepgsql_test_database; - -DROP SCHEMA IF EXISTS regtest_schema CASCADE; diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql new file mode 100644 index 0000000..8dd57e0 --- /dev/null +++ b/contrib/sepgsql/sql/ddl.sql @@ -0,0 +1,81 @@ +-- +-- Regression Test for DDL of Object Permission Checks +-- + +-- confirm required permissions using audit messages +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0 +SET sepgsql.debug_audit = true; +SET client_min_messages = LOG; + +-- +-- CREATE Permission checks +-- +CREATE DATABASE regtest_sepgsql_test_database; + +CREATE USER regtest_sepgsql_test_user; + +CREATE SCHEMA regtest_schema; + +GRANT ALL ON SCHEMA regtest_schema TO regtest_sepgsql_test_user; + +SET search_path = regtest_schema, public; + +CREATE TABLE regtest_table (x serial primary key, y text); + +ALTER TABLE regtest_table ADD COLUMN z int; + +CREATE TABLE regtest_table_2 (a int) WITH OIDS; + +-- corresponding toast table should not have label and permission checks +ALTER TABLE regtest_table_2 ADD COLUMN b text; + +-- VACUUM FULL internally create a new table and swap them later. +VACUUM FULL regtest_table; + +CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100; + +CREATE SEQUENCE regtest_seq; + +CREATE TYPE regtest_comptype AS (a int, b text); + +CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql + AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END'; + +CREATE AGGREGATE regtest_agg ( + sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0' +); + +-- CREATE objects owned by others +SET SESSION AUTHORIZATION regtest_sepgsql_test_user; + +SET search_path = regtest_schema, public; + +CREATE TABLE regtest_table_3 (x int, y serial); + +CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < y; + +CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql + AS 'BEGIN RETURN $1 * $1 < 100; END'; + +RESET SESSION AUTHORIZATION; + +-- +-- DROP Permission checks (with clean-up) +-- + +DROP FUNCTION regtest_func(text,int[]); +DROP AGGREGATE regtest_agg(int); + +DROP SEQUENCE regtest_seq; +DROP VIEW regtest_view; + +ALTER TABLE regtest_table DROP COLUMN y; +ALTER TABLE regtest_table_2 SET WITHOUT OIDS; + +DROP TABLE regtest_table; + +DROP OWNED BY regtest_sepgsql_test_user; + +DROP DATABASE regtest_sepgsql_test_database; +DROP USER regtest_sepgsql_test_user; +DROP SCHEMA IF EXISTS regtest_schema CASCADE; diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql index 52237e6..473004f 100755 --- a/contrib/sepgsql/test_sepgsql +++ b/contrib/sepgsql/test_sepgsql @@ -259,6 +259,6 @@ echo "found ${NUM}" echo echo "============== running sepgsql regression tests ==============" -make REGRESS="label dml create misc" REGRESS_OPTS="--launcher ./launcher" installcheck +make REGRESS="label dml ddl misc" REGRESS_OPTS="--launcher ./launcher" installcheck # exit with the exit code provided by "make" diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml index e45c258..d9b1fed 100644 --- a/doc/src/sgml/sepgsql.sgml +++ b/doc/src/sgml/sepgsql.sgml @@ -448,6 +448,20 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100; + When DROP command is executed, drop will be + checked on the object being removed for each object types. + Please note that it shall not be checked on the objects removed by + cascaded deletion according to the standard manner in SQL. + + + A few additional checks are applied depending on object types. + On deletion of objects underlying a particula schema (tables, views, + sequences and procedures), remove_name shall be also checked + on the schema, not only drop on the object being removed + 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/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index c3e55ab..1ed2d70 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -20,6 +20,7 @@ #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/indexing.h" +#include "catalog/objectaccess.h" #include "catalog/pg_authid.h" #include "catalog/pg_collation.h" #include "catalog/pg_conversion.h" @@ -1232,6 +1233,10 @@ shdepDropOwned(List *roleids, DropBehavior behavior) obj.objectId = sdepForm->objid; obj.objectSubId = sdepForm->objsubid; add_exact_object_address(&obj, deleteobjs); + + /* DROP hook for the object being removed */ + InvokeObjectAccessHook(OAT_DROP, obj.classId, + obj.objectId, obj.objectSubId); break; } } diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 42a8b31..ca12369 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -777,6 +777,9 @@ dropdb(const char *dbname, bool missing_ok) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); + /* DROP hook for the database being removed */ + InvokeObjectAccessHook(OAT_DROP, DatabaseRelationId, db_id, 0); + /* * Disallow dropping a DB that is marked istemplate. This is just to * prevent people from accidentally dropping template0 or template1; they diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 9eeba04..c52310e 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -18,6 +18,7 @@ #include "access/heapam.h" #include "catalog/dependency.h" #include "catalog/namespace.h" +#include "catalog/objectaccess.h" #include "catalog/objectaddress.h" #include "catalog/pg_class.h" #include "catalog/pg_proc.h" @@ -111,6 +112,10 @@ RemoveObjects(DropStmt *stmt) check_object_ownership(GetUserId(), stmt->removeType, address, objname, objargs, relation); + /* DROP hook for the object being removed */ + InvokeObjectAccessHook(OAT_DROP, address.classId, + address.objectId, address.objectSubId); + /* Release any relcache reference count, but keep lock until commit. */ if (relation) heap_close(relation, NoLock); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index c373016..8a7f938 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -806,6 +806,9 @@ RemoveRelations(DropStmt *drop) continue; } + /* DROP hook for the relation being removed */ + InvokeObjectAccessHook(OAT_DROP, RelationRelationId, relOid, 0); + /* OK, we're ready to delete this one */ obj.classId = RelationRelationId; obj.objectId = relOid; @@ -5088,6 +5091,10 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, attnum = targetatt->attnum; + /* DROP hook for the attribute being removed */ + InvokeObjectAccessHook(OAT_DROP, RelationRelationId, + RelationGetRelid(rel), attnum); + /* Can't drop a system attribute, except OID */ if (attnum <= 0 && attnum != ObjectIdAttributeNumber) ereport(ERROR, diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index ff58490..bf9f362 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -434,6 +434,9 @@ DropTableSpace(DropTableSpaceStmt *stmt) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tablespacename); + /* DROP hook for the tablespace being removed */ + InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId, tablespaceoid, 0); + /* * Remove the pg_tablespace tuple (this will roll back if we fail below) */ diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h index 5c7a40a..cb38cba 100644 --- a/src/include/catalog/objectaccess.h +++ b/src/include/catalog/objectaccess.h @@ -19,11 +19,15 @@ * Typically, this is done after inserting the primary catalog records and * associated dependencies. * + * OAT_DROP should be invoked just after the permission checks of objects + * deletion. Please note that it shall NOT be invoked around cascaded drops. + * * Other types may be added in the future. */ typedef enum ObjectAccessType { OAT_POST_CREATE, + OAT_DROP, } ObjectAccessType; /*