contrib/sepgsql/expected/alter.out | 31 +++++++++++++++++++++++ contrib/sepgsql/expected/ddl.out | 52 ++++++++++++++++++++++++++++++++++++++ contrib/sepgsql/expected/dml.out | 27 ++++++++++++++++++++ contrib/sepgsql/hooks.c | 19 ++++++++++++++ contrib/sepgsql/schema.c | 33 ++++++++++++++++-------- contrib/sepgsql/sepgsql-regtest.te | 5 +++- contrib/sepgsql/sepgsql.h | 1 + contrib/sepgsql/sql/dml.sql | 18 +++++++++++++ doc/src/sgml/sepgsql.sgml | 7 +++++ src/backend/catalog/namespace.c | 15 ++++++++--- src/backend/catalog/objectaccess.c | 25 ++++++++++++++++++ src/backend/tcop/fastpath.c | 2 ++ src/include/catalog/objectaccess.h | 33 ++++++++++++++++++++++++ 13 files changed, 253 insertions(+), 15 deletions(-) diff --git a/contrib/sepgsql/expected/alter.out b/contrib/sepgsql/expected/alter.out index ef9abb3..718aced 100644 --- a/contrib/sepgsql/expected/alter.out +++ b/contrib/sepgsql/expected/alter.out @@ -48,6 +48,9 @@ LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined 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 { search } 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" 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" @@ -90,6 +93,8 @@ LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" 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; @@ -109,7 +114,13 @@ 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 { search } 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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" @@ -132,10 +143,30 @@ 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 { search } 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" +LINE 1: SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" f... + ^ +QUERY: 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +LINE 1: ...schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_s... + ^ +QUERY: 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +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" 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" diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out index d60c65b..b578b9f 100644 --- a/contrib/sepgsql/expected/ddl.out +++ b/contrib/sepgsql/expected/ddl.out @@ -24,9 +24,12 @@ LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_ 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" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" 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); +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" 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" @@ -39,12 +42,27 @@ 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +LINE 1: CREATE TABLE regtest_table (x serial primary key, y text); + ^ +LOG: SELinux: allowed { search } 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 { 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 { search } 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 { search } 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_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq" ALTER TABLE regtest_table ADD COLUMN z int; +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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" @@ -67,9 +85,11 @@ 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 ( @@ -81,8 +101,12 @@ LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_ SET SESSION AUTHORIZATION regtest_sepgsql_test_user; SET search_path = regtest_schema, public; CREATE TABLE regtest_table_3 (x int, y serial); +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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" @@ -93,12 +117,18 @@ 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } 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 { search } 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_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" CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql AS 'BEGIN RETURN $1 * $1 < 100; END'; +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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; @@ -106,6 +136,14 @@ 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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" @@ -117,6 +155,12 @@ 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_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 { search } 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +LINE 1: CREATE TABLE regtest_table_4 (x int primary key, y int, z in... + ^ +LOG: SELinux: allowed { search } 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 { 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); @@ -126,6 +170,8 @@ 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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" @@ -156,9 +202,11 @@ LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t: -- DROP Permission checks (with clean-up) -- DROP FUNCTION regtest_func(text,int[]); +LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema pg_catalog" 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; @@ -187,6 +235,8 @@ LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t: 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" 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" @@ -207,6 +257,8 @@ 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 { search } 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 { search } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema public" 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/expected/dml.out b/contrib/sepgsql/expected/dml.out index 1a29a63..3b90f89 100644 --- a/contrib/sepgsql/expected/dml.out +++ b/contrib/sepgsql/expected/dml.out @@ -47,6 +47,12 @@ ORDER BY objname; column | t5.g | system_u:object_r:sepgsql_secret_table_t:s0 (8 rows) +CREATE SCHEMA my_schema_1; +CREATE TABLE my_schema_1.ts1 (a int, b text); +CREATE SCHEMA my_schema_2; +CREATE TABLE my_schema_2.ts2 (x int, y text); +SECURITY LABEL ON SCHEMA my_schema_2 + IS 'system_u:object_r:sepgsql_regtest_invisible_schema_t:s0'; -- Hardwired Rules UPDATE pg_attribute SET attisdropped = true WHERE attrelid = 't5'::regclass AND attname = 'f'; -- failed @@ -166,6 +172,23 @@ COPY t5 (e,f) FROM '/dev/null'; -- failed ERROR: SELinux: security policy violation COPY t5 (e) FROM '/dev/null'; -- ok -- +-- Schema search path +-- +SET search_path = my_schema_1, my_schema_2, public; +SELECT * FROM ts1; -- ok + a | b +---+--- +(0 rows) + +SELECT * FROM ts2; -- failed (relation not found) +ERROR: relation "ts2" does not exist +LINE 1: SELECT * FROM ts2; + ^ +SELECT * FROM my_schema_2.ts2; -- failed (policy violation) +ERROR: SELinux: security policy violation +LINE 1: SELECT * FROM my_schema_2.ts2; + ^ +-- -- Clean up -- SELECT sepgsql_getcon(); -- confirm client privilege @@ -180,3 +203,7 @@ DROP TABLE IF EXISTS t3 CASCADE; DROP TABLE IF EXISTS t4 CASCADE; DROP TABLE IF EXISTS t5 CASCADE; DROP TABLE IF EXISTS customer CASCADE; +DROP SCHEMA IF EXISTS my_schema_1 CASCADE; +NOTICE: drop cascades to table my_schema_1.ts1 +DROP SCHEMA IF EXISTS my_schema_2 CASCADE; +NOTICE: drop cascades to table my_schema_2.ts2 diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c index 2cb3aed..c65e428 100644 --- a/contrib/sepgsql/hooks.c +++ b/contrib/sepgsql/hooks.c @@ -236,6 +236,25 @@ sepgsql_object_access(ObjectAccessType access, } break; + case OAT_SCHEMA_SEARCH: + { + ObjectAccessSchemaSearch *ss_arg = arg; + + /* + * XXX - If stacked extension already decided not to allow + * users to search this schema, sepgsql respect it. + */ + if (!ss_arg->ereport_on_violation && !ss_arg->result) + break; + + Assert(classId == NamespaceRelationId); + Assert(ss_arg->result); + ss_arg->result + = sepgsql_schema_search(objectId, + ss_arg->ereport_on_violation); + } + break; + default: elog(ERROR, "unexpected object access type: %d", (int) access); break; diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index ecdfd73..32203c6 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -168,42 +168,45 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel) * * utility routine to check db_schema:{xxx} permissions */ -static void -check_schema_perms(Oid namespaceId, uint32 required) +static bool +check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation) { ObjectAddress object; char *audit_name; + bool result; 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); + result = sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_SCHEMA, + required, + audit_name, + abort_on_violation); pfree(audit_name); + + return result; } /* db_schema:{setattr} permission */ void sepgsql_schema_setattr(Oid namespaceId) { - check_schema_perms(namespaceId, SEPG_DB_SCHEMA__SETATTR); + check_schema_perms(namespaceId, SEPG_DB_SCHEMA__SETATTR, true); } void sepgsql_schema_add_name(Oid namespaceId) { - check_schema_perms(namespaceId, SEPG_DB_SCHEMA__ADD_NAME); + check_schema_perms(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); } void sepgsql_schema_remove_name(Oid namespaceId) { - check_schema_perms(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME); + check_schema_perms(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); } void @@ -211,5 +214,13 @@ sepgsql_schema_rename(Oid namespaceId) { check_schema_perms(namespaceId, SEPG_DB_SCHEMA__ADD_NAME | - SEPG_DB_SCHEMA__REMOVE_NAME); + SEPG_DB_SCHEMA__REMOVE_NAME, true); +} + +bool +sepgsql_schema_search(Oid namespaceId, bool abort_on_violation) +{ + return check_schema_perms(namespaceId, + SEPG_DB_SCHEMA__SEARCH, + abort_on_violation); } diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te index d872945..eaf398d 100644 --- a/contrib/sepgsql/sepgsql-regtest.te +++ b/contrib/sepgsql/sepgsql-regtest.te @@ -1,4 +1,4 @@ -policy_module(sepgsql-regtest, 1.04) +policy_module(sepgsql-regtest, 1.06) gen_require(` all_userspace_class_perms @@ -20,6 +20,9 @@ postgresql_procedure_object(sepgsql_regtest_trusted_proc_exec_t) type sepgsql_nosuch_trusted_proc_exec_t; postgresql_procedure_object(sepgsql_nosuch_trusted_proc_exec_t) +type sepgsql_regtest_invisible_schema_t; +postgresql_schema_object(sepgsql_regtest_invisible_schema_t); + # # Test domains for database administrators # diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index d4ee94b..d3aab7d 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -305,6 +305,7 @@ 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); +extern bool sepgsql_schema_search(Oid namespaceId, bool abort_on_violation); /* * relation.c diff --git a/contrib/sepgsql/sql/dml.sql b/contrib/sepgsql/sql/dml.sql index 94bf31a..97e01c3 100644 --- a/contrib/sepgsql/sql/dml.sql +++ b/contrib/sepgsql/sql/dml.sql @@ -43,6 +43,14 @@ SELECT objtype, objname, label FROM pg_seclabels AND objname in ('t1', 't2', 't3', 't4', 't5', 't5.e', 't5.f', 't5.g') ORDER BY objname; +CREATE SCHEMA my_schema_1; +CREATE TABLE my_schema_1.ts1 (a int, b text); +CREATE SCHEMA my_schema_2; +CREATE TABLE my_schema_2.ts2 (x int, y text); + +SECURITY LABEL ON SCHEMA my_schema_2 + IS 'system_u:object_r:sepgsql_regtest_invisible_schema_t:s0'; + -- Hardwired Rules UPDATE pg_attribute SET attisdropped = true WHERE attrelid = 't5'::regclass AND attname = 'f'; -- failed @@ -108,6 +116,14 @@ COPY t5 (e,f) FROM '/dev/null'; -- failed COPY t5 (e) FROM '/dev/null'; -- ok -- +-- Schema search path +-- +SET search_path = my_schema_1, my_schema_2, public; +SELECT * FROM ts1; -- ok +SELECT * FROM ts2; -- failed (relation not found) +SELECT * FROM my_schema_2.ts2; -- failed (policy violation) + +-- -- Clean up -- -- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c255 @@ -117,3 +133,5 @@ DROP TABLE IF EXISTS t3 CASCADE; DROP TABLE IF EXISTS t4 CASCADE; DROP TABLE IF EXISTS t5 CASCADE; DROP TABLE IF EXISTS customer CASCADE; +DROP SCHEMA IF EXISTS my_schema_1 CASCADE; +DROP SCHEMA IF EXISTS my_schema_2 CASCADE; diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml index a9141ff..bddf5bc 100644 --- a/doc/src/sgml/sepgsql.sgml +++ b/doc/src/sgml/sepgsql.sgml @@ -392,6 +392,13 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100; + For schemas, db_schema:search will be checked. + Unprivileged schemas shall be ignored when user tried to solve a certain + object name underlying this schema. Or, an error shall be raised in case + when explicit qualification was used. + + + For functions, db_procedure:{execute} is defined, but is not checked in this version. diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index b256498..a525644 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -22,6 +22,7 @@ #include "access/htup_details.h" #include "access/xact.h" #include "catalog/dependency.h" +#include "catalog/objectaccess.h" #include "catalog/pg_authid.h" #include "catalog/pg_collation.h" #include "catalog/pg_conversion.h" @@ -2666,7 +2667,10 @@ LookupExplicitNamespace(const char *nspname) if (strcmp(nspname, "pg_temp") == 0) { if (OidIsValid(myTempNamespace)) + { + InvokeSchemaSearchHook(myTempNamespace, true); return myTempNamespace; + } /* * Since this is used only for looking up existing objects, there is @@ -2682,6 +2686,8 @@ LookupExplicitNamespace(const char *nspname) if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, nspname); + /* Schema search hook for this lookup */ + InvokeSchemaSearchHook(namespaceId, true); return namespaceId; } @@ -3421,7 +3427,8 @@ recomputeNamespacePath(void) if (OidIsValid(namespaceId) && !list_member_oid(oidlist, namespaceId) && pg_namespace_aclcheck(namespaceId, roleid, - ACL_USAGE) == ACLCHECK_OK) + ACL_USAGE) == ACLCHECK_OK && + InvokeSchemaSearchHook(namespaceId, false)) oidlist = lappend_oid(oidlist, namespaceId); } } @@ -3430,7 +3437,8 @@ recomputeNamespacePath(void) /* pg_temp --- substitute temp namespace, if any */ if (OidIsValid(myTempNamespace)) { - if (!list_member_oid(oidlist, myTempNamespace)) + if (!list_member_oid(oidlist, myTempNamespace) && + InvokeSchemaSearchHook(myTempNamespace, false)) oidlist = lappend_oid(oidlist, myTempNamespace); } else @@ -3447,7 +3455,8 @@ recomputeNamespacePath(void) if (OidIsValid(namespaceId) && !list_member_oid(oidlist, namespaceId) && pg_namespace_aclcheck(namespaceId, roleid, - ACL_USAGE) == ACLCHECK_OK) + ACL_USAGE) == ACLCHECK_OK && + InvokeSchemaSearchHook(namespaceId, false)) oidlist = lappend_oid(oidlist, namespaceId); } } diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c index 0e6844c..166a4a5 100644 --- a/src/backend/catalog/objectaccess.c +++ b/src/backend/catalog/objectaccess.c @@ -11,6 +11,7 @@ #include "postgres.h" #include "catalog/objectaccess.h" +#include "catalog/pg_namespace.h" /* * Hook on object accesses. This is intended as infrastructure for security @@ -84,3 +85,27 @@ RunObjectPostAlterHook(Oid classId, Oid objectId, int subId, classId, objectId, subId, (void *) &pa_arg); } + +/* + * RunSchemaSearchHook + * + * It is entrypoint of OAT_SCHEMA_SEARCH event + */ +bool +RunSchemaSearchHook(Oid objectId, bool ereport_on_violation) +{ + ObjectAccessSchemaSearch ss_arg; + + /* XXX - should be checked at caller side */ + Assert(object_access_hook != NULL); + + memset(&ss_arg, 0, sizeof(ObjectAccessSchemaSearch)); + ss_arg.ereport_on_violation = ereport_on_violation; + ss_arg.result = true; + + (*object_access_hook)(OAT_SCHEMA_SEARCH, + NamespaceRelationId, objectId, 0, + (void *) &ss_arg); + + return ss_arg.result; +} diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index 21c9797..6bafc97 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -22,6 +22,7 @@ #include "access/htup_details.h" #include "access/xact.h" +#include "catalog/objectaccess.h" #include "catalog/pg_proc.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -355,6 +356,7 @@ HandleFunctionRequest(StringInfo msgBuf) if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(fip->namespace)); + InvokeSchemaSearchHook(fip->namespace, true); aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK) diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h index 1359368..6e67c3f 100644 --- a/src/include/catalog/objectaccess.h +++ b/src/include/catalog/objectaccess.h @@ -27,6 +27,10 @@ * extension can reference two different version of system catalog using * SnapshotNow and SnapshotSelf, to identify which field was altered. * + * OAT_SCHEMA_SEARCH should be invoked prior to object name lookup under + * a particular schema. This event is equivalent to 'use' of schema + * permission at the default access control mechanism. + * * Other types may be added in the future. */ typedef enum ObjectAccessType @@ -34,6 +38,7 @@ typedef enum ObjectAccessType OAT_POST_CREATE, OAT_DROP, OAT_POST_ALTER, + OAT_SCHEMA_SEARCH, } ObjectAccessType; /* @@ -84,6 +89,28 @@ typedef struct } ObjectAccessPostAlter; /* + * Arguments of OAT_SCHEMA_SEARCH + */ +typedef struct +{ + /* + * True, if caller wants to raise an error when extension does not + * admit users to search this schema. In this case, result being set + * shall be ignored in the caller side. Elsewhere, extension should + * set an appropriate result. + */ + bool ereport_on_violation; + + /* + * It should be initialized to true, but extension can switch off + * this value, if it does not want user to search object underlying + * this schema. In case when multiple extensions are stacked, our + * convension is "unanimous vote". + */ + bool result; +} ObjectAccessSchemaSearch; + +/* * Hook, and a macro to invoke it. */ typedef void (*object_access_hook_type) (ObjectAccessType access, @@ -100,6 +127,7 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId, int dropflags); extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId, Oid auxiliaryId, bool is_internal); +extern bool RunSchemaSearchHook(Oid objectId, bool ereport_on_volation); #define InvokeObjectPostCreateHook(classId,objectId,subId) \ InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false) @@ -130,4 +158,9 @@ extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId, (auxiliaryId),(is_internal)); \ } while(0) +#define InvokeSchemaSearchHook(objectId, ereport_on_violation) \ + (!object_access_hook \ + ? true \ + : RunSchemaSearchHook((objectId), (ereport_on_violation))) + #endif /* OBJECTACCESS_H */