[sepgsql 2/3] Add db_schema:search permission checks
This patch adds sepgsql support for permission checks equivalent
to the existing SCHEMA USE privilege.
This feature is constructed on new OAT_SCHEMA_SEARCH event
type being invoked around pg_namespace_aclcheck().
So, its expected behavior also follows the behavior of existing
permissions; unprivileged schema is ignored from the search path,
or raise an error if object name is fully qualified.
This patch needs src/backend/catalog/objectaccess.c is existing,
so please apply this patch on top of this feature.
https://commitfest.postgresql.org/action/patch_view?id=1003
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-schema-search-permission.v1.patchapplication/octet-stream; name=sepgsql-v9.3-schema-search-permission.v1.patchDownload
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;
</para>
<para>
+ For schemas, <literal>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.
+ </para>
+
+ <para>
For functions, <literal>db_procedure:{execute}</> is defined, but is not
checked in this version.
</para>
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 */
On 15 January 2013 20:28, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
This patch adds sepgsql support for permission checks equivalent
to the existing SCHEMA USE privilege.This feature is constructed on new OAT_SCHEMA_SEARCH event
type being invoked around pg_namespace_aclcheck().
Can you explain the exact detailed rationale behind this patch? Like
URLs or other info that explains *why* we are doing this, what
problems it causes if we don't, etc?
Otherwise there is no reference point for a review. Other patch types
like new features have syntax we can discuss and check, performance
patches have measurements we can check. With this, it is just "we add
some checks". No idea if that is all the places we need, or whether
there is a better way of doing this, or whether anyone cares if we do
this or not.
(Same comment for patch 3/3)
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/1/29 Simon Riggs <simon@2ndquadrant.com>:
On 15 January 2013 20:28, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
This patch adds sepgsql support for permission checks equivalent
to the existing SCHEMA USE privilege.This feature is constructed on new OAT_SCHEMA_SEARCH event
type being invoked around pg_namespace_aclcheck().Can you explain the exact detailed rationale behind this patch? Like
URLs or other info that explains *why* we are doing this, what
problems it causes if we don't, etc?
Sorry for this inconvenient. The second and third sepgsql patch try to
add permission checks on the places being not covered by sepgsql,
even though we defined related permissions; search of db_schema
and execute of db_procedure.
It is unavailable to control user's access towards these objects from
perspective of selinux policy, without these patches, even though
existing DAC mechanism well controls.
Right now, sepgsql applies no checks when users tried to lookup
an object name underlying a particular schema. It is inconvenient
to set up an environment that enforces per-domain namespace
according to the selinux basis, because current sepgsql ignores
searching schema, thus, it means all the schema is allowed to
search from viewpoint of selinux.
What we want to do is almost same as existing permission checks
are doing when users tried to search a particular schema, except
for its criteria to make access control decision.
Also, sepgsql applies no checks when users tries to execute
functions, right now. It makes unavailable to control execution of
functions from viewpoint of selinux, and here is no way selinux
to prevent to execute functions defined by other domains, or
others being not permitted.
Also, what we want to do is almost same as existing permission
checks, except for its criteria to make access control decision.
SELinux model requires client domain has db_schema:{search}
permission when it tries to search its underlying objects, and
client domain has db_procedure:{execute} permission when
it tries to execute the function and db_procedure:{entrypoint}
additionally if this execution performs as entrypoint of trusted-
procedures.
These are the problems behind of these patches.
In short, I'd like to give sepgsql configuration more flexibility
as existing DAC doing. That helps use cases of typical SaaS
applications that shares a database with multiple clients but
to be separated each other.
It is the motivation why I'd like to add these permissions here.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 29 January 2013 13:30, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
It makes unavailable to control execution of
functions from viewpoint of selinux, and here is no way selinux
to prevent to execute functions defined by other domains, or
others being not permitted.
Also, what we want to do is almost same as existing permission
checks, except for its criteria to make access control decision.
Do you have a roadmap of all the things this relates to?
If selinux has a viewpoint, I'd like to be able to see a list of
capabilities and then which ones are currently missing. I guess I'm
looking for external assurance that someone somewhere needs this and
that it fits into a complete overall plan of what we should do. Just
like we are able to use SQLStandard as a guide as to what we need to
implement, we would like something to refer back to. Does this have a
request id, specification document page number or whatever?
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/1/29 Simon Riggs <simon@2ndquadrant.com>:
On 29 January 2013 13:30, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
It makes unavailable to control execution of
functions from viewpoint of selinux, and here is no way selinux
to prevent to execute functions defined by other domains, or
others being not permitted.
Also, what we want to do is almost same as existing permission
checks, except for its criteria to make access control decision.Do you have a roadmap of all the things this relates to?
If selinux has a viewpoint, I'd like to be able to see a list of
capabilities and then which ones are currently missing. I guess I'm
looking for external assurance that someone somewhere needs this and
that it fits into a complete overall plan of what we should do. Just
like we are able to use SQLStandard as a guide as to what we need to
implement, we would like something to refer back to. Does this have a
request id, specification document page number or whatever?
I previously made several wiki pages for reference of permissions
to be checked, but it needs maintenance works towards the latest
state, such as newly added permissions.
http://wiki.postgresql.org/wiki/SEPostgreSQL_References
Even though selinuxproject.org hosts permission list, it is more
rough than what I described at wiki.postgresql.org.
http://www.selinuxproject.org/page/ObjectClassesPerms#Database_Object_Classes
Unlike SQL standard, we have less resource to document its spec
being validated by third persons. However, it is a reasonable solution
to write up which permission shall be checked on which timing.
Let me revise the above wikipage to show my overall plan.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 29 January 2013 14:39, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2013/1/29 Simon Riggs <simon@2ndquadrant.com>:
On 29 January 2013 13:30, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
It makes unavailable to control execution of
functions from viewpoint of selinux, and here is no way selinux
to prevent to execute functions defined by other domains, or
others being not permitted.
Also, what we want to do is almost same as existing permission
checks, except for its criteria to make access control decision.Do you have a roadmap of all the things this relates to?
If selinux has a viewpoint, I'd like to be able to see a list of
capabilities and then which ones are currently missing. I guess I'm
looking for external assurance that someone somewhere needs this and
that it fits into a complete overall plan of what we should do. Just
like we are able to use SQLStandard as a guide as to what we need to
implement, we would like something to refer back to. Does this have a
request id, specification document page number or whatever?I previously made several wiki pages for reference of permissions
to be checked, but it needs maintenance works towards the latest
state, such as newly added permissions.
http://wiki.postgresql.org/wiki/SEPostgreSQL_ReferencesEven though selinuxproject.org hosts permission list, it is more
rough than what I described at wiki.postgresql.org.
http://www.selinuxproject.org/page/ObjectClassesPerms#Database_Object_ClassesUnlike SQL standard, we have less resource to document its spec
being validated by third persons. However, it is a reasonable solution
to write up which permission shall be checked on which timing.Let me revise the above wikipage to show my overall plan.
OK, that's looking like a good and useful set of info.
What we need to do is to give the SELinux API a spec/version number
(yes, the SELinux one) and then match what PostgreSQL implements
against that, so we can say we are moving towards spec compliance with
1.0 and we have a list of unimplemented features...
That puts this in a proper context, so we know what we are doing, why
we are doing it and also when we've finished it. And also, how to know
what future external changes will cause additional work.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/29/2013 10:10 PM, Simon Riggs wrote:
On 29 January 2013 13:30, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
It makes unavailable to control execution of
functions from viewpoint of selinux, and here is no way selinux
to prevent to execute functions defined by other domains, or
others being not permitted.
Also, what we want to do is almost same as existing permission
checks, except for its criteria to make access control decision.Do you have a roadmap of all the things this relates to?
If selinux has a viewpoint, I'd like to be able to see a list of
capabilities and then which ones are currently missing. I guess I'm
looking for external assurance that someone somewhere needs this and
that it fits into a complete overall plan of what we should do. Just
like we are able to use SQLStandard as a guide as to what we need to
implement, we would like something to refer back to. Does this have a
request id, specification document page number or whatever?
I think that would greatly assist people in understanding why these
patches are neccessary, what real-world functionality they lead to, and
what problems they solve.
Some info on the wiki may be a good option.
For example, if you were to say "these changes will help with
multi-tenant PostgreSQL installations by <x>" then that will catch some
people's eye.
--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Sorry for my late updates.
I tried to update list of permissions that sepgsql expects, even though
the description might be still a bit rough...
https://wiki.postgresql.org/wiki/SEPostgreSQL_Permissions
Set of permissions are defined for each object class that represents
a particular database object. This list summarize all the defined
permissions and introduction of the case when it shall be checked.
Right now, the list of permissions are based on the latest selinux
policy release at 20120725, but db_materialized_view class will
be (probably) added in the future release somewhere in 2013.
So, I added a short mention of this.
My 2/3 and 3.3 patch try to add support "search" permission of
db_schema class and "execute" permission of db_procedure class.
It tries to implement relevant checks, but not supported yet.
Does the permission list help to understand what does these
patch try to tackle?
Thanks,
2013/1/29 Simon Riggs <simon@2ndquadrant.com>:
On 29 January 2013 14:39, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
2013/1/29 Simon Riggs <simon@2ndquadrant.com>:
On 29 January 2013 13:30, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
It makes unavailable to control execution of
functions from viewpoint of selinux, and here is no way selinux
to prevent to execute functions defined by other domains, or
others being not permitted.
Also, what we want to do is almost same as existing permission
checks, except for its criteria to make access control decision.Do you have a roadmap of all the things this relates to?
If selinux has a viewpoint, I'd like to be able to see a list of
capabilities and then which ones are currently missing. I guess I'm
looking for external assurance that someone somewhere needs this and
that it fits into a complete overall plan of what we should do. Just
like we are able to use SQLStandard as a guide as to what we need to
implement, we would like something to refer back to. Does this have a
request id, specification document page number or whatever?I previously made several wiki pages for reference of permissions
to be checked, but it needs maintenance works towards the latest
state, such as newly added permissions.
http://wiki.postgresql.org/wiki/SEPostgreSQL_ReferencesEven though selinuxproject.org hosts permission list, it is more
rough than what I described at wiki.postgresql.org.
http://www.selinuxproject.org/page/ObjectClassesPerms#Database_Object_ClassesUnlike SQL standard, we have less resource to document its spec
being validated by third persons. However, it is a reasonable solution
to write up which permission shall be checked on which timing.Let me revise the above wikipage to show my overall plan.
OK, that's looking like a good and useful set of info.
What we need to do is to give the SELinux API a spec/version number
(yes, the SELinux one) and then match what PostgreSQL implements
against that, so we can say we are moving towards spec compliance with
1.0 and we have a list of unimplemented features...That puts this in a proper context, so we know what we are doing, why
we are doing it and also when we've finished it. And also, how to know
what future external changes will cause additional work.--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Jan 15, 2013 at 3:28 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
This patch adds sepgsql support for permission checks equivalent
to the existing SCHEMA USE privilege.This feature is constructed on new OAT_SCHEMA_SEARCH event
type being invoked around pg_namespace_aclcheck().
So, its expected behavior also follows the behavior of existing
permissions; unprivileged schema is ignored from the search path,
or raise an error if object name is fully qualified.This patch needs src/backend/catalog/objectaccess.c is existing,
so please apply this patch on top of this feature.
https://commitfest.postgresql.org/action/patch_view?id=1003
KaiGai,
Could you please rebase this patch?
Thanks,
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/4/1 Robert Haas <robertmhaas@gmail.com>:
On Tue, Jan 15, 2013 at 3:28 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
This patch adds sepgsql support for permission checks equivalent
to the existing SCHEMA USE privilege.This feature is constructed on new OAT_SCHEMA_SEARCH event
type being invoked around pg_namespace_aclcheck().
So, its expected behavior also follows the behavior of existing
permissions; unprivileged schema is ignored from the search path,
or raise an error if object name is fully qualified.This patch needs src/backend/catalog/objectaccess.c is existing,
so please apply this patch on top of this feature.
https://commitfest.postgresql.org/action/patch_view?id=1003KaiGai,
Could you please rebase this patch?
OK, please check the attached ones.
Both patches were rebased to the latest master branch, thus, once either
of them got committed, another one has to be rebased later.
Please also pay attention security policy module for regression test was
also adjusted for these features.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-schema-search-permission.v3.patchapplication/octet-stream; name=sepgsql-v9.3-schema-search-permission.v3.patchDownload
contrib/sepgsql/expected/alter.out | 31 +++++++++++++++++++++++
contrib/sepgsql/expected/ddl.out | 52 ++++++++++++++++++++++++++++++++++++++
contrib/sepgsql/expected/dml.out | 27 ++++++++++++++++++++
contrib/sepgsql/hooks.c | 21 +++++++++++++++
contrib/sepgsql/schema.c | 35 +++++++++++++++++--------
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, 257 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 0715aa8..7b79359 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -236,6 +236,27 @@ sepgsql_object_access(ObjectAccessType access,
}
break;
+ case OAT_SCHEMA_SEARCH:
+ {
+ ObjectAccessSchemaSearch *ss_arg = arg;
+
+ /*
+ * If stacked extension already decided not to allow users
+ * to search this schema, sepgsql does not reverse this
+ * suggestion any more, regardless of SELinux's permission
+ * checks.
+ */
+ if (!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 74e1667..bafe17a 100644
--- a/contrib/sepgsql/schema.c
+++ b/contrib/sepgsql/schema.c
@@ -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);
}
diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te
index 790c4e8..823384e 100644
--- a/contrib/sepgsql/sepgsql-regtest.te
+++ b/contrib/sepgsql/sepgsql-regtest.te
@@ -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
#
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index f7448cd..37d7455 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -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);
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 da0915b..469140d 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -393,6 +393,13 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
</para>
<para>
+ For schemas, <literal>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.
+ </para>
+
+ <para>
For functions, <literal>db_procedure:{execute}</> is defined, but is not
checked in this version.
</para>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 07a8761..34c44da 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"
@@ -2655,7 +2656,10 @@ LookupNamespaceNoError(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
@@ -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 */
+ InvokeSchemaSearchHook(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 &&
+ InvokeSchemaSearchHook(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) &&
+ InvokeSchemaSearchHook(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 &&
+ InvokeSchemaSearchHook(namespaceId, false))
oidlist = lappend_oid(oidlist, namespaceId);
}
}
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index bc565eb..51a9a2e 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 25f963b..885d21a 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -27,6 +27,10 @@
* hook can use SnapshotNow and SnapshotSelf to get the old and new
* versions of the tuple.
*
+ * 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
bool is_internal;
} 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;
+
/* 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 RunSchemaSearchHook(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 InvokeSchemaSearchHook(objectId, ereport_on_violation) \
+ (!object_access_hook \
+ ? true \
+ : RunSchemaSearchHook((objectId), (ereport_on_violation)))
+
#endif /* OBJECTACCESS_H */
sepgsql-v9.3-function-execute-permission.v3.patchapplication/octet-stream; name=sepgsql-v9.3-function-execute-permission.v3.patchDownload
contrib/sepgsql/expected/label.out | 17 +++++++++
contrib/sepgsql/expected/misc.out | 67 ++++++++++++++++++++++++++++++++++++
contrib/sepgsql/hooks.c | 8 +++++
contrib/sepgsql/label.c | 23 +++++++++++--
contrib/sepgsql/proc.c | 26 ++++++++++++++
contrib/sepgsql/sepgsql-regtest.te | 17 ++-------
contrib/sepgsql/sepgsql.h | 1 +
contrib/sepgsql/sql/label.sql | 2 ++
contrib/sepgsql/sql/misc.sql | 25 ++++++++++++++
doc/src/sgml/sepgsql.sgml | 7 ++--
src/backend/catalog/objectaccess.c | 17 +++++++++
src/backend/executor/execQual.c | 3 ++
src/backend/executor/nodeAgg.c | 4 +++
src/backend/executor/nodeWindowAgg.c | 4 +++
src/backend/tcop/fastpath.c | 2 ++
src/include/catalog/objectaccess.h | 14 ++++++++
16 files changed, 218 insertions(+), 19 deletions(-)
diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out
index 0a15f27..18bdf81 100644
--- a/contrib/sepgsql/expected/label.out
+++ b/contrib/sepgsql/expected/label.out
@@ -131,23 +131,40 @@ SELECT sepgsql_getcon(); -- confirm client privilege
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
(1 row)
+SET sepgsql.debug_audit = true;
+SET client_min_messages = log;
SELECT f1(); -- normal procedure
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function f1()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+CONTEXT: SQL function "f1" statement 1
f1
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
(1 row)
SELECT f2(); -- trusted procedure
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
+LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
+LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+CONTEXT: SQL function "f2" statement 1
f2
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0
(1 row)
SELECT f3(); -- trusted procedure that raises an error
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
+LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
+LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
ERROR: an exception from f3()
SELECT f4(); -- failed on domain transition
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
+LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
+LOG: SELinux: denied { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_regtest_nosuch_t:s0 tclass=process
ERROR: SELinux: security policy violation
SELECT sepgsql_getcon(); -- client's label must be restored
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
sepgsql_getcon
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
diff --git a/contrib/sepgsql/expected/misc.out b/contrib/sepgsql/expected/misc.out
index 329852c..aaa5d25 100644
--- a/contrib/sepgsql/expected/misc.out
+++ b/contrib/sepgsql/expected/misc.out
@@ -3,3 +3,70 @@
--
LOAD '$libdir/sepgsql'; -- failed
ERROR: SELinux: LOAD is not permitted
+--
+-- Permissions to execute functions
+--
+CREATE TABLE t1 (x int, y text);
+INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
+SET sepgsql.debug_audit = on;
+SET client_min_messages = log;
+-- regular function and operators
+SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4gt(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
+ x | y
+-----+----------------------------------
+ 77 | 28dd2c7955ce926456240b2ff0100bde
+ 89 | 7647966b7343c29048673252e490f736
+ 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 91 | 54229abfcfa5649e7003b83dd4755294
+ 99 | ac627ab1ccbdb62ec96e702f07f6425b
+ 100 | f899139df5e1059396431415e770c6dd
+(6 rows)
+
+-- aggregate function
+SELECT MIN(x), AVG(x) FROM t1;
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function avg(integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4_avg_accum(bigint[],integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int8_avg(bigint[])"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function min(integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4smaller(integer,integer)"
+ min | avg
+-----+---------------------
+ 1 | 50.5000000000000000
+(1 row)
+
+-- window function
+SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function row_number()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
+ row_number | x | y
+------------+----+----------------------------------
+ 1 | 2 | c81e728d9d4c2f636f067f89cc14862c
+ 2 | 17 | 70efdf2ec9b086079795c442636b55fb
+ 3 | 22 | b6d767d2f8ed5d21a44b0e5886680cb9
+ 4 | 27 | 02e74f10e0327ad868d138f2b4fdd6f0
+ 5 | 33 | 182be0c5cdcd5072bb1864cdee4d3d6e
+ 6 | 43 | 17e62166fc8586dfa4d1bc0e1742c08b
+ 7 | 54 | a684eceee76fc522773286a895bc8436
+ 8 | 73 | d2ddea18f00665ce8623e36bd4e3c7c5
+ 9 | 76 | fbd7939d674997cdb4692d34de8633c4
+ 10 | 89 | 7647966b7343c29048673252e490f736
+ 11 | 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 12 | 94 | f4b9ec30ad9f68f89b29639786cb62ef
+(12 rows)
+
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+--
+-- Cleanup
+--
+DROP TABLE IF EXISTS t1 CASCADE;
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 0715aa8..2ad46a8 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -236,6 +236,14 @@ sepgsql_object_access(ObjectAccessType access,
}
break;
+ case OAT_FUNCTION_EXEC:
+ {
+ Assert(classId == ProcedureRelationId);
+ sepgsql_proc_execute(objectId);
+
+ }
+ break;
+
default:
elog(ERROR, "unexpected object access type: %d", (int) access);
break;
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index a5bdde3..6146399 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -303,7 +303,8 @@ sepgsql_needs_fmgr_hook(Oid functionId)
object.objectSubId = 0;
if (!sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
- SEPG_DB_PROCEDURE__EXECUTE,
+ SEPG_DB_PROCEDURE__EXECUTE |
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
SEPGSQL_AVC_NOAUDIT, false))
return true;
@@ -347,13 +348,31 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
* process:transition permission between old and new label,
* when user tries to switch security label of the client on
* execution of trusted procedure.
+ *
+ * Also, db_procedure:entrypoint permission should be checked
+ * whether this procedure can perform as an entrypoint of the
+ * trusted procedure, or not.
+ * Note that db_procedure:execute permission shall be checked
+ * individually.
*/
if (stack->new_label)
+ {
+ ObjectAddress object;
+
+ object.classId = ProcedureRelationId;
+ object.objectId = flinfo->fn_oid;
+ object.objectSubId = 0;
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
+ getObjectDescription(&object),
+ true);
+
sepgsql_avc_check_perms_label(stack->new_label,
SEPG_CLASS_PROCESS,
SEPG_PROCESS__TRANSITION,
NULL, true);
-
+ }
*private = PointerGetDatum(stack);
}
Assert(!stack->old_label);
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index afc3755..0cd2c8c 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -301,3 +301,29 @@ sepgsql_proc_setattr(Oid functionId)
systable_endscan(sscan);
heap_close(rel, AccessShareLock);
}
+
+/*
+ * sepgsql_proc_execute
+ *
+ * It checks privileges to execute the supplied function
+ */
+void
+sepgsql_proc_execute(Oid functionId)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * check db_procedure:{execute} permission
+ */
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ audit_name = getObjectDescription(&object);
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__EXECUTE,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te
index 790c4e8..37c0316 100644
--- a/contrib/sepgsql/sepgsql-regtest.te
+++ b/contrib/sepgsql/sepgsql-regtest.te
@@ -1,4 +1,4 @@
-policy_module(sepgsql-regtest, 1.05)
+policy_module(sepgsql-regtest, 1.06)
gen_require(`
all_userspace_class_perms
@@ -176,18 +176,5 @@ optional_policy(`
gen_require(`
attribute sepgsql_client_type;
')
- allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute };
-
- # These rules intends sepgsql_regtest_user_t domain to translate
- # sepgsql_regtest_dba_t on execution of procedures labeled as
- # sepgsql_regtest_trusted_proc_exec_t.
- #
-# allow sepgsql_client_type sepgsql_regtest_trusted_proc_exec_t:db_procedure { getattr execute };
-
- # These rules intends sepgsql_regtest_user_t domain to translate
- # sepgsql_regtest_nosuch_t on execution of procedures labeled as
- # sepgsql_nosuch_trusted_proc_exec_t, without permissions to
- # translate to sepgsql_nosuch_trusted_proc_exec_t.
- #
-# allow sepgsql_client_type sepgsql_nosuch_trusted_proc_exec_t:db_procedure { getattr execute install };
+ allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute entrypoint };
')
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index f7448cd..56094a8 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -327,5 +327,6 @@ extern void sepgsql_proc_post_create(Oid functionId);
extern void sepgsql_proc_drop(Oid functionId);
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
extern void sepgsql_proc_setattr(Oid functionId);
+extern void sepgsql_proc_execute(Oid functionId);
#endif /* SEPGSQL_H */
diff --git a/contrib/sepgsql/sql/label.sql b/contrib/sepgsql/sql/label.sql
index 6201cd7..7a05c24 100644
--- a/contrib/sepgsql/sql/label.sql
+++ b/contrib/sepgsql/sql/label.sql
@@ -97,6 +97,8 @@ SECURITY LABEL ON COLUMN t2.b
-- Tests for Trusted Procedures
--
-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+SET sepgsql.debug_audit = true;
+SET client_min_messages = log;
SELECT f1(); -- normal procedure
SELECT f2(); -- trusted procedure
SELECT f3(); -- trusted procedure that raises an error
diff --git a/contrib/sepgsql/sql/misc.sql b/contrib/sepgsql/sql/misc.sql
index a46d8a6..c277711 100644
--- a/contrib/sepgsql/sql/misc.sql
+++ b/contrib/sepgsql/sql/misc.sql
@@ -3,3 +3,28 @@
--
LOAD '$libdir/sepgsql'; -- failed
+
+--
+-- Permissions to execute functions
+--
+CREATE TABLE t1 (x int, y text);
+INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
+
+SET sepgsql.debug_audit = on;
+SET client_min_messages = log;
+
+-- regular function and operators
+SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
+
+-- aggregate function
+SELECT MIN(x), AVG(x) FROM t1;
+
+-- window function
+SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
+
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+--
+-- Cleanup
+--
+DROP TABLE IF EXISTS t1 CASCADE;
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index da0915b..715365a 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -393,8 +393,11 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
</para>
<para>
- For functions, <literal>db_procedure:{execute}</> is defined, but is not
- checked in this version.
+ For functions, <literal>db_procedure:{execute}</> will be checked when
+ user tries to execute a function as a part of query, or using fast-path
+ invocation. If this function is a trusted procedure, it also checks
+ <literal>db_procedure:{entrypoint}</> permission to check whether it
+ can perform as entrypoint of trusted procedure.
</para>
<para>
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index bc565eb..3c7d7b0 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_proc.h"
/*
* Hook on object accesses. This is intended as infrastructure for security
@@ -84,3 +85,19 @@ RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
classId, objectId, subId,
(void *) &pa_arg);
}
+
+/*
+ * RunFunctionExecHook
+ *
+ * It is entrypoint of OAT_FUNCTION_EXEC event
+ */
+void
+RunFunctionExecHook(Oid objectId)
+{
+ /* XXX - should be checked at caller side */
+ Assert(object_access_hook != NULL);
+
+ (*object_access_hook)(OAT_FUNCTION_EXEC,
+ ProcedureRelationId, objectId, 0,
+ NULL);
+}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 62d27a7..5b87f4f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -39,6 +39,7 @@
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/tupconvert.h"
+#include "catalog/objectaccess.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "executor/execdebug.h"
@@ -1289,6 +1290,7 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));
+ InvokeFunctionExecHook(foid);
/*
* Safety check on nargs. Under normal circumstances this should never
@@ -4223,6 +4225,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(acoerce->elemfuncid));
+ InvokeFunctionExecHook(acoerce->elemfuncid);
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 7efc490..55ab150 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -79,6 +79,7 @@
#include "postgres.h"
#include "access/htup_details.h"
+#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@@ -1625,6 +1626,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(aggref->aggfnoid));
+ InvokeFunctionExecHook(aggref->aggfnoid);
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
@@ -1647,6 +1649,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(transfn_oid));
+ InvokeFunctionExecHook(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
@@ -1654,6 +1657,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(finalfn_oid));
+ InvokeFunctionExecHook(finalfn_oid);
}
}
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 3bc42ba..6e76dc6 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -34,6 +34,7 @@
#include "postgres.h"
#include "access/htup_details.h"
+#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@@ -1559,6 +1560,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(wfunc->winfnoid));
+ InvokeFunctionExecHook(wfunc->winfnoid);
/* Fill in the perfuncstate data */
perfuncstate->wfuncstate = wfuncstate;
@@ -1767,6 +1769,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(transfn_oid));
+ InvokeFunctionExecHook(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
@@ -1774,6 +1777,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(finalfn_oid));
+ InvokeFunctionExecHook(finalfn_oid);
}
}
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 21c9797..2e655ed 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"
@@ -360,6 +361,7 @@ HandleFunctionRequest(StringInfo msgBuf)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(fid));
+ InvokeFunctionExecHook(fid);
/*
* Prepare function call info block and insert arguments.
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 25f963b..119d1d1 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -27,6 +27,12 @@
* hook can use SnapshotNow and SnapshotSelf to get the old and new
* versions of the tuple.
*
+ * OAT_FUNCTION_EXEC should be invoked prior to function execution.
+ * This event is almost equivalent to ACL_EXECUTE permission on functions,
+ * but isn't invoked where ACL_EXECUTE is checked during object creation
+ * or altering. (Extensions can check same stuff on OAT_POST_CREATE or
+ * OAT_POST_ALTER events).
+ *
* Other types may be added in the future.
*/
typedef enum ObjectAccessType
@@ -34,6 +40,7 @@ typedef enum ObjectAccessType
OAT_POST_CREATE,
OAT_DROP,
OAT_POST_ALTER,
+ OAT_FUNCTION_EXEC,
} ObjectAccessType;
/*
@@ -101,6 +108,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 void RunFunctionExecHook(Oid objectId);
/*
* The following macros are wrappers around the functions above; these should
@@ -137,4 +145,10 @@ extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
(auxiliaryId),(is_internal)); \
} while(0)
+#define InvokeFunctionExecHook(objectId) \
+ do { \
+ if (object_access_hook) \
+ RunFunctionExecHook(objectId); \
+ } while(0)
+
#endif /* OBJECTACCESS_H */
On Tue, Apr 2, 2013 at 2:22 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
OK, please check the attached ones.
Thanks. I reviewed the schema-search patch and I think it looks
reasonable, but shouldn't we be calling the event OAT_NAMESPACE_SEARCH
rather than OAT_SCHEMA_SEARCH? And, similarly,
ObjectAccessNamespaceSearch and InvokeNamespaceSearchHook? I think
this terminology could be confusing to backend hackers who are used to
seeing the term "namespace" internally when referring to schemas.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/4/3 Robert Haas <robertmhaas@gmail.com>:
On Tue, Apr 2, 2013 at 2:22 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
OK, please check the attached ones.
Thanks. I reviewed the schema-search patch and I think it looks
reasonable, but shouldn't we be calling the event OAT_NAMESPACE_SEARCH
rather than OAT_SCHEMA_SEARCH? And, similarly,
ObjectAccessNamespaceSearch and InvokeNamespaceSearchHook? I think
this terminology could be confusing to backend hackers who are used to
seeing the term "namespace" internally when referring to schemas.
OK, I follow the manner of the terminology as we usually call it.
The attached patch just replaced things you suggested.
I'll also rebase the function-exec permission stuff later.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-schema-search-permission.v4.patchapplication/octet-stream; name=sepgsql-v9.3-schema-search-permission.v4.patchDownload
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 0715aa8..e027c16 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -236,6 +236,27 @@ 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, sepgsql does not reverse this
+ * suggestion any more, regardless of SELinux's permission
+ * checks.
+ */
+ 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;
diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c
index 74e1667..bafe17a 100644
--- a/contrib/sepgsql/schema.c
+++ b/contrib/sepgsql/schema.c
@@ -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);
}
diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te
index 790c4e8..823384e 100644
--- a/contrib/sepgsql/sepgsql-regtest.te
+++ b/contrib/sepgsql/sepgsql-regtest.te
@@ -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
#
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index f7448cd..37d7455 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -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);
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 da0915b..469140d 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -393,6 +393,13 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
</para>
<para>
+ For schemas, <literal>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.
+ </para>
+
+ <para>
For functions, <literal>db_procedure:{execute}</> is defined, but is not
checked in this version.
</para>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 07a8761..f48c0bc 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"
@@ -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);
}
}
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index bc565eb..f70797f 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);
}
+
+/*
+ * 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;
+}
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 21c9797..016e7d9 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));
+ InvokeNamespaceSearchHook(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 25f963b..d9a64a7 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -27,6 +27,10 @@
* 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 '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_NAMESPACE_SEARCH,
} ObjectAccessType;
/*
@@ -84,6 +89,28 @@ typedef struct
bool is_internal;
} ObjectAccessPostAlter;
+/*
+ * Arguments of OAT_NAMESPACE_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;
+} 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 */
On Thu, Apr 4, 2013 at 8:26 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
OK, I follow the manner of the terminology as we usually call it.
The attached patch just replaced things you suggested.
Thanks, I have committed this, after making some changes to the
comments and documentation. Please review the changes and let me know
if you see any mistakes.
BTW, if it were possible to set things up so that the test_sepgsql
script could validate the version of the sepgsql-regtest policy
installed, that would eliminate a certain category of errors. I
notice also that the regression tests themselves seem to fail if you
invoke the script as contrib/sepgsql/test_sepgsql rather than
./test_sepgsql, which suggests another possible pre-validation step.
Thanks,
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/4/5 Robert Haas <robertmhaas@gmail.com>:
On Thu, Apr 4, 2013 at 8:26 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
OK, I follow the manner of the terminology as we usually call it.
The attached patch just replaced things you suggested.Thanks, I have committed this, after making some changes to the
comments and documentation. Please review the changes and let me know
if you see any mistakes.
Thanks. I could find two obvious wording stuffs here, please see smaller
one of the attached patches. I didn't fixup manner to use "XXX" in source
code comments.
Also, the attached function-execute-permission patch is a rebased
version. I rethought its event name should be OAT_FUNCTION_EXECUTE,
rather than OAT_FUNCTION_EXEC according to the manner without
abbreviation. Other portion is same as previous ones.
BTW, if it were possible to set things up so that the test_sepgsql
script could validate the version of the sepgsql-regtest policy
installed, that would eliminate a certain category of errors. I
notice also that the regression tests themselves seem to fail if you
invoke the script as contrib/sepgsql/test_sepgsql rather than
./test_sepgsql, which suggests another possible pre-validation step.
Please see the test-script-fixup patch.
I added "cd `dirname $0`" on top of the script. It makes pg_regress to
avoid this troubles. Probably, pg_regress was unavailable to read
sql commands to run.
A problem regarding to validation of sepgsql-regtest policy module
is originated by semodule commands that takes root privilege to
list up installed policy modules. So, I avoided to use this command
in the test_sepgsql script.
However, I have an idea that does not raise script fail even if "sudo
semodule -l" returned an error, except for a case when it can run
correctly and the policy version is not expected one.
How about your opinion for this check?
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
pgsql-v9.3-obvious-wording-fixes.patchapplication/octet-stream; name=pgsql-v9.3-obvious-wording-fixes.patchDownload
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index f70797f..ad12d74 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -96,7 +96,7 @@ RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation)
{
ObjectAccessNamespaceSearch ns_arg;
- /* XXX - should be checked at caller side */
+ /* caller should check, but just in case... */
Assert(object_access_hook != NULL);
memset(&ns_arg, 0, sizeof(ObjectAccessNamespaceSearch));
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 12ae55f..a34c4c7 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -29,7 +29,7 @@
*
* 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.
+ * on a schema under the default access control mechanism.
*
* Other types may be added in the future.
*/
sepgsql-v9.3-test-script-fixup.v1.patchapplication/octet-stream; name=sepgsql-v9.3-test-script-fixup.v1.patchDownload
contrib/sepgsql/test_sepgsql | 46 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
index 8d1a35c..5d46600 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -14,6 +14,10 @@
PG_BINDIR=`pg_config --bindir`
+# It must move to contrib/sepgsql directory to read sql commands and
+# write its results on the expected directory.
+cd `dirname $0`
+
echo
echo "============== checking selinux environment =============="
@@ -133,7 +137,47 @@ if [ ! -e "${SELINUX_MNT}/booleans/sepgsql_regression_test_mode" ]; then
echo ""
exit 1
fi
-echo "ok"
+EXPECTED_POLVER="1.07"
+REGTEST_POLVER="`sudo semodule -l | awk '/^sepgsql-regtest/ {print $2}'`"
+if [ -z "$REGTEST_POLVER" ]; then
+ echo "uncertain"
+ echo
+ echo "The 'sepgsql-regtest' policy module version ${EXPECTED_POLVER} has"
+ echo "to be installed, however, it takes root privilege to confirm this."
+ echo "We expected sudo is configured on the current user, but it didn't"
+ echo "works well. If regression test generates some difference towards"
+ echo "expected one, please ensure the version of installed policy module."
+ echo
+ echo "To confirm that the policy package is installed, use this command:"
+ echo ""
+ echo " \$ sudo semodule -l | grep sepgsql"
+ echo ""
+ echo "Expected result is:"
+ echo " sepgsql-regtest ${EXPECTED_POLVER}"
+ echo
+elif [ "$REGTEST_POLVER" != "$EXPECTED_POLVER" ]; then
+ echo "failed"
+ echo
+ echo "The 'sepgsql-regtest' policy module version ${EXPECTED_POLVER} has"
+ echo "to be installed to run this regression test as expected,"
+ echo "but version ${REGTEST_POLVER} was installed here."
+ echo "You can install this module using the following commands:"
+ echo ""
+ echo " \$ make -f /usr/share/selinux/devel/Makefile clean"
+ echo " \$ make -f /usr/share/selinux/devel/Makefile"
+ echo " \$ sudo semodule -u sepgsql-regtest.pp"
+ echo ""
+ echo "To confirm that the policy package is installed, use this command:"
+ echo ""
+ echo " \$ sudo semodule -l | grep sepgsql"
+ echo ""
+ echo "Expected result is:"
+ echo " sepgsql-regtest ${EXPECTED_POLVER}"
+ echo
+ exit 1
+else
+ echo "found version ${REGTEST_POLVER}"
+fi
# Verify that sepgsql_regression_test_mode is active.
echo -n "checking whether policy is enabled ... "
sepgsql-v9.3-function-execute-permission.v4.patchapplication/octet-stream; name=sepgsql-v9.3-function-execute-permission.v4.patchDownload
contrib/sepgsql/expected/label.out | 17 +++++++++
contrib/sepgsql/expected/misc.out | 67 ++++++++++++++++++++++++++++++++++++
contrib/sepgsql/hooks.c | 7 ++++
contrib/sepgsql/label.c | 23 +++++++++++--
contrib/sepgsql/proc.c | 26 ++++++++++++++
contrib/sepgsql/sepgsql-regtest.te | 23 ++++---------
contrib/sepgsql/sepgsql.h | 1 +
contrib/sepgsql/sql/label.sql | 2 ++
contrib/sepgsql/sql/misc.sql | 25 ++++++++++++++
doc/src/sgml/sepgsql.sgml | 7 ++--
src/backend/catalog/objectaccess.c | 17 +++++++++
src/backend/executor/execQual.c | 3 ++
src/backend/executor/nodeAgg.c | 4 +++
src/backend/executor/nodeWindowAgg.c | 4 +++
src/backend/tcop/fastpath.c | 1 +
src/include/catalog/objectaccess.h | 14 ++++++++
16 files changed, 220 insertions(+), 21 deletions(-)
diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out
index 0a15f27..18bdf81 100644
--- a/contrib/sepgsql/expected/label.out
+++ b/contrib/sepgsql/expected/label.out
@@ -131,23 +131,40 @@ SELECT sepgsql_getcon(); -- confirm client privilege
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
(1 row)
+SET sepgsql.debug_audit = true;
+SET client_min_messages = log;
SELECT f1(); -- normal procedure
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function f1()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+CONTEXT: SQL function "f1" statement 1
f1
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
(1 row)
SELECT f2(); -- trusted procedure
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
+LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
+LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+CONTEXT: SQL function "f2" statement 1
f2
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0
(1 row)
SELECT f3(); -- trusted procedure that raises an error
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
+LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
+LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
ERROR: an exception from f3()
SELECT f4(); -- failed on domain transition
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
+LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
+LOG: SELinux: denied { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_regtest_nosuch_t:s0 tclass=process
ERROR: SELinux: security policy violation
SELECT sepgsql_getcon(); -- client's label must be restored
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
sepgsql_getcon
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
diff --git a/contrib/sepgsql/expected/misc.out b/contrib/sepgsql/expected/misc.out
index 329852c..aaa5d25 100644
--- a/contrib/sepgsql/expected/misc.out
+++ b/contrib/sepgsql/expected/misc.out
@@ -3,3 +3,70 @@
--
LOAD '$libdir/sepgsql'; -- failed
ERROR: SELinux: LOAD is not permitted
+--
+-- Permissions to execute functions
+--
+CREATE TABLE t1 (x int, y text);
+INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
+SET sepgsql.debug_audit = on;
+SET client_min_messages = log;
+-- regular function and operators
+SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4gt(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
+ x | y
+-----+----------------------------------
+ 77 | 28dd2c7955ce926456240b2ff0100bde
+ 89 | 7647966b7343c29048673252e490f736
+ 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 91 | 54229abfcfa5649e7003b83dd4755294
+ 99 | ac627ab1ccbdb62ec96e702f07f6425b
+ 100 | f899139df5e1059396431415e770c6dd
+(6 rows)
+
+-- aggregate function
+SELECT MIN(x), AVG(x) FROM t1;
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function avg(integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4_avg_accum(bigint[],integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int8_avg(bigint[])"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function min(integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4smaller(integer,integer)"
+ min | avg
+-----+---------------------
+ 1 | 50.5000000000000000
+(1 row)
+
+-- window function
+SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function row_number()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
+ row_number | x | y
+------------+----+----------------------------------
+ 1 | 2 | c81e728d9d4c2f636f067f89cc14862c
+ 2 | 17 | 70efdf2ec9b086079795c442636b55fb
+ 3 | 22 | b6d767d2f8ed5d21a44b0e5886680cb9
+ 4 | 27 | 02e74f10e0327ad868d138f2b4fdd6f0
+ 5 | 33 | 182be0c5cdcd5072bb1864cdee4d3d6e
+ 6 | 43 | 17e62166fc8586dfa4d1bc0e1742c08b
+ 7 | 54 | a684eceee76fc522773286a895bc8436
+ 8 | 73 | d2ddea18f00665ce8623e36bd4e3c7c5
+ 9 | 76 | fbd7939d674997cdb4692d34de8633c4
+ 10 | 89 | 7647966b7343c29048673252e490f736
+ 11 | 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 12 | 94 | f4b9ec30ad9f68f89b29639786cb62ef
+(12 rows)
+
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+--
+-- Cleanup
+--
+DROP TABLE IF EXISTS t1 CASCADE;
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 5faa1ea..04c5120 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -255,6 +255,13 @@ sepgsql_object_access(ObjectAccessType access,
}
break;
+ case OAT_FUNCTION_EXECUTE:
+ {
+ Assert(classId == ProcedureRelationId);
+ sepgsql_proc_execute(objectId);
+ }
+ break;
+
default:
elog(ERROR, "unexpected object access type: %d", (int) access);
break;
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index a5bdde3..6146399 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -303,7 +303,8 @@ sepgsql_needs_fmgr_hook(Oid functionId)
object.objectSubId = 0;
if (!sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
- SEPG_DB_PROCEDURE__EXECUTE,
+ SEPG_DB_PROCEDURE__EXECUTE |
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
SEPGSQL_AVC_NOAUDIT, false))
return true;
@@ -347,13 +348,31 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
* process:transition permission between old and new label,
* when user tries to switch security label of the client on
* execution of trusted procedure.
+ *
+ * Also, db_procedure:entrypoint permission should be checked
+ * whether this procedure can perform as an entrypoint of the
+ * trusted procedure, or not.
+ * Note that db_procedure:execute permission shall be checked
+ * individually.
*/
if (stack->new_label)
+ {
+ ObjectAddress object;
+
+ object.classId = ProcedureRelationId;
+ object.objectId = flinfo->fn_oid;
+ object.objectSubId = 0;
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
+ getObjectDescription(&object),
+ true);
+
sepgsql_avc_check_perms_label(stack->new_label,
SEPG_CLASS_PROCESS,
SEPG_PROCESS__TRANSITION,
NULL, true);
-
+ }
*private = PointerGetDatum(stack);
}
Assert(!stack->old_label);
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index afc3755..0cd2c8c 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -301,3 +301,29 @@ sepgsql_proc_setattr(Oid functionId)
systable_endscan(sscan);
heap_close(rel, AccessShareLock);
}
+
+/*
+ * sepgsql_proc_execute
+ *
+ * It checks privileges to execute the supplied function
+ */
+void
+sepgsql_proc_execute(Oid functionId)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * check db_procedure:{execute} permission
+ */
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ audit_name = getObjectDescription(&object);
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__EXECUTE,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te
index 823384e..8727523 100644
--- a/contrib/sepgsql/sepgsql-regtest.te
+++ b/contrib/sepgsql/sepgsql-regtest.te
@@ -1,4 +1,4 @@
-policy_module(sepgsql-regtest, 1.06)
+policy_module(sepgsql-regtest, 1.07)
gen_require(`
all_userspace_class_perms
@@ -172,25 +172,14 @@ optional_policy(`
#
# Rule to execute original trusted procedures
#
-# XXX - sepgsql_client_type contains any valid client types, so we allow
-# them to execute the original trusted procedure at once.
+# These rules intends to allow any valid client types to launch trusted-
+# procedures (including ones causes domain transition to invalid domain)
+# being labeled as sepgsql_regtest_trusted_proc_exec_t and
+# sepgsql_nosuch_trusted_proc_exec_t.
#
optional_policy(`
gen_require(`
attribute sepgsql_client_type;
')
- allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute };
-
- # These rules intends sepgsql_regtest_user_t domain to translate
- # sepgsql_regtest_dba_t on execution of procedures labeled as
- # sepgsql_regtest_trusted_proc_exec_t.
- #
-# allow sepgsql_client_type sepgsql_regtest_trusted_proc_exec_t:db_procedure { getattr execute };
-
- # These rules intends sepgsql_regtest_user_t domain to translate
- # sepgsql_regtest_nosuch_t on execution of procedures labeled as
- # sepgsql_nosuch_trusted_proc_exec_t, without permissions to
- # translate to sepgsql_nosuch_trusted_proc_exec_t.
- #
-# allow sepgsql_client_type sepgsql_nosuch_trusted_proc_exec_t:db_procedure { getattr execute install };
+ allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute entrypoint };
')
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 37d7455..7359f1b 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -328,5 +328,6 @@ extern void sepgsql_proc_post_create(Oid functionId);
extern void sepgsql_proc_drop(Oid functionId);
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
extern void sepgsql_proc_setattr(Oid functionId);
+extern void sepgsql_proc_execute(Oid functionId);
#endif /* SEPGSQL_H */
diff --git a/contrib/sepgsql/sql/label.sql b/contrib/sepgsql/sql/label.sql
index 6201cd7..7a05c24 100644
--- a/contrib/sepgsql/sql/label.sql
+++ b/contrib/sepgsql/sql/label.sql
@@ -97,6 +97,8 @@ SECURITY LABEL ON COLUMN t2.b
-- Tests for Trusted Procedures
--
-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+SET sepgsql.debug_audit = true;
+SET client_min_messages = log;
SELECT f1(); -- normal procedure
SELECT f2(); -- trusted procedure
SELECT f3(); -- trusted procedure that raises an error
diff --git a/contrib/sepgsql/sql/misc.sql b/contrib/sepgsql/sql/misc.sql
index a46d8a6..c277711 100644
--- a/contrib/sepgsql/sql/misc.sql
+++ b/contrib/sepgsql/sql/misc.sql
@@ -3,3 +3,28 @@
--
LOAD '$libdir/sepgsql'; -- failed
+
+--
+-- Permissions to execute functions
+--
+CREATE TABLE t1 (x int, y text);
+INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
+
+SET sepgsql.debug_audit = on;
+SET client_min_messages = log;
+
+-- regular function and operators
+SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
+
+-- aggregate function
+SELECT MIN(x), AVG(x) FROM t1;
+
+-- window function
+SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
+
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+--
+-- Cleanup
+--
+DROP TABLE IF EXISTS t1 CASCADE;
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index 0a2ee86..2cdbe9d 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -393,8 +393,11 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
</para>
<para>
- For functions, <literal>db_procedure:{execute}</> is defined, but is not
- checked in this version.
+ For functions, <literal>db_procedure:{execute}</> will be checked when
+ user tries to execute a function as a part of query, or using fast-path
+ invocation. If this function is a trusted procedure, it also checks
+ <literal>db_procedure:{entrypoint}</> permission to check whether it
+ can perform as entrypoint of trusted procedure.
</para>
<para>
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index ad12d74..87158e3 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -12,6 +12,7 @@
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
/*
* Hook on object accesses. This is intended as infrastructure for security
@@ -109,3 +110,19 @@ RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation)
return ns_arg.result;
}
+
+/*
+ * RunFunctionExecuteHook
+ *
+ * It is entrypoint of OAT_FUNCTION_EXECUTE event
+ */
+void
+RunFunctionExecuteHook(Oid objectId)
+{
+ /* caller should check, but just in case... */
+ Assert(object_access_hook != NULL);
+
+ (*object_access_hook)(OAT_FUNCTION_EXECUTE,
+ ProcedureRelationId, objectId, 0,
+ NULL);
+}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 62d27a7..330d889 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -39,6 +39,7 @@
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/tupconvert.h"
+#include "catalog/objectaccess.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "executor/execdebug.h"
@@ -1289,6 +1290,7 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));
+ InvokeFunctionExecuteHook(foid);
/*
* Safety check on nargs. Under normal circumstances this should never
@@ -4223,6 +4225,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(acoerce->elemfuncid));
+ InvokeFunctionExecuteHook(acoerce->elemfuncid);
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 7efc490..c741131 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -79,6 +79,7 @@
#include "postgres.h"
#include "access/htup_details.h"
+#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@@ -1625,6 +1626,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(aggref->aggfnoid));
+ InvokeFunctionExecuteHook(aggref->aggfnoid);
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
@@ -1647,6 +1649,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(transfn_oid));
+ InvokeFunctionExecuteHook(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
@@ -1654,6 +1657,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(finalfn_oid));
+ InvokeFunctionExecuteHook(finalfn_oid);
}
}
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 3bc42ba..d9f0e79 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -34,6 +34,7 @@
#include "postgres.h"
#include "access/htup_details.h"
+#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@@ -1559,6 +1560,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(wfunc->winfnoid));
+ InvokeFunctionExecuteHook(wfunc->winfnoid);
/* Fill in the perfuncstate data */
perfuncstate->wfuncstate = wfuncstate;
@@ -1767,6 +1769,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(transfn_oid));
+ InvokeFunctionExecuteHook(transfn_oid);
if (OidIsValid(finalfn_oid))
{
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
@@ -1774,6 +1777,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(finalfn_oid));
+ InvokeFunctionExecuteHook(finalfn_oid);
}
}
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 016e7d9..bd0801c 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -362,6 +362,7 @@ HandleFunctionRequest(StringInfo msgBuf)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(fid));
+ InvokeFunctionExecuteHook(fid);
/*
* Prepare function call info block and insert arguments.
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index a34c4c7..f4e464e 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -31,6 +31,12 @@
* a particular namespace. This event is equivalent to usage permission
* on a schema under the default access control mechanism.
*
+ * OAT_FUNCTION_EXECUTE should be invoked prior to function execution.
+ * This event is almost equivalent to execute permission on functions,
+ * except for the case when execute permission is checked during object
+ * creation or altering, because OAT_POST_CREATE or OAT_POST_ALTER are
+ * sufficient for extensions to track these kind of checks.
+ *
* Other types may be added in the future.
*/
typedef enum ObjectAccessType
@@ -39,6 +45,7 @@ typedef enum ObjectAccessType
OAT_DROP,
OAT_POST_ALTER,
OAT_NAMESPACE_SEARCH,
+ OAT_FUNCTION_EXECUTE,
} ObjectAccessType;
/*
@@ -129,6 +136,7 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
Oid auxiliaryId, bool is_internal);
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_volation);
+extern void RunFunctionExecuteHook(Oid objectId);
/*
* The following macros are wrappers around the functions above; these should
@@ -170,4 +178,10 @@ extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_volation);
? true \
: RunNamespaceSearchHook((objectId), (ereport_on_violation)))
+#define InvokeFunctionExecuteHook(objectId) \
+ do { \
+ if (object_access_hook) \
+ RunFunctionExecuteHook(objectId); \
+ } while(0)
+
#endif /* OBJECTACCESS_H */
On Mon, Apr 8, 2013 at 12:28 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
Thanks. I could find two obvious wording stuffs here, please see smaller
one of the attached patches. I didn't fixup manner to use "XXX" in source
code comments.
Committed.
Also, the attached function-execute-permission patch is a rebased
version. I rethought its event name should be OAT_FUNCTION_EXECUTE,
rather than OAT_FUNCTION_EXEC according to the manner without
abbreviation. Other portion is same as previous ones.
Great. This looks fine to me, committed. I also committed your
getObjectIdentity patch, which caused some regression test output
changes. I applied the necessary correction before committing, I
think, but please check.
BTW, if it were possible to set things up so that the test_sepgsql
script could validate the version of the sepgsql-regtest policy
installed, that would eliminate a certain category of errors. I
notice also that the regression tests themselves seem to fail if you
invoke the script as contrib/sepgsql/test_sepgsql rather than
./test_sepgsql, which suggests another possible pre-validation step.Please see the test-script-fixup patch.
I added "cd `dirname $0`" on top of the script. It makes pg_regress to
avoid this troubles. Probably, pg_regress was unavailable to read
sql commands to run.A problem regarding to validation of sepgsql-regtest policy module
is originated by semodule commands that takes root privilege to
list up installed policy modules. So, I avoided to use this command
in the test_sepgsql script.
However, I have an idea that does not raise script fail even if "sudo
semodule -l" returned an error, except for a case when it can run
correctly and the policy version is not expected one.
How about your opinion for this check?
Not sure that's too useful. And I don't like the idea of putting sudo
commands in a test harness script. That seems too much like the sort
of thing bad people do.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Robert Haas escribió:
On Mon, Apr 8, 2013 at 12:28 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
Also, the attached function-execute-permission patch is a rebased
version. I rethought its event name should be OAT_FUNCTION_EXECUTE,
rather than OAT_FUNCTION_EXEC according to the manner without
abbreviation. Other portion is same as previous ones.Great. This looks fine to me, committed. I also committed your
getObjectIdentity patch, which caused some regression test output
changes. I applied the necessary correction before committing, I
think, but please check.
I think the function-execute code path is still using
getObjectDescription rather than identity.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Apr 12, 2013 at 10:42 AM, Alvaro Herrera
<alvherre@2ndquadrant.com> wrote:
Robert Haas escribió:
On Mon, Apr 8, 2013 at 12:28 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
Also, the attached function-execute-permission patch is a rebased
version. I rethought its event name should be OAT_FUNCTION_EXECUTE,
rather than OAT_FUNCTION_EXEC according to the manner without
abbreviation. Other portion is same as previous ones.Great. This looks fine to me, committed. I also committed your
getObjectIdentity patch, which caused some regression test output
changes. I applied the necessary correction before committing, I
think, but please check.I think the function-execute code path is still using
getObjectDescription rather than identity.
Yeah, I think so. KaiGai, can you provide a follow-on patch to fix that?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/4/12 Robert Haas <robertmhaas@gmail.com>:
On Fri, Apr 12, 2013 at 10:42 AM, Alvaro Herrera
<alvherre@2ndquadrant.com> wrote:Robert Haas escribió:
On Mon, Apr 8, 2013 at 12:28 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
Also, the attached function-execute-permission patch is a rebased
version. I rethought its event name should be OAT_FUNCTION_EXECUTE,
rather than OAT_FUNCTION_EXEC according to the manner without
abbreviation. Other portion is same as previous ones.Great. This looks fine to me, committed. I also committed your
getObjectIdentity patch, which caused some regression test output
changes. I applied the necessary correction before committing, I
think, but please check.I think the function-execute code path is still using
getObjectDescription rather than identity.Yeah, I think so. KaiGai, can you provide a follow-on patch to fix that?
Yes, of course. The attached one replaces the getObjectDescription in
sepgsql/proc.c, and relative changes in regression test.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-replace-get-object-description.v2.patchapplication/octet-stream; name=sepgsql-v9.3-replace-get-object-description.v2.patchDownload
contrib/sepgsql/expected/label.out | 14 +++++++-------
contrib/sepgsql/expected/misc.out | 18 +++++++++---------
contrib/sepgsql/proc.c | 2 +-
3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out
index 18bdf81..9d1f904 100644
--- a/contrib/sepgsql/expected/label.out
+++ b/contrib/sepgsql/expected/label.out
@@ -134,8 +134,8 @@ SELECT sepgsql_getcon(); -- confirm client privilege
SET sepgsql.debug_audit = true;
SET client_min_messages = log;
SELECT f1(); -- normal procedure
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function f1()"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="public.f1()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.sepgsql_getcon()"
CONTEXT: SQL function "f1" statement 1
f1
-----------------------------------------------------
@@ -143,10 +143,10 @@ CONTEXT: SQL function "f1" statement 1
(1 row)
SELECT f2(); -- trusted procedure
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="public.f2()"
LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.sepgsql_getcon()"
CONTEXT: SQL function "f2" statement 1
f2
-----------------------------------------------------
@@ -154,17 +154,17 @@ CONTEXT: SQL function "f2" statement 1
(1 row)
SELECT f3(); -- trusted procedure that raises an error
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="public.f3()"
LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
ERROR: an exception from f3()
SELECT f4(); -- failed on domain transition
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="public.f4()"
LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
LOG: SELinux: denied { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_regtest_nosuch_t:s0 tclass=process
ERROR: SELinux: security policy violation
SELECT sepgsql_getcon(); -- client's label must be restored
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.sepgsql_getcon()"
sepgsql_getcon
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
diff --git a/contrib/sepgsql/expected/misc.out b/contrib/sepgsql/expected/misc.out
index 26d9c18..5904840 100644
--- a/contrib/sepgsql/expected/misc.out
+++ b/contrib/sepgsql/expected/misc.out
@@ -15,8 +15,8 @@ SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4gt(integer,integer)"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4gt(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
x | y
-----+----------------------------------
77 | 28dd2c7955ce926456240b2ff0100bde
@@ -31,11 +31,11 @@ LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined
SELECT MIN(x), AVG(x) FROM t1;
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function avg(integer)"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4_avg_accum(bigint[],integer)"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int8_avg(bigint[])"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function min(integer)"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4smaller(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.avg(integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4_avg_accum(bigint[],integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int8_avg(bigint[])"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.min(integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4smaller(integer,integer)"
min | avg
-----+---------------------
1 | 50.5000000000000000
@@ -46,8 +46,8 @@ SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function row_number()"
-LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.row_number()"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
row_number | x | y
------------+----+----------------------------------
1 | 2 | c81e728d9d4c2f636f067f89cc14862c
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index fe33119..0230028 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -325,7 +325,7 @@ sepgsql_proc_execute(Oid functionId)
object.classId = ProcedureRelationId;
object.objectId = functionId;
object.objectSubId = 0;
- audit_name = getObjectDescription(&object);
+ audit_name = getObjectIdentity(&object);
sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__EXECUTE,
A problem regarding to validation of sepgsql-regtest policy module
is originated by semodule commands that takes root privilege to
list up installed policy modules. So, I avoided to use this command
in the test_sepgsql script.
However, I have an idea that does not raise script fail even if "sudo
semodule -l" returned an error, except for a case when it can run
correctly and the policy version is not expected one.
How about your opinion for this check?Not sure that's too useful. And I don't like the idea of putting sudo
commands in a test harness script. That seems too much like the sort
of thing bad people do.
OK, I also doubt whether my idea make sense.
The attached patch omitted the portion to check the version of
sepgsql-regtest, and add some notice in the document instead.
Also, it moves current directory to the contrib/sepgsql on top of
the script, to avoid the problem when we run test_sepgsql
on the directory except for contring/sepgsql.
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
Attachments:
sepgsql-v9.3-test-script-fixup.v2.patchapplication/octet-stream; name=sepgsql-v9.3-test-script-fixup.v2.patchDownload
contrib/sepgsql/test_sepgsql | 3 +++
doc/src/sgml/sepgsql.sgml | 13 +++++++++----
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
index 8d1a35c..1266718 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -14,6 +14,9 @@
PG_BINDIR=`pg_config --bindir`
+# we must move to contrib/sepgsql directory to run pg_regress correctly
+cd `dirname $0`
+
echo
echo "============== checking selinux environment =============="
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index 2cdbe9d..d6e7f25 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -187,7 +187,7 @@ $ cd .../contrib/sepgsql
$ make -f /usr/share/selinux/devel/Makefile
$ sudo semodule -u sepgsql-regtest.pp
$ sudo semodule -l | grep sepgsql
-sepgsql-regtest 1.04
+sepgsql-regtest 1.07
</screen>
<para>
@@ -227,9 +227,14 @@ $ ./test_sepgsql
</screen>
<para>
- This script will attempt to verify that you have done all the configuration
- steps correctly, and then it will run the regression tests for the
- <filename>sepgsql</> module.
+ This script will attempt to verify that you have done most of
+ the configuration steps correctly, and then it will run the regression
+ tests for the <filename>sepgsql</> module.
+ Please note that it does not check version of the installed
+ <filename>sepgsql-regtest</> policy because it takes root privilege to
+ list up policy modules using <command>semodule</> command, thus, make
+ sure whether the installed policy is really the latest one, even if
+ you got regression test failed.
</para>
<para>
On Fri, Apr 12, 2013 at 2:44 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:
Yes, of course. The attached one replaces the getObjectDescription in
sepgsql/proc.c, and relative changes in regression test.
Thanks. Committed. I also committed the first two hunks of your
cleanup patch but omitted the third one, which is not well-worded and
seems like overkill anyway.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers