diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index 975c1d4795..64d37a3ca9 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -148,6 +148,33 @@ sepgsql_database_drop(Oid databaseId) pfree(audit_name); } +/* + * sepgsql_database_post_alter + * + * It checks privileges to alter the supplied database + */ +void +sepgsql_database_setattr(Oid databaseId) +{ + ObjectAddress object; + char *audit_name; + + /* + * check db_database:{setattr} 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__SETATTR, + audit_name, + true); + pfree(audit_name); +} + /* * sepgsql_database_relabel * diff --git a/contrib/sepgsql/expected/alter.out b/contrib/sepgsql/expected/alter.out new file mode 100644 index 0000000000..ef9abb34ce --- /dev/null +++ b/contrib/sepgsql/expected/alter.out @@ -0,0 +1,192 @@ +-- +-- Test for various ALTER statements +-- +-- clean-up in case a prior regression run failed +SET client_min_messages TO 'warning'; +DROP DATABASE IF EXISTS regtest_sepgsql_test_database_1; +DROP DATABASE IF EXISTS regtest_sepgsql_test_database; +DROP USER IF EXISTS regtest_sepgsql_test_user; +RESET client_min_messages; +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +------------------------------------------- + unconfined_u:unconfined_r:unconfined_t:s0 +(1 row) + +-- +-- CREATE Objects to be altered (with debug_audit being silent) +-- +CREATE DATABASE regtest_sepgsql_test_database_1; +CREATE USER regtest_sepgsql_test_user; +CREATE SCHEMA regtest_schema_1; +CREATE SCHEMA regtest_schema_2; +GRANT ALL ON SCHEMA regtest_schema_1 TO public; +GRANT ALL ON SCHEMA regtest_schema_2 TO public; +SET search_path = regtest_schema_1, regtest_schema_2, public; +CREATE TABLE regtest_table_1 (a int, b text); +CREATE TABLE regtest_table_2 (c text) inherits (regtest_table_1); +CREATE TABLE regtest_table_3 (x int primary key, y text); +CREATE SEQUENCE regtest_seq_1; +CREATE VIEW regtest_view_1 AS SELECT * FROM regtest_table_1 WHERE a > 0; +CREATE FUNCTION regtest_func_1 (text) RETURNS bool + AS 'BEGIN RETURN true; END' LANGUAGE 'plpgsql'; +-- switch on debug_audit +SET sepgsql.debug_audit = true; +SET client_min_messages = LOG; +-- +-- ALTER xxx OWNER TO +-- +-- XXX: It should take db_xxx:{setattr} permission checks even if +-- owner is not actually changed. +-- +ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } 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_1" +ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } 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_1" +ALTER SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema_1" +ALTER SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema_1" +ALTER TABLE regtest_table_1 OWNER TO regtest_sepgsql_test_user; +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_1" +ALTER TABLE regtest_table_1 OWNER TO regtest_sepgsql_test_user; +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_1" +ALTER SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1" +ALTER SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1" +ALTER VIEW regtest_view_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1" +ALTER VIEW regtest_view_1 OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1" +ALTER FUNCTION regtest_func_1(text) OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } 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_1(text)" +ALTER FUNCTION regtest_func_1(text) OWNER TO regtest_sepgsql_test_user; +LOG: SELinux: allowed { setattr } 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_1(text)" +-- +-- ALTER xxx SET SCHEMA +-- +ALTER TABLE regtest_table_1 SET SCHEMA regtest_schema_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_1" +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_2" +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_1" +ALTER SEQUENCE regtest_seq_1 SET SCHEMA regtest_schema_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_1" +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_2" +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1" +ALTER VIEW regtest_view_1 SET SCHEMA regtest_schema_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_1" +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_2" +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1" +ALTER FUNCTION regtest_func_1(text) SET SCHEMA regtest_schema_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_1" +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_1" +LOG: SELinux: allowed { setattr } 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_1(text)" +-- +-- ALTER xxx RENAME TO +-- +ALTER DATABASE regtest_sepgsql_test_database_1 RENAME TO regtest_sepgsql_test_database; +LOG: SELinux: allowed { setattr } 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_1" +ALTER SCHEMA regtest_schema_1 RENAME TO regtest_schema; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema_1" +ALTER TABLE regtest_table_1 RENAME TO regtest_table; +LOG: SELinux: allowed { add_name 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_2" +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_1" +ALTER SEQUENCE regtest_seq_1 RENAME TO regtest_seq; +LOG: SELinux: allowed { add_name 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_2" +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1" +ALTER VIEW regtest_view_1 RENAME TO regtest_view; +LOG: SELinux: allowed { add_name 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_2" +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1" +ALTER FUNCTION regtest_func_1(text) RENAME TO regtest_func; +LOG: SELinux: allowed { add_name 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_2" +LOG: SELinux: allowed { setattr } 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_1(text)" +SET search_path = regtest_schema, regtest_schema_2, public; +-- +-- misc ALTER commands +-- +ALTER DATABASE regtest_sepgsql_test_database CONNECTION LIMIT 999; +LOG: SELinux: allowed { setattr } 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" +ALTER DATABASE regtest_sepgsql_test_database SET search_path TO regtest_schema, public; -- not supported yet +ALTER TABLE regtest_table ADD COLUMN d float; +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 d" +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 d" +ALTER TABLE regtest_table DROP COLUMN d; +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 d" +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 d" +ALTER TABLE regtest_table ALTER b SET DEFAULT 'abcd'; -- not supported yet +ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ'; -- not supported yet +ALTER TABLE regtest_table ALTER b DROP DEFAULT; -- not supported yet +ALTER TABLE regtest_table ALTER b SET NOT NULL; +LOG: SELinux: allowed { setattr } 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 b" +LOG: SELinux: allowed { setattr } 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" +ALTER TABLE regtest_table ALTER b DROP NOT NULL; +LOG: SELinux: allowed { setattr } 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 b" +LOG: SELinux: allowed { setattr } 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" +ALTER TABLE regtest_table ALTER b SET STATISTICS -1; +LOG: SELinux: allowed { setattr } 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 b" +LOG: SELinux: allowed { setattr } 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" +ALTER TABLE regtest_table ALTER b SET (n_distinct = 999); +LOG: SELinux: allowed { setattr } 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 b" +ALTER TABLE regtest_table ALTER b SET STORAGE PLAIN; +LOG: SELinux: allowed { setattr } 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 b" +LOG: SELinux: allowed { setattr } 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" +ALTER TABLE regtest_table ADD CONSTRAINT test_fk FOREIGN KEY (a) REFERENCES regtest_table_3(x); -- not supported +LOG: SELinux: allowed { select } 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 { select } 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 a" +LOG: SELinux: allowed { select } 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 { select } 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 { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table" +CONTEXT: SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)" +LOG: SELinux: allowed { select } 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 a" +CONTEXT: SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)" +LOG: SELinux: allowed { select } 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" +CONTEXT: SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)" +LOG: SELinux: allowed { select } 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" +CONTEXT: SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)" +ALTER TABLE regtest_table ADD CONSTRAINT test_ck CHECK (b like '%abc%') NOT VALID; -- not supported +ALTER TABLE regtest_table VALIDATE CONSTRAINT test_ck; -- not supported +ALTER TABLE regtest_table DROP CONSTRAINT test_ck; -- not supported +CREATE TRIGGER regtest_test_trig BEFORE UPDATE ON regtest_table + FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); +ALTER TABLE regtest_table DISABLE TRIGGER regtest_test_trig; -- not supported +ALTER TABLE regtest_table ENABLE TRIGGER regtest_test_trig; -- not supported +CREATE RULE regtest_test_rule AS ON INSERT TO regtest_table_3 DO ALSO NOTHING; +ALTER TABLE regtest_table_3 DISABLE RULE regtest_test_rule; -- not supported +ALTER TABLE regtest_table_3 ENABLE RULE regtest_test_rule; -- not supported +ALTER TABLE regtest_table SET WITH OIDS; +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 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 oid" +ALTER TABLE regtest_table 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" +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 oid" +ALTER TABLE regtest_table SET (fillfactor = 75); +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 RESET (fillfactor); +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_2 NO INHERIT regtest_table; -- not supported +ALTER TABLE regtest_table_2 INHERIT regtest_table; -- not supported +ALTER TABLE regtest_table SET TABLESPACE pg_default; +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 VIEW regtest_view SET (security_barrier); +LOG: SELinux: allowed { setattr } 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 SEQUENCE regtest_seq INCREMENT BY 10 START WITH 1000; +LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq" +-- +-- clean-up objects +-- +RESET sepgsql.debug_audit; +RESET client_min_messages; +DROP DATABASE regtest_sepgsql_test_database; +DROP SCHEMA regtest_schema CASCADE; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to table regtest_table_2 +drop cascades to table regtest_table_3 +drop cascades to constraint test_fk on table regtest_table +DROP SCHEMA regtest_schema_2 CASCADE; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table regtest_table +drop cascades to sequence regtest_seq +drop cascades to view regtest_view +drop cascades to function regtest_func(text) +DROP USER regtest_sepgsql_test_user; diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out index 1f7ea886b0..d60c65bdb1 100644 --- a/contrib/sepgsql/expected/ddl.out +++ b/contrib/sepgsql/expected/ddl.out @@ -1,6 +1,11 @@ -- -- Regression Test for DDL of Object Permission Checks -- +-- clean-up in case a prior regression run failed +SET client_min_messages TO 'warning'; +DROP DATABASE IF EXISTS regtest_sepgsql_test_database; +DROP USER IF EXISTS regtest_sepgsql_test_user; +RESET client_min_messages; -- confirm required permissions using audit messages SELECT sepgsql_getcon(); -- confirm client privilege sepgsql_getcon @@ -36,6 +41,7 @@ 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 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" +LOG: SELinux: allowed { setattr } 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" 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; @@ -61,6 +67,7 @@ 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); +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" 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" @@ -86,6 +93,7 @@ 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_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" +LOG: SELinux: allowed { setattr } 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" 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" @@ -118,6 +126,7 @@ 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; +LOG: SELinux: allowed { setattr } 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" 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" diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c index 7ec72a0563..0715aa8bc6 100644 --- a/contrib/sepgsql/hooks.c +++ b/contrib/sepgsql/hooks.c @@ -188,6 +188,54 @@ sepgsql_object_access(ObjectAccessType access, } break; + case OAT_POST_ALTER: + { + ObjectAccessPostAlter *pa_arg = arg; + bool is_internal = pa_arg->is_internal; + + switch (classId) + { + case DatabaseRelationId: + Assert(!is_internal); + sepgsql_database_setattr(objectId); + break; + + case NamespaceRelationId: + Assert(!is_internal); + sepgsql_schema_setattr(objectId); + break; + + case RelationRelationId: + if (subId == 0) + { + /* + * A case when we don't want to apply permission + * check is that relation is internally altered + * without user's intention. E.g, no need to + * check on toast table/index to be renamed at + * end of the table rewrites. + */ + if (is_internal) + break; + + sepgsql_relation_setattr(objectId); + } + else + sepgsql_attribute_setattr(objectId, subId); + break; + + case ProcedureRelationId: + Assert(!is_internal); + sepgsql_proc_setattr(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 b47c880f54..53b941d855 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -23,6 +23,7 @@ #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" +#include "utils/syscache.h" #include "utils/tqual.h" #include "sepgsql.h" @@ -43,6 +44,7 @@ sepgsql_proc_post_create(Oid functionId) char *scontext; char *tcontext; char *ncontext; + uint32 required; int i; StringInfoData audit_name; ObjectAddress object; @@ -96,7 +98,7 @@ sepgsql_proc_post_create(Oid functionId) SEPG_CLASS_DB_PROCEDURE); /* - * check db_procedure:{create} permission + * check db_procedure:{create (install)} permission */ initStringInfo(&audit_name); appendStringInfo(&audit_name, "function %s(", NameStr(proForm->proname)); @@ -110,9 +112,13 @@ sepgsql_proc_post_create(Oid functionId) } appendStringInfoChar(&audit_name, ')'); + required = SEPG_DB_PROCEDURE__CREATE; + if (proForm->proleakproof) + required |= SEPG_DB_PROCEDURE__INSTALL; + sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_PROCEDURE, - SEPG_DB_PROCEDURE__CREATE, + required, audit_name.data, true); @@ -214,3 +220,83 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel) true); pfree(audit_name); } + +/* + * sepgsql_proc_setattr + * + * It checks privileges to alter the supplied function. + */ +void +sepgsql_proc_setattr(Oid functionId) +{ + Relation rel; + ScanKeyData skey; + SysScanDesc sscan; + HeapTuple oldtup; + HeapTuple newtup; + Form_pg_proc oldform; + Form_pg_proc newform; + uint32 required; + ObjectAddress object; + char *audit_name; + + /* + * Fetch newer catalog + */ + rel = heap_open(ProcedureRelationId, AccessShareLock); + + ScanKeyInit(&skey, + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(functionId)); + + sscan = systable_beginscan(rel, ProcedureOidIndexId, true, + SnapshotSelf, 1, &skey); + newtup = systable_getnext(sscan); + if (!HeapTupleIsValid(newtup)) + elog(ERROR, "catalog lookup failed for function %u", functionId); + newform = (Form_pg_proc) GETSTRUCT(newtup); + + /* + * Fetch older catalog + */ + oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId)); + if (!HeapTupleIsValid(oldtup)) + elog(ERROR, "cache lookup failed for function %u", functionId); + oldform = (Form_pg_proc) GETSTRUCT(oldtup); + + /* + * Does this ALTER command takes operation to namespace? + */ + if (newform->pronamespace != oldform->pronamespace) + { + sepgsql_schema_remove_name(oldform->pronamespace); + sepgsql_schema_add_name(oldform->pronamespace); + } + if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0) + sepgsql_schema_rename(oldform->pronamespace); + + /* + * check db_procedure:{setattr (install)} permission + */ + required = SEPG_DB_PROCEDURE__SETATTR; + if (!oldform->proleakproof && newform->proleakproof) + required |= SEPG_DB_PROCEDURE__INSTALL; + + object.classId = ProcedureRelationId; + object.objectId = functionId; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_PROCEDURE, + required, + audit_name, + true); + /* cleanups */ + pfree(audit_name); + + ReleaseSysCache(oldtup); + systable_endscan(sscan); + heap_close(rel, AccessShareLock); +} diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index a277fab066..8bcaa41d31 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -190,6 +190,36 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, pfree(audit_name); } +/* + * sepgsql_attribute_setattr + * + * It checks privileges to alter the supplied column. + */ +void +sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum) +{ + ObjectAddress object; + char *audit_name; + + if (get_rel_relkind(relOid) != RELKIND_RELATION) + return; + + /* + * check db_column:{setattr} 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__SETATTR, + audit_name, + true); + pfree(audit_name); +} + /* * sepgsql_relation_post_create * @@ -529,6 +559,13 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel) void sepgsql_relation_setattr(Oid relOid) { + Relation rel; + ScanKeyData skey; + SysScanDesc sscan; + HeapTuple oldtup; + HeapTuple newtup; + Form_pg_class oldform; + Form_pg_class newform; ObjectAddress object; char *audit_name; uint16_t tclass; @@ -553,26 +590,66 @@ sepgsql_relation_setattr(Oid relOid) return; } - object.classId = RelationRelationId; - object.objectId = relOid; - object.objectSubId = 0; - audit_name = getObjectDescription(&object); + /* + * Fetch newer catalog + */ + rel = heap_open(RelationRelationId, AccessShareLock); + + ScanKeyInit(&skey, + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relOid)); + + sscan = systable_beginscan(rel, ClassOidIndexId, true, + SnapshotSelf, 1, &skey); + + newtup = systable_getnext(sscan); + if (!HeapTupleIsValid(newtup)) + elog(ERROR, "catalog lookup failed for relation %u", relOid); + newform = (Form_pg_class) GETSTRUCT(newtup); /* - * 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. + * Fetch older catalog + */ + oldtup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); + if (!HeapTupleIsValid(oldtup)) + elog(ERROR, "cache lookup failed for relation %u", relOid); + oldform = (Form_pg_class) GETSTRUCT(oldtup); + + /* + * Does this ALTER command takes operation to namespace? + */ + if (newform->relnamespace != oldform->relnamespace) + { + sepgsql_schema_remove_name(oldform->relnamespace); + sepgsql_schema_add_name(newform->relnamespace); + } + if (strcmp(NameStr(newform->relname), NameStr(oldform->relname)) != 0) + sepgsql_schema_rename(oldform->relnamespace); + + /* + * XXX - In the future version, db_tuple:{use} of system catalog entry + * shall be checked, if tablespace configuration is changed. */ /* * check db_xxx:{setattr} permission */ + object.classId = RelationRelationId; + object.objectId = relOid; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + sepgsql_avc_check_perms(&object, tclass, SEPG_DB_TABLE__SETATTR, audit_name, true); pfree(audit_name); + + ReleaseSysCache(oldtup); + systable_endscan(sscan); + heap_close(rel, AccessShareLock); } /* diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index 75b28261ce..ecdfd738d9 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -162,3 +162,54 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel) true); pfree(audit_name); } + +/* + * sepgsql_schema_check_perms + * + * utility routine to check db_schema:{xxx} permissions + */ +static void +check_schema_perms(Oid namespaceId, uint32 required) +{ + ObjectAddress object; + char *audit_name; + + object.classId = NamespaceRelationId; + object.objectId = namespaceId; + object.objectSubId = 0; + audit_name = getObjectDescription(&object); + + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_SCHEMA, + required, + audit_name, + true); + pfree(audit_name); +} + +/* db_schema:{setattr} permission */ +void +sepgsql_schema_setattr(Oid namespaceId) +{ + check_schema_perms(namespaceId, SEPG_DB_SCHEMA__SETATTR); +} + +void +sepgsql_schema_add_name(Oid namespaceId) +{ + check_schema_perms(namespaceId, SEPG_DB_SCHEMA__ADD_NAME); +} + +void +sepgsql_schema_remove_name(Oid namespaceId) +{ + check_schema_perms(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME); +} + +void +sepgsql_schema_rename(Oid namespaceId) +{ + check_schema_perms(namespaceId, + SEPG_DB_SCHEMA__ADD_NAME | + SEPG_DB_SCHEMA__REMOVE_NAME); +} diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index 5ae51469d7..d4ee94be5a 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -293,6 +293,7 @@ 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); +extern void sepgsql_database_setattr(Oid databaseId); /* * schema.c @@ -300,6 +301,10 @@ extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel); 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); +extern void sepgsql_schema_setattr(Oid namespaceId); +extern void sepgsql_schema_add_name(Oid namespaceId); +extern void sepgsql_schema_remove_name(Oid namespaceId); +extern void sepgsql_schema_rename(Oid namespaceId); /* * relation.c @@ -308,6 +313,7 @@ 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_attribute_setattr(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); @@ -319,5 +325,6 @@ extern void sepgsql_relation_setattr(Oid relOid); 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); +extern void sepgsql_proc_setattr(Oid functionId); #endif /* SEPGSQL_H */ diff --git a/contrib/sepgsql/sql/alter.sql b/contrib/sepgsql/sql/alter.sql new file mode 100644 index 0000000000..4bded7ead5 --- /dev/null +++ b/contrib/sepgsql/sql/alter.sql @@ -0,0 +1,136 @@ +-- +-- Test for various ALTER statements +-- + +-- clean-up in case a prior regression run failed +SET client_min_messages TO 'warning'; +DROP DATABASE IF EXISTS regtest_sepgsql_test_database_1; +DROP DATABASE IF EXISTS regtest_sepgsql_test_database; +DROP USER IF EXISTS regtest_sepgsql_test_user; +RESET client_min_messages; + +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0 + +-- +-- CREATE Objects to be altered (with debug_audit being silent) +-- +CREATE DATABASE regtest_sepgsql_test_database_1; + +CREATE USER regtest_sepgsql_test_user; + +CREATE SCHEMA regtest_schema_1; +CREATE SCHEMA regtest_schema_2; + +GRANT ALL ON SCHEMA regtest_schema_1 TO public; +GRANT ALL ON SCHEMA regtest_schema_2 TO public; + +SET search_path = regtest_schema_1, regtest_schema_2, public; + +CREATE TABLE regtest_table_1 (a int, b text); + +CREATE TABLE regtest_table_2 (c text) inherits (regtest_table_1); + +CREATE TABLE regtest_table_3 (x int primary key, y text); + +CREATE SEQUENCE regtest_seq_1; + +CREATE VIEW regtest_view_1 AS SELECT * FROM regtest_table_1 WHERE a > 0; + +CREATE FUNCTION regtest_func_1 (text) RETURNS bool + AS 'BEGIN RETURN true; END' LANGUAGE 'plpgsql'; + +-- switch on debug_audit +SET sepgsql.debug_audit = true; +SET client_min_messages = LOG; + +-- +-- ALTER xxx OWNER TO +-- +-- XXX: It should take db_xxx:{setattr} permission checks even if +-- owner is not actually changed. +-- +ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user; +ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user; +ALTER SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user; +ALTER SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user; +ALTER TABLE regtest_table_1 OWNER TO regtest_sepgsql_test_user; +ALTER TABLE regtest_table_1 OWNER TO regtest_sepgsql_test_user; +ALTER SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user; +ALTER SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user; +ALTER VIEW regtest_view_1 OWNER TO regtest_sepgsql_test_user; +ALTER VIEW regtest_view_1 OWNER TO regtest_sepgsql_test_user; +ALTER FUNCTION regtest_func_1(text) OWNER TO regtest_sepgsql_test_user; +ALTER FUNCTION regtest_func_1(text) OWNER TO regtest_sepgsql_test_user; + +-- +-- ALTER xxx SET SCHEMA +-- +ALTER TABLE regtest_table_1 SET SCHEMA regtest_schema_2; +ALTER SEQUENCE regtest_seq_1 SET SCHEMA regtest_schema_2; +ALTER VIEW regtest_view_1 SET SCHEMA regtest_schema_2; +ALTER FUNCTION regtest_func_1(text) SET SCHEMA regtest_schema_2; + +-- +-- ALTER xxx RENAME TO +-- +ALTER DATABASE regtest_sepgsql_test_database_1 RENAME TO regtest_sepgsql_test_database; +ALTER SCHEMA regtest_schema_1 RENAME TO regtest_schema; +ALTER TABLE regtest_table_1 RENAME TO regtest_table; +ALTER SEQUENCE regtest_seq_1 RENAME TO regtest_seq; +ALTER VIEW regtest_view_1 RENAME TO regtest_view; +ALTER FUNCTION regtest_func_1(text) RENAME TO regtest_func; + +SET search_path = regtest_schema, regtest_schema_2, public; + +-- +-- misc ALTER commands +-- +ALTER DATABASE regtest_sepgsql_test_database CONNECTION LIMIT 999; +ALTER DATABASE regtest_sepgsql_test_database SET search_path TO regtest_schema, public; -- not supported yet + +ALTER TABLE regtest_table ADD COLUMN d float; +ALTER TABLE regtest_table DROP COLUMN d; +ALTER TABLE regtest_table ALTER b SET DEFAULT 'abcd'; -- not supported yet +ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ'; -- not supported yet +ALTER TABLE regtest_table ALTER b DROP DEFAULT; -- not supported yet +ALTER TABLE regtest_table ALTER b SET NOT NULL; +ALTER TABLE regtest_table ALTER b DROP NOT NULL; +ALTER TABLE regtest_table ALTER b SET STATISTICS -1; +ALTER TABLE regtest_table ALTER b SET (n_distinct = 999); +ALTER TABLE regtest_table ALTER b SET STORAGE PLAIN; +ALTER TABLE regtest_table ADD CONSTRAINT test_fk FOREIGN KEY (a) REFERENCES regtest_table_3(x); -- not supported +ALTER TABLE regtest_table ADD CONSTRAINT test_ck CHECK (b like '%abc%') NOT VALID; -- not supported +ALTER TABLE regtest_table VALIDATE CONSTRAINT test_ck; -- not supported +ALTER TABLE regtest_table DROP CONSTRAINT test_ck; -- not supported + +CREATE TRIGGER regtest_test_trig BEFORE UPDATE ON regtest_table + FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); + +ALTER TABLE regtest_table DISABLE TRIGGER regtest_test_trig; -- not supported +ALTER TABLE regtest_table ENABLE TRIGGER regtest_test_trig; -- not supported + +CREATE RULE regtest_test_rule AS ON INSERT TO regtest_table_3 DO ALSO NOTHING; +ALTER TABLE regtest_table_3 DISABLE RULE regtest_test_rule; -- not supported +ALTER TABLE regtest_table_3 ENABLE RULE regtest_test_rule; -- not supported + +ALTER TABLE regtest_table SET WITH OIDS; +ALTER TABLE regtest_table SET WITHOUT OIDS; +ALTER TABLE regtest_table SET (fillfactor = 75); +ALTER TABLE regtest_table RESET (fillfactor); +ALTER TABLE regtest_table_2 NO INHERIT regtest_table; -- not supported +ALTER TABLE regtest_table_2 INHERIT regtest_table; -- not supported +ALTER TABLE regtest_table SET TABLESPACE pg_default; + +ALTER VIEW regtest_view SET (security_barrier); + +ALTER SEQUENCE regtest_seq INCREMENT BY 10 START WITH 1000; + +-- +-- clean-up objects +-- +RESET sepgsql.debug_audit; +RESET client_min_messages; +DROP DATABASE regtest_sepgsql_test_database; +DROP SCHEMA regtest_schema CASCADE; +DROP SCHEMA regtest_schema_2 CASCADE; +DROP USER regtest_sepgsql_test_user; diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql index 5afe1ba193..c91c4cf572 100644 --- a/contrib/sepgsql/sql/ddl.sql +++ b/contrib/sepgsql/sql/ddl.sql @@ -2,6 +2,12 @@ -- Regression Test for DDL of Object Permission Checks -- +-- clean-up in case a prior regression run failed +SET client_min_messages TO 'warning'; +DROP DATABASE IF EXISTS regtest_sepgsql_test_database; +DROP USER IF EXISTS regtest_sepgsql_test_user; +RESET client_min_messages; + -- confirm required permissions using audit messages -- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0 SET sepgsql.debug_audit = true; diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql index 473004f6d2..8d1a35ce85 100755 --- a/contrib/sepgsql/test_sepgsql +++ b/contrib/sepgsql/test_sepgsql @@ -162,6 +162,31 @@ if [ "${POLICY_STATUS}" != on ]; then echo "" exit 1 fi +POLICY_STATUS=`getsebool sepgsql_enable_users_ddl | awk '{print $3}'` +echo ${POLICY_STATUS:-failed} +if [ "${POLICY_STATUS}" != on ]; then + echo "" + echo "The SELinux boolean 'sepgsql_enable_users_ddl' must be" + echo "turned on in order to enable the rules necessary to run" + echo "the regression tests." + echo "" + if [ "${POLICY_STATUS}" = "" ]; then + echo "We attempted to determine the state of this Boolean using" + echo "'getsebool', but that command did not produce the expected" + echo "output. Please verify that getsebool is available and in" + echo "your PATH." + else + echo "You can turn on this variable using the following commands:" + echo "" + echo " \$ sudo setsebool sepgsql_enable_users_ddl on" + echo "" + echo "For security reasons, it is suggested that you turn off this" + echo "variable when regression testing is complete, unless you" + echo "don't want to allow unprivileged users DDL commands." + fi + echo "" + exit 1 +fi # 'psql' command must be executable from test domain echo -n "checking whether we can run psql ... " @@ -259,6 +284,6 @@ echo "found ${NUM}" echo echo "============== running sepgsql regression tests ==============" -make REGRESS="label dml ddl misc" REGRESS_OPTS="--launcher ./launcher" installcheck +make REGRESS="label dml ddl alter 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 e7ce8b5d5b..5ee08e1dee 100644 --- a/doc/src/sgml/sepgsql.sgml +++ b/doc/src/sgml/sepgsql.sgml @@ -438,6 +438,12 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100; On creation of objects within a particular schema (tables, views, sequences and procedures), add_name will be also checked on the schema, not only create on the new object itself. + On , install permission + will be checked if leakproof attribute was given, not only + create on the new function. This permission will be also + checked when user tries to turn on leakproof attribute + using command, with + setattr permission on the function being altered. @@ -450,9 +456,19 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100; - When objects that are subsidiary of other objects (such as a table's indexes - or triggers) are created or dropped, setattr permission will be - checked on the main object, instead of the subsidiary object itself. + When ALTER command is executed, setattr will be + checked on the object being modified for each object types. + In addition, remove_name and add_name + will be checked on the old and new schemas, respectively, when an + object is moved to a new schema. + For certain object types, additional checks are performed. + + + + When objects that are subsidiary of other objects (such as a table's + indexes or triggers) are created, dropped or altered, + setattr permission will be checked on the main object, + instead of the subsidiary object itself.