sepgsql: Enforce db_schema:search permission.
authorRobert Haas <rhaas@postgresql.org>
Fri, 5 Apr 2013 12:51:31 +0000 (08:51 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 5 Apr 2013 12:51:31 +0000 (08:51 -0400)
KaiGai Kohei, with comment and doc wordsmithing by me

13 files changed:
contrib/sepgsql/expected/alter.out
contrib/sepgsql/expected/ddl.out
contrib/sepgsql/expected/dml.out
contrib/sepgsql/hooks.c
contrib/sepgsql/schema.c
contrib/sepgsql/sepgsql-regtest.te
contrib/sepgsql/sepgsql.h
contrib/sepgsql/sql/dml.sql
doc/src/sgml/sepgsql.sgml
src/backend/catalog/namespace.c
src/backend/catalog/objectaccess.c
src/backend/tcop/fastpath.c
src/include/catalog/objectaccess.h

index ef9abb34ce1efb39a21b9504d5908b69eecbdc15..718aced0cc404646fc37ff26e5c4737d65b4c7bf 100644 (file)
@@ -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"
index d60c65bdb1b1543fd559c92ccddc972cc79e4810..b578b9fe1046a58f953d7edb585970c60bc2624c 100644 (file)
@@ -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
index 1a29a63971bea0eca28471ab8729304f29988fc0..3b90f8934714b55b01fe407eff8a35d2de387c18 100644 (file)
@@ -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
index 0715aa8bc6e802d0ad80245cd8c0db41ad86b619..5faa1ea797fb48b1aa5af972e9d2861dadd7bc2e 100644 (file)
@@ -236,6 +236,25 @@ sepgsql_object_access(ObjectAccessType access,
            }
            break;
 
+       case OAT_NAMESPACE_SEARCH:
+           {
+               ObjectAccessNamespaceSearch   *ns_arg = arg;
+
+               /*
+                * If stacked extension already decided not to allow users
+                * to search this schema, we just stick with that decision.
+                */
+               if (!ns_arg->result)
+                   break;
+
+               Assert(classId == NamespaceRelationId);
+               Assert(ns_arg->result);
+               ns_arg->result
+                   = sepgsql_schema_search(objectId,
+                                           ns_arg->ereport_on_violation);
+           }
+           break;
+
        default:
            elog(ERROR, "unexpected object access type: %d", (int) access);
            break;
index 74e16678cb5e8c55fcbc50dc63b07143ff3758ba..bafe17adcd0d34bc0b37fa30b24d6ab21ac92005 100644 (file)
@@ -173,42 +173,54 @@ 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);
+}
+
+/* db_schema:{search} permission */
+bool
+sepgsql_schema_search(Oid namespaceId, bool abort_on_violation)
+{
+   return check_schema_perms(namespaceId,
+                             SEPG_DB_SCHEMA__SEARCH,
+                             abort_on_violation);
 }
 
 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
@@ -216,5 +228,6 @@ 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);
 }
index 790c4e85bb49235a93ead0bffbe89491b75abd0e..823384ecc6765fbc3af89974e2fee1f1286c8377 100644 (file)
@@ -1,4 +1,4 @@
-policy_module(sepgsql-regtest, 1.05)
+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
 #
index f7448cdeb68b35d47887c13e011bfbdf414b4b2b..37d7455fd256a6787d022c971cb13286c3bf5eb2 100644 (file)
@@ -303,6 +303,7 @@ 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 bool sepgsql_schema_search(Oid namespaceId, bool abort_on_violation);
 extern void sepgsql_schema_add_name(Oid namespaceId);
 extern void sepgsql_schema_remove_name(Oid namespaceId);
 extern void sepgsql_schema_rename(Oid namespaceId);
index 94bf31a97af9bee8e9807bd7a48fa2b300332f1d..97e01c3e3c4100ef0d93b40aec0ef3280c13b837 100644 (file)
@@ -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
@@ -107,6 +115,14 @@ COPY t5 FROM '/dev/null';          -- failed
 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
 --
@@ -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;
index da0915bff3a2954a40f8da15750982a334e30b43..0a2ee86a111f8684a1ae0332e791710c8e828a45 100644 (file)
@@ -397,6 +397,16 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
     checked in this version.
    </para>
 
+   <para>
+    In order to access any schema object, <literal>db_schema:search</>
+    permission is required on the containing schema.  When an object is
+    referenced without schema qualification, schemas on which this
+    permission is not present will not be searched (just as if the user did
+    not have <literal>USAGE</> privilege on the schema).  If an explicit schema
+    qualification is present, an error will occur if the user does not have
+    the requisite permission on the named schema.
+   </para>
+
    <para>
     The client must be allowed to access all referenced tables and
     columns, even if they originated from views which were then expanded,
index 07a8761709e5c337c9319505e235d5659280adaa..f48c0bcb31f27c4a2b05764a080d35a2bfd7cbbd 100644 (file)
@@ -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"
@@ -2655,7 +2656,10 @@ LookupNamespaceNoError(const char *nspname)
    if (strcmp(nspname, "pg_temp") == 0)
    {
        if (OidIsValid(myTempNamespace))
+       {
+           InvokeNamespaceSearchHook(myTempNamespace, true);
            return myTempNamespace;
+       }
 
        /*
         * Since this is used only for looking up existing objects, there is
@@ -2702,6 +2706,8 @@ LookupExplicitNamespace(const char *nspname, bool missing_ok)
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       nspname);
+   /* Schema search hook for this lookup */
+   InvokeNamespaceSearchHook(namespaceId, true);
 
    return namespaceId;
 }
@@ -3468,7 +3474,8 @@ recomputeNamespacePath(void)
                if (OidIsValid(namespaceId) &&
                    !list_member_oid(oidlist, namespaceId) &&
                    pg_namespace_aclcheck(namespaceId, roleid,
-                                         ACL_USAGE) == ACLCHECK_OK)
+                                         ACL_USAGE) == ACLCHECK_OK &&
+                   InvokeNamespaceSearchHook(namespaceId, false))
                    oidlist = lappend_oid(oidlist, namespaceId);
            }
        }
@@ -3477,7 +3484,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) &&
+                   InvokeNamespaceSearchHook(myTempNamespace, false))
                    oidlist = lappend_oid(oidlist, myTempNamespace);
            }
            else
@@ -3494,7 +3502,8 @@ recomputeNamespacePath(void)
            if (OidIsValid(namespaceId) &&
                !list_member_oid(oidlist, namespaceId) &&
                pg_namespace_aclcheck(namespaceId, roleid,
-                                     ACL_USAGE) == ACLCHECK_OK)
+                                     ACL_USAGE) == ACLCHECK_OK &&
+               InvokeNamespaceSearchHook(namespaceId, false))
                oidlist = lappend_oid(oidlist, namespaceId);
        }
    }
index bc565ebe497f3ef72ff67e9f6142394a9523cfe1..f70797f2643311ac6fff418c22ecc86a29daa21e 100644 (file)
@@ -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);
 }
+
+/*
+ * RunNamespaceSearchHook
+ *
+ * It is entrypoint of OAT_NAMESPACE_SEARCH event
+ */
+bool
+RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation)
+{
+   ObjectAccessNamespaceSearch ns_arg;
+
+   /* XXX - should be checked at caller side */
+   Assert(object_access_hook != NULL);
+
+   memset(&ns_arg, 0, sizeof(ObjectAccessNamespaceSearch));
+   ns_arg.ereport_on_violation = ereport_on_violation;
+   ns_arg.result = true;
+
+   (*object_access_hook)(OAT_NAMESPACE_SEARCH,
+                         NamespaceRelationId, objectId, 0,
+                         (void *) &ns_arg);
+
+   return ns_arg.result;
+}
index 21c979753e0641866d8d7501fbbe04412725c542..016e7d9ec66b20a8758ec4c2578712dd73880d06 100644 (file)
@@ -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));
+   InvokeNamespaceSearchHook(fip->namespace, true);
 
    aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
    if (aclresult != ACLCHECK_OK)
index 25f963b0748f13f661b3ae3154529cca2a36ae68..12ae55f498c4c4320ad7fe43fae234bcf8ee3720 100644 (file)
  * hook can use SnapshotNow and SnapshotSelf to get the old and new
  * versions of the tuple.
  *
+ * OAT_NAMESPACE_SEARCH should be invoked prior to object name lookup under
+ * a particular namespace. This event is equivalent to usage permission
+ * permission on a schema under 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_NAMESPACE_SEARCH,
 } ObjectAccessType;
 
 /*
@@ -84,6 +89,28 @@ typedef struct
    bool        is_internal;
 } ObjectAccessPostAlter;
 
+/*
+ * Arguments of OAT_NAMESPACE_SEARCH
+ */
+typedef struct
+{
+   /*
+    * If true, hook should report an error when permission to search this
+    * schema is denied.
+    */
+   bool        ereport_on_violation;
+
+   /*
+    * This is, in essence, an out parameter.  Core code should
+    * initialize this to true, and any extension that wants to deny
+    * access should reset it to false.  But an extension should be
+    * careful never to store a true value here, so that in case there are
+    * multiple extensions access is only allowed if all extensions
+    * agree.
+    */
+   bool        result;
+} ObjectAccessNamespaceSearch;
+
 /* Plugin provides a hook function matching this signature. */
 typedef void (*object_access_hook_type) (ObjectAccessType access,
                                                     Oid classId,
@@ -101,6 +128,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 RunNamespaceSearchHook(Oid objectId, bool ereport_on_volation);
 
 /*
  * The following macros are wrappers around the functions above; these should
@@ -137,4 +165,9 @@ extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
                                   (auxiliaryId),(is_internal));    \
    } while(0)
 
+#define InvokeNamespaceSearchHook(objectId, ereport_on_violation)  \
+   (!object_access_hook                                            \
+    ? true                                                         \
+    : RunNamespaceSearchHook((objectId), (ereport_on_violation)))
+
 #endif   /* OBJECTACCESS_H */