summaryrefslogtreecommitdiffstats
path: root/contrib/sepgsql
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/sepgsql/.gitignore7
-rw-r--r--contrib/sepgsql/Makefile33
-rw-r--r--contrib/sepgsql/database.c217
-rw-r--r--contrib/sepgsql/dml.c362
-rw-r--r--contrib/sepgsql/expected/alter.out316
-rw-r--r--contrib/sepgsql/expected/ddl.out537
-rw-r--r--contrib/sepgsql/expected/dml.out399
-rw-r--r--contrib/sepgsql/expected/label.out611
-rw-r--r--contrib/sepgsql/expected/misc.out231
-rw-r--r--contrib/sepgsql/expected/truncate.out46
-rw-r--r--contrib/sepgsql/hooks.c481
-rw-r--r--contrib/sepgsql/label.c938
-rwxr-xr-xcontrib/sepgsql/launcher52
-rw-r--r--contrib/sepgsql/proc.c334
-rw-r--r--contrib/sepgsql/relation.c774
-rw-r--r--contrib/sepgsql/schema.c236
-rw-r--r--contrib/sepgsql/selinux.c945
-rw-r--r--contrib/sepgsql/sepgsql-regtest.te261
-rw-r--r--contrib/sepgsql/sepgsql.h329
-rw-r--r--contrib/sepgsql/sepgsql.sql.in37
-rw-r--r--contrib/sepgsql/sql/alter.sql197
-rw-r--r--contrib/sepgsql/sql/ddl.sql125
-rw-r--r--contrib/sepgsql/sql/dml.sql257
-rw-r--r--contrib/sepgsql/sql/label.sql294
-rw-r--r--contrib/sepgsql/sql/misc.sql45
-rw-r--r--contrib/sepgsql/sql/truncate.sql24
-rwxr-xr-xcontrib/sepgsql/test_sepgsql306
-rw-r--r--contrib/sepgsql/uavc.c520
28 files changed, 8914 insertions, 0 deletions
diff --git a/contrib/sepgsql/.gitignore b/contrib/sepgsql/.gitignore
new file mode 100644
index 0000000..31613e0
--- /dev/null
+++ b/contrib/sepgsql/.gitignore
@@ -0,0 +1,7 @@
+/sepgsql.sql
+/sepgsql-regtest.fc
+/sepgsql-regtest.if
+/sepgsql-regtest.pp
+/tmp
+# Generated subdirectories
+/results/
diff --git a/contrib/sepgsql/Makefile b/contrib/sepgsql/Makefile
new file mode 100644
index 0000000..afca75b
--- /dev/null
+++ b/contrib/sepgsql/Makefile
@@ -0,0 +1,33 @@
+# contrib/sepgsql/Makefile
+
+MODULE_big = sepgsql
+OBJS = \
+ $(WIN32RES) \
+ database.o \
+ dml.o \
+ hooks.o \
+ label.o \
+ proc.o \
+ relation.o \
+ schema.o \
+ selinux.o \
+ uavc.o
+DATA_built = sepgsql.sql
+PGFILEDESC = "sepgsql - SELinux integration"
+
+# Note: because we don't tell the Makefile there are any regression tests,
+# we have to clean those result files explicitly
+EXTRA_CLEAN = -r $(pg_regress_clean_files) tmp/ *.pp sepgsql-regtest.if sepgsql-regtest.fc
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/sepgsql
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
+
+SHLIB_LINK += -lselinux
diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
new file mode 100644
index 0000000..4e83b7b
--- /dev/null
+++ b/contrib/sepgsql/database.c
@@ -0,0 +1,217 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/database.c
+ *
+ * Routines corresponding to database objects
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "access/table.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_database.h"
+#include "commands/dbcommands.h"
+#include "commands/seclabel.h"
+#include "sepgsql.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/snapmgr.h"
+
+/*
+ * sepgsql_database_post_create
+ *
+ * This routine assigns a default security label on a newly defined
+ * database, and check permission needed for its creation.
+ */
+void
+sepgsql_database_post_create(Oid databaseId, const char *dtemplate)
+{
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ char *tcontext;
+ char *ncontext;
+ ObjectAddress object;
+ Form_pg_database datForm;
+ StringInfoData audit_name;
+
+ /*
+ * Oid of the source database is not saved in pg_database catalog, so we
+ * collect its identifier using contextual information. If NULL, its
+ * default is "template1" according to createdb().
+ */
+ if (!dtemplate)
+ dtemplate = "template1";
+
+ object.classId = DatabaseRelationId;
+ object.objectId = get_database_oid(dtemplate, false);
+ object.objectSubId = 0;
+
+ tcontext = sepgsql_get_label(object.classId,
+ object.objectId,
+ object.objectSubId);
+
+ /*
+ * check db_database:{getattr} permission
+ */
+ initStringInfo(&audit_name);
+ appendStringInfoString(&audit_name, quote_identifier(dtemplate));
+ sepgsql_avc_check_perms_label(tcontext,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__GETATTR,
+ audit_name.data,
+ true);
+
+ /*
+ * Compute a default security label of the newly created database based on
+ * a pair of security label of client and source database.
+ *
+ * XXX - upcoming version of libselinux supports to take object name to
+ * handle special treatment on default security label.
+ */
+ rel = table_open(DatabaseRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_database_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(databaseId));
+
+ sscan = systable_beginscan(rel, DatabaseOidIndexId, true,
+ SnapshotSelf, 1, &skey);
+ tuple = systable_getnext(sscan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for database %u", databaseId);
+
+ datForm = (Form_pg_database) GETSTRUCT(tuple);
+
+ ncontext = sepgsql_compute_create(sepgsql_get_client_label(),
+ tcontext,
+ SEPG_CLASS_DB_DATABASE,
+ NameStr(datForm->datname));
+
+ /*
+ * check db_database:{create} permission
+ */
+ resetStringInfo(&audit_name);
+ appendStringInfoString(&audit_name,
+ quote_identifier(NameStr(datForm->datname)));
+ sepgsql_avc_check_perms_label(ncontext,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__CREATE,
+ audit_name.data,
+ true);
+
+ systable_endscan(sscan);
+ table_close(rel, AccessShareLock);
+
+ /*
+ * Assign the default security label on the new database
+ */
+ object.classId = DatabaseRelationId;
+ object.objectId = databaseId;
+ object.objectSubId = 0;
+
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
+
+ pfree(ncontext);
+ pfree(tcontext);
+}
+
+/*
+ * sepgsql_database_drop
+ *
+ * It checks privileges to drop the supplied database
+ */
+void
+sepgsql_database_drop(Oid databaseId)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * check db_database:{drop} permission
+ */
+ object.classId = DatabaseRelationId;
+ object.objectId = databaseId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__DROP,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_database_post_alter
+ *
+ * It checks privileges to alter the supplied database
+ */
+void
+sepgsql_database_setattr(Oid databaseId)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * check db_database:{setattr} permission
+ */
+ object.classId = DatabaseRelationId;
+ object.objectId = databaseId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__SETATTR,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_database_relabel
+ *
+ * It checks privileges to relabel the supplied database with the `seclabel'
+ */
+void
+sepgsql_database_relabel(Oid databaseId, const char *seclabel)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ object.classId = DatabaseRelationId;
+ object.objectId = databaseId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ /*
+ * check db_database:{setattr relabelfrom} permission
+ */
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__SETATTR |
+ SEPG_DB_DATABASE__RELABELFROM,
+ audit_name,
+ true);
+
+ /*
+ * check db_database:{relabelto} permission
+ */
+ sepgsql_avc_check_perms_label(seclabel,
+ SEPG_CLASS_DB_DATABASE,
+ SEPG_DB_DATABASE__RELABELTO,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c
new file mode 100644
index 0000000..53f6f41
--- /dev/null
+++ b/contrib/sepgsql/dml.c
@@ -0,0 +1,362 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/dml.c
+ *
+ * Routines to handle DML permission checks
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "access/tupdesc.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/heap.h"
+#include "catalog/pg_attribute.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_inherits.h"
+#include "commands/seclabel.h"
+#include "commands/tablecmds.h"
+#include "executor/executor.h"
+#include "nodes/bitmapset.h"
+#include "sepgsql.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+/*
+ * fixup_whole_row_references
+ *
+ * When user references a whole-row Var, it is equivalent to referencing
+ * all the user columns (not system columns). So, we need to fix up the
+ * given bitmapset, if it contains a whole-row reference.
+ */
+static Bitmapset *
+fixup_whole_row_references(Oid relOid, Bitmapset *columns)
+{
+ Bitmapset *result;
+ HeapTuple tuple;
+ AttrNumber natts;
+ AttrNumber attno;
+ int index;
+
+ /* if no whole-row references, nothing to do */
+ index = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber;
+ if (!bms_is_member(index, columns))
+ return columns;
+
+ /* obtain number of attributes */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relOid);
+ natts = ((Form_pg_class) GETSTRUCT(tuple))->relnatts;
+ ReleaseSysCache(tuple);
+
+ /* remove bit 0 from column set, add in all the non-dropped columns */
+ result = bms_copy(columns);
+ result = bms_del_member(result, index);
+
+ for (attno = 1; attno <= natts; attno++)
+ {
+ tuple = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relOid),
+ Int16GetDatum(attno));
+ if (!HeapTupleIsValid(tuple))
+ continue; /* unexpected case, should we error? */
+
+ if (!((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
+ {
+ index = attno - FirstLowInvalidHeapAttributeNumber;
+ result = bms_add_member(result, index);
+ }
+
+ ReleaseSysCache(tuple);
+ }
+ return result;
+}
+
+/*
+ * fixup_inherited_columns
+ *
+ * When user is querying on a table with children, it implicitly accesses
+ * child tables also. So, we also need to check security label of child
+ * tables and columns, but here is no guarantee attribute numbers are
+ * same between the parent and children.
+ * It returns a bitmapset which contains attribute number of the child
+ * table based on the given bitmapset of the parent.
+ */
+static Bitmapset *
+fixup_inherited_columns(Oid parentId, Oid childId, Bitmapset *columns)
+{
+ Bitmapset *result = NULL;
+ int index;
+
+ /*
+ * obviously, no need to do anything here
+ */
+ if (parentId == childId)
+ return columns;
+
+ index = -1;
+ while ((index = bms_next_member(columns, index)) >= 0)
+ {
+ /* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
+ AttrNumber attno = index + FirstLowInvalidHeapAttributeNumber;
+ char *attname;
+
+ /*
+ * whole-row-reference shall be fixed-up later
+ */
+ if (attno == InvalidAttrNumber)
+ {
+ result = bms_add_member(result, index);
+ continue;
+ }
+
+ attname = get_attname(parentId, attno, false);
+ attno = get_attnum(childId, attname);
+ if (attno == InvalidAttrNumber)
+ elog(ERROR, "cache lookup failed for attribute %s of relation %u",
+ attname, childId);
+
+ result = bms_add_member(result,
+ attno - FirstLowInvalidHeapAttributeNumber);
+
+ pfree(attname);
+ }
+
+ return result;
+}
+
+/*
+ * check_relation_privileges
+ *
+ * It actually checks required permissions on a certain relation
+ * and its columns.
+ */
+static bool
+check_relation_privileges(Oid relOid,
+ Bitmapset *selected,
+ Bitmapset *inserted,
+ Bitmapset *updated,
+ uint32 required,
+ bool abort_on_violation)
+{
+ ObjectAddress object;
+ char *audit_name;
+ Bitmapset *columns;
+ int index;
+ char relkind = get_rel_relkind(relOid);
+ bool result = true;
+
+ /*
+ * Hardwired Policies: SE-PostgreSQL enforces - clients cannot modify
+ * system catalogs using DMLs - clients cannot reference/modify toast
+ * relations using DMLs
+ */
+ if (sepgsql_getenforce() > 0)
+ {
+ if ((required & (SEPG_DB_TABLE__UPDATE |
+ SEPG_DB_TABLE__INSERT |
+ SEPG_DB_TABLE__DELETE)) != 0 &&
+ IsCatalogRelationOid(relOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: hardwired security policy violation")));
+
+ if (relkind == RELKIND_TOASTVALUE)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: hardwired security policy violation")));
+ }
+
+ /*
+ * Check permissions on the relation
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ case RELKIND_PARTITIONED_TABLE:
+ result = sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_TABLE,
+ required,
+ audit_name,
+ abort_on_violation);
+ break;
+
+ case RELKIND_SEQUENCE:
+ Assert((required & ~SEPG_DB_TABLE__SELECT) == 0);
+
+ if (required & SEPG_DB_TABLE__SELECT)
+ result = sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SEQUENCE,
+ SEPG_DB_SEQUENCE__GET_VALUE,
+ audit_name,
+ abort_on_violation);
+ break;
+
+ case RELKIND_VIEW:
+ result = sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_VIEW,
+ SEPG_DB_VIEW__EXPAND,
+ audit_name,
+ abort_on_violation);
+ break;
+
+ default:
+ /* nothing to be checked */
+ break;
+ }
+ pfree(audit_name);
+
+ /*
+ * Only columns owned by relations shall be checked
+ */
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
+ return true;
+
+ /*
+ * Check permissions on the columns
+ */
+ selected = fixup_whole_row_references(relOid, selected);
+ inserted = fixup_whole_row_references(relOid, inserted);
+ updated = fixup_whole_row_references(relOid, updated);
+ columns = bms_union(selected, bms_union(inserted, updated));
+
+ while ((index = bms_first_member(columns)) >= 0)
+ {
+ AttrNumber attnum;
+ uint32 column_perms = 0;
+
+ if (bms_is_member(index, selected))
+ column_perms |= SEPG_DB_COLUMN__SELECT;
+ if (bms_is_member(index, inserted))
+ {
+ if (required & SEPG_DB_TABLE__INSERT)
+ column_perms |= SEPG_DB_COLUMN__INSERT;
+ }
+ if (bms_is_member(index, updated))
+ {
+ if (required & SEPG_DB_TABLE__UPDATE)
+ column_perms |= SEPG_DB_COLUMN__UPDATE;
+ }
+ if (column_perms == 0)
+ continue;
+
+ /* obtain column's permission */
+ attnum = index + FirstLowInvalidHeapAttributeNumber;
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attnum;
+ audit_name = getObjectDescription(&object);
+
+ result = sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_COLUMN,
+ column_perms,
+ audit_name,
+ abort_on_violation);
+ pfree(audit_name);
+
+ if (!result)
+ return result;
+ }
+ return true;
+}
+
+/*
+ * sepgsql_dml_privileges
+ *
+ * Entrypoint of the DML permission checks
+ */
+bool
+sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
+{
+ ListCell *lr;
+
+ foreach(lr, rangeTabls)
+ {
+ RangeTblEntry *rte = lfirst(lr);
+ uint32 required = 0;
+ List *tableIds;
+ ListCell *li;
+
+ /*
+ * Only regular relations shall be checked
+ */
+ if (rte->rtekind != RTE_RELATION)
+ continue;
+
+ /*
+ * Find out required permissions
+ */
+ if (rte->requiredPerms & ACL_SELECT)
+ required |= SEPG_DB_TABLE__SELECT;
+ if (rte->requiredPerms & ACL_INSERT)
+ required |= SEPG_DB_TABLE__INSERT;
+ if (rte->requiredPerms & ACL_UPDATE)
+ {
+ if (!bms_is_empty(rte->updatedCols))
+ required |= SEPG_DB_TABLE__UPDATE;
+ else
+ required |= SEPG_DB_TABLE__LOCK;
+ }
+ if (rte->requiredPerms & ACL_DELETE)
+ required |= SEPG_DB_TABLE__DELETE;
+
+ /*
+ * Skip, if nothing to be checked
+ */
+ if (required == 0)
+ continue;
+
+ /*
+ * If this RangeTblEntry is also supposed to reference inherited
+ * tables, we need to check security label of the child tables. So, we
+ * expand rte->relid into list of OIDs of inheritance hierarchy, then
+ * checker routine will be invoked for each relations.
+ */
+ if (!rte->inh)
+ tableIds = list_make1_oid(rte->relid);
+ else
+ tableIds = find_all_inheritors(rte->relid, NoLock, NULL);
+
+ foreach(li, tableIds)
+ {
+ Oid tableOid = lfirst_oid(li);
+ Bitmapset *selectedCols;
+ Bitmapset *insertedCols;
+ Bitmapset *updatedCols;
+
+ /*
+ * child table has different attribute numbers, so we need to fix
+ * up them.
+ */
+ selectedCols = fixup_inherited_columns(rte->relid, tableOid,
+ rte->selectedCols);
+ insertedCols = fixup_inherited_columns(rte->relid, tableOid,
+ rte->insertedCols);
+ updatedCols = fixup_inherited_columns(rte->relid, tableOid,
+ rte->updatedCols);
+
+ /*
+ * check permissions on individual tables
+ */
+ if (!check_relation_privileges(tableOid,
+ selectedCols,
+ insertedCols,
+ updatedCols,
+ required, abort_on_violation))
+ return false;
+ }
+ list_free(tableIds);
+ }
+ return true;
+}
diff --git a/contrib/sepgsql/expected/alter.out b/contrib/sepgsql/expected/alter.out
new file mode 100644
index 0000000..836acea
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,316 @@
+--
+-- Test for various ALTER statements
+--
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS sepgsql_test_regression_1;
+DROP DATABASE IF EXISTS sepgsql_test_regression;
+DROP USER IF EXISTS regress_sepgsql_test_user;
+RESET client_min_messages;
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0
+(1 row)
+
+--
+-- CREATE Objects to be altered (with debug_audit being silent)
+--
+CREATE DATABASE sepgsql_test_regression_1;
+CREATE USER regress_sepgsql_test_user;
+CREATE SCHEMA regtest_schema_1;
+CREATE SCHEMA regtest_schema_2;
+GRANT ALL ON SCHEMA regtest_schema_1 TO public;
+GRANT ALL ON SCHEMA regtest_schema_2 TO public;
+SET search_path = regtest_schema_1, regtest_schema_2, public;
+CREATE TABLE regtest_table_1 (a int, b text);
+CREATE TABLE regtest_table_2 (c text) inherits (regtest_table_1);
+CREATE TABLE regtest_table_3 (x int primary key, y text);
+---
+-- partitioned table parent
+CREATE TABLE regtest_ptable_1 (o int, p text) PARTITION BY RANGE (o);
+-- partitioned table children
+CREATE TABLE regtest_ptable_1_ones PARTITION OF regtest_ptable_1 FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE regtest_ptable_1_tens PARTITION OF regtest_ptable_1 FOR VALUES FROM ('10') TO ('100');
+---
+CREATE SEQUENCE regtest_seq_1;
+CREATE VIEW regtest_view_1 AS SELECT * FROM regtest_table_1 WHERE a > 0;
+CREATE FUNCTION regtest_func_1 (text) RETURNS bool
+ AS 'BEGIN RETURN true; END' LANGUAGE 'plpgsql';
+-- switch on debug_audit
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+--
+-- ALTER xxx OWNER TO
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+-- owner is not actually changed.
+--
+ALTER DATABASE sepgsql_test_regression_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="sepgsql_test_regression_1"
+ALTER DATABASE sepgsql_test_regression_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="sepgsql_test_regression_1"
+ALTER SCHEMA regtest_schema_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+ALTER SCHEMA regtest_schema_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+ALTER TABLE regtest_table_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_table_1"
+ALTER TABLE regtest_table_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_table_1"
+ALTER TABLE regtest_ptable_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_ptable_1"
+ALTER TABLE regtest_ptable_1_ones OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_ptable_1_ones"
+ALTER SEQUENCE regtest_seq_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema_1.regtest_seq_1"
+ALTER SEQUENCE regtest_seq_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema_1.regtest_seq_1"
+ALTER VIEW regtest_view_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema_1.regtest_view_1"
+ALTER VIEW regtest_view_1 OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema_1.regtest_view_1"
+ALTER FUNCTION regtest_func_1(text) OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema_1.regtest_func_1(pg_catalog.text)"
+ALTER FUNCTION regtest_func_1(text) OWNER TO regress_sepgsql_test_user;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema_1.regtest_func_1(pg_catalog.text)"
+--
+-- ALTER xxx SET SCHEMA
+--
+ALTER TABLE regtest_table_1 SET SCHEMA regtest_schema_2;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_table_1"
+ALTER TABLE regtest_ptable_1 SET SCHEMA regtest_schema_2;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_ptable_1"
+ALTER TABLE regtest_ptable_1_ones SET SCHEMA regtest_schema_2;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_1.regtest_ptable_1_ones"
+ALTER SEQUENCE regtest_seq_1 SET SCHEMA regtest_schema_2;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema_1.regtest_seq_1"
+ALTER VIEW regtest_view_1 SET SCHEMA regtest_schema_2;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema_1.regtest_view_1"
+ALTER FUNCTION regtest_func_1(text) SET SCHEMA regtest_schema_2;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema_1.regtest_func_1(pg_catalog.text)"
+--
+-- ALTER xxx RENAME TO
+--
+ALTER DATABASE sepgsql_test_regression_1 RENAME TO sepgsql_test_regression;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="sepgsql_test_regression_1"
+ALTER SCHEMA regtest_schema_1 RENAME TO regtest_schema;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_1"
+ALTER TABLE regtest_table_1 RENAME TO regtest_table;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LOG: SELinux: allowed { add_name remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table_1"
+---
+-- partitioned table parent
+ALTER TABLE regtest_ptable_1 RENAME TO regtest_ptable;
+LOG: SELinux: allowed { add_name remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_ptable_1"
+-- partitioned table child
+ALTER TABLE regtest_ptable_1_ones RENAME TO regtest_table_part;
+LOG: SELinux: allowed { add_name remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_ptable_1_ones"
+---
+ALTER SEQUENCE regtest_seq_1 RENAME TO regtest_seq;
+LOG: SELinux: allowed { add_name remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema_2.regtest_seq_1"
+ALTER VIEW regtest_view_1 RENAME TO regtest_view;
+LOG: SELinux: allowed { add_name remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema_2.regtest_view_1"
+ALTER FUNCTION regtest_func_1(text) RENAME TO regtest_func;
+LOG: SELinux: allowed { add_name remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema_2.regtest_func_1(pg_catalog.text)"
+SET search_path = regtest_schema, regtest_schema_2, public;
+--
+-- misc ALTER commands
+--
+ALTER DATABASE sepgsql_test_regression CONNECTION LIMIT 999;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="sepgsql_test_regression"
+ALTER DATABASE sepgsql_test_regression 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:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema_2"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ALTER TABLE regtest_table ADD COLUMN d float;
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.d"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.d"
+ALTER TABLE regtest_table DROP COLUMN d;
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.d"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.d"
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'abcd'; -- not supported yet
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ'; -- not supported yet
+ALTER TABLE regtest_table ALTER b DROP DEFAULT; -- not supported yet
+ALTER TABLE regtest_table ALTER b SET NOT NULL;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b"
+ALTER TABLE regtest_table ALTER b DROP NOT NULL;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b"
+ALTER TABLE regtest_table ALTER b SET STATISTICS -1;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b"
+ALTER TABLE regtest_table ALTER b SET (n_distinct = 999);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b"
+ALTER TABLE regtest_table ALTER b SET STORAGE PLAIN;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.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:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column a of table regtest_table"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_3"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column x of table regtest_table_3"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="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:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="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:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ..."regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(p...
+ ^
+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:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column a of table regtest_table"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_3"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column x of table regtest_table_3"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4eq(integer,integer)"
+ALTER TABLE regtest_table ADD CONSTRAINT test_ck CHECK (b like '%abc%') NOT VALID; -- not supported
+ALTER TABLE regtest_table VALIDATE CONSTRAINT test_ck; -- not supported
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+ALTER TABLE regtest_table DROP CONSTRAINT test_ck; -- not supported
+CREATE TRIGGER regtest_test_trig BEFORE UPDATE ON regtest_table
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+ALTER TABLE regtest_table DISABLE TRIGGER regtest_test_trig; -- not supported
+ALTER TABLE regtest_table ENABLE TRIGGER regtest_test_trig; -- not supported
+CREATE RULE regtest_test_rule AS ON INSERT TO regtest_table_3 DO ALSO NOTHING;
+ALTER TABLE regtest_table_3 DISABLE RULE regtest_test_rule; -- not supported
+ALTER TABLE regtest_table_3 ENABLE RULE regtest_test_rule; -- not supported
+ALTER TABLE regtest_table SET (fillfactor = 75);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table"
+ALTER TABLE regtest_table RESET (fillfactor);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table"
+ALTER TABLE regtest_table_2 NO INHERIT regtest_table; -- not supported
+ALTER TABLE regtest_table_2 INHERIT regtest_table; -- not supported
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table"
+---
+-- partitioned table parent
+ALTER TABLE regtest_ptable ADD COLUMN d float;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ALTER TABLE regtest_ptable ADD COLUMN d float;
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.d"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.d"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_1_tens.d"
+ALTER TABLE regtest_ptable DROP COLUMN d;
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.d"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_1_tens.d"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.d"
+ALTER TABLE regtest_ptable ALTER p SET DEFAULT 'abcd'; -- not supported by sepgsql
+ALTER TABLE regtest_ptable ALTER p SET DEFAULT 'XYZ'; -- not supported by sepgsql
+ALTER TABLE regtest_ptable ALTER p DROP DEFAULT; -- not supported by sepgsql
+ALTER TABLE regtest_ptable ALTER p SET NOT NULL;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_1_tens.p"
+ALTER TABLE regtest_ptable ALTER p DROP NOT NULL;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_1_tens.p"
+ALTER TABLE regtest_ptable ALTER p SET STATISTICS -1;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_1_tens.p"
+ALTER TABLE regtest_ptable ALTER p SET (n_distinct = 999);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.p"
+ALTER TABLE regtest_ptable ALTER p SET STORAGE PLAIN;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_ptable.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_1_tens.p"
+ALTER TABLE regtest_ptable ADD CONSTRAINT test_ck CHECK (p like '%abc%') NOT VALID; -- not supported by sepgsql
+ALTER TABLE regtest_ptable DROP CONSTRAINT test_ck; -- not supported by sepgsql
+ALTER TABLE regtest_ptable SET TABLESPACE pg_default;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_ptable"
+-- partitioned table child
+ALTER TABLE regtest_table_part ALTER p SET DEFAULT 'abcd'; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ALTER p SET DEFAULT 'XYZ'; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ALTER p DROP DEFAULT; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ALTER p SET NOT NULL;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+ALTER TABLE regtest_table_part ALTER p DROP NOT NULL;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+ALTER TABLE regtest_table_part ALTER p SET STATISTICS -1;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+ALTER TABLE regtest_table_part ALTER p SET (n_distinct = 999);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+ALTER TABLE regtest_table_part ALTER p SET STORAGE PLAIN;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table_part.p"
+ALTER TABLE regtest_table_part ADD CONSTRAINT test_ck CHECK (p like '%abc%') NOT VALID; -- not supported by sepgsql
+ALTER TABLE regtest_table_part VALIDATE CONSTRAINT test_ck; -- not supported by sepgsql
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+ALTER TABLE regtest_table_part DROP CONSTRAINT test_ck; -- not supported by sepgsql
+CREATE TRIGGER regtest_part_test_trig BEFORE UPDATE ON regtest_table_part
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+ALTER TABLE regtest_table_part DISABLE TRIGGER regtest_part_test_trig; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ENABLE TRIGGER regtest_part_test_trig; -- not supported by sepgsql
+ALTER TABLE regtest_table_part SET (fillfactor = 75);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table_part"
+ALTER TABLE regtest_table_part RESET (fillfactor);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table_part"
+ALTER TABLE regtest_table_part SET TABLESPACE pg_default;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema_2.regtest_table_part"
+---
+ALTER VIEW regtest_view SET (security_barrier);
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema_2.regtest_view"
+ALTER SEQUENCE regtest_seq INCREMENT BY 10 START WITH 1000;
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema_2.regtest_seq"
+--
+-- clean-up objects
+--
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+DROP DATABASE sepgsql_test_regression;
+DROP SCHEMA regtest_schema CASCADE;
+NOTICE: drop cascades to 4 other objects
+DETAIL: drop cascades to table regtest_table_2
+drop cascades to table regtest_table_3
+drop cascades to constraint test_fk on table regtest_table
+drop cascades to table regtest_ptable_1_tens
+DROP SCHEMA regtest_schema_2 CASCADE;
+NOTICE: drop cascades to 5 other objects
+DETAIL: drop cascades to table regtest_table
+drop cascades to table regtest_ptable
+drop cascades to sequence regtest_seq
+drop cascades to view regtest_view
+drop cascades to function regtest_func(text)
+DROP USER regress_sepgsql_test_user;
diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out
new file mode 100644
index 0000000..0def0e5
--- /dev/null
+++ b/contrib/sepgsql/expected/ddl.out
@@ -0,0 +1,537 @@
+--
+-- Regression Test for DDL of Object Permission Checks
+--
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS sepgsql_test_regression;
+DROP USER IF EXISTS regress_sepgsql_test_user;
+RESET client_min_messages;
+-- confirm required permissions using audit messages
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0
+(1 row)
+
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+--
+-- CREATE Permission checks
+--
+CREATE DATABASE sepgsql_test_regression;
+LOG: SELinux: allowed { getattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_db_t:s0 tclass=db_database name="template1"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="sepgsql_test_regression"
+CREATE USER regress_sepgsql_test_user;
+CREATE SCHEMA regtest_schema;
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+GRANT ALL ON SCHEMA regtest_schema TO regress_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:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LINE 1: CREATE TABLE regtest_table (x serial primary key, y text);
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LINE 1: CREATE TABLE regtest_table (x serial primary key, y text);
+ ^
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_table_x_seq"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.x"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.y"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_table_x_seq"
+ALTER TABLE regtest_table ADD COLUMN z int;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ALTER TABLE regtest_table ADD COLUMN z int;
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.z"
+CREATE TABLE regtest_table_2 (a int);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_table_2 (a int);
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_2"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.a"
+CREATE TABLE regtest_ptable (a int) PARTITION BY RANGE (a);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_ptable (a int) PARTITION BY RANGE (a);
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.a"
+CREATE TABLE regtest_ptable_ones PARTITION OF regtest_ptable FOR VALUES FROM ('0') TO ('10');
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_ones"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.a"
+CREATE TABLE regtest_ptable_tens PARTITION OF regtest_ptable FOR VALUES FROM ('10') TO ('100');
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_tens"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.a"
+ALTER TABLE regtest_ptable ADD COLUMN q int;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ALTER TABLE regtest_ptable ADD COLUMN q int;
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.q"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.q"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.q"
+-- corresponding toast table should not have label and permission checks
+ALTER TABLE regtest_table_2 ADD COLUMN b text;
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b"
+-- VACUUM FULL internally create a new table and swap them later.
+VACUUM FULL regtest_table;
+VACUUM FULL regtest_ptable;
+CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_view"
+CREATE VIEW regtest_pview AS SELECT * FROM regtest_ptable WHERE a < 99;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_pview"
+CREATE SEQUENCE regtest_seq;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_seq"
+CREATE TYPE regtest_comptype AS (a int, b text);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="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:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema.regtest_func(pg_catalog.text,integer[])"
+CREATE AGGREGATE regtest_agg (
+ sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0'
+);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema.regtest_agg(integer)"
+-- CREATE objects owned by others
+SET SESSION AUTHORIZATION regress_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:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LINE 1: CREATE TABLE regtest_table_3 (x int, y serial);
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LINE 1: CREATE TABLE regtest_table_3 (x int, y serial);
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_table_3 (x int, y serial);
+ ^
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_table_3_y_seq"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_3"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.x"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.y"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_table_3_y_seq"
+CREATE TABLE regtest_ptable_3 (o int, p serial) PARTITION BY RANGE (o);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_ptable_3 (o int, p serial) PARTITION BY...
+ ^
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_ptable_3_p_seq"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_3"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.o"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.p"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_ptable_3_p_seq"
+CREATE TABLE regtest_ptable_3_ones PARTITION OF regtest_ptable_3 FOR VALUES FROM ('0') to ('10');
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_3_ones"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.o"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.p"
+CREATE TABLE regtest_ptable_3_tens PARTITION OF regtest_ptable_3 FOR VALUES FROM ('10') to ('100');
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_3_tens"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.o"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.p"
+CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < y;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_view_2"
+CREATE VIEW regtest_pview_2 AS SELECT * FROM regtest_ptable_3 WHERE o < p;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_pview_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:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema.regtest_func_2(integer)"
+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:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="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:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LINE 1: CREATE TABLE regtest_table_4 (x int primary key, y int, z in...
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_table_4 (x int primary key, y int, z in...
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ...REATE TABLE regtest_table_4 (x int primary key, y int, z int...
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: ...ATE TABLE regtest_table_4 (x int primary key, y int, z int);
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.x"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.y"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.z"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.y"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.float8(integer)"
+DROP INDEX regtest_index_tbl4_y;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+ALTER TABLE regtest_table_4
+ ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+DROP TABLE regtest_table_4 CASCADE;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_4"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.x"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.y"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_4.z"
+-- For partitioned tables
+CREATE TABLE regtest_ptable_4 (x int, y int, z int) PARTITION BY RANGE (x);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_ptable_4 (x int, y int, z int) PARTITIO...
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_ptable_4 (x int, y int, z int) PARTITIO...
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LINE 1: CREATE TABLE regtest_ptable_4 (x int, y int, z int) PARTITIO...
+ ^
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.x"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.y"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.z"
+CREATE TABLE regtest_ptable_4_ones PARTITION OF regtest_ptable_4 FOR VALUES FROM ('0') TO ('10');
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.x"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.y"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.z"
+CREATE INDEX regtest_pindex_tbl4_y ON regtest_ptable_4_ones(y);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+CREATE INDEX regtest_pindex_tbl4_z ON regtest_ptable_4_ones(z);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+ALTER TABLE regtest_ptable_4 ALTER COLUMN y TYPE float;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.y"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.y"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.float8(integer)"
+DROP INDEX regtest_pindex_tbl4_y;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+ALTER TABLE regtest_ptable_4_ones
+ ADD CONSTRAINT regtest_ptbl4_con EXCLUDE USING btree (z WITH =);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+DROP TABLE regtest_ptable_4 CASCADE;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4_ones"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.x"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.y"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4_ones.z"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_4"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.x"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.y"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_4.z"
+--
+-- DROP Permission checks (with clean-up)
+--
+DROP FUNCTION regtest_func(text,int[]);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema.regtest_func(pg_catalog.text,integer[])"
+DROP AGGREGATE regtest_agg(int);
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="pg_catalog"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema.regtest_agg(integer)"
+DROP SEQUENCE regtest_seq;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_seq"
+DROP VIEW regtest_view;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_view"
+ALTER TABLE regtest_table DROP COLUMN y;
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.y"
+ALTER TABLE regtest_ptable DROP COLUMN q CASCADE;
+NOTICE: drop cascades to view regtest_pview
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.q"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.q"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_pview"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.q"
+DROP TABLE regtest_table;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_table_x_seq"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.x"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table.z"
+DROP TABLE regtest_ptable CASCADE;
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_tens"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_tens.a"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_ones"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_ones.a"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable.a"
+DROP OWNED BY regress_sepgsql_test_user;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="regtest_schema.regtest_func_2(integer)"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_pview_2"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="regtest_schema.regtest_view_2"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_3_tens"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.o"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_tens.p"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_3_ones"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.o"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3_ones.p"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_ptable_3_p_seq"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_ptable_3"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.o"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_ptable_3.p"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="regtest_schema.regtest_table_3_y_seq"
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_3"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.x"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_3.y"
+DROP DATABASE sepgsql_test_regression;
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="sepgsql_test_regression"
+DROP USER regress_sepgsql_test_user;
+DROP SCHEMA IF EXISTS regtest_schema CASCADE;
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { search } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=system_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="public"
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to table regtest_table_2
+drop cascades to type regtest_comptype
+LOG: SELinux: allowed { remove_name } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="regtest_schema.regtest_table_2"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.tableoid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.cmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.xmax"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.cmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.xmin"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.ctid"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.a"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b"
+LOG: SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="regtest_schema"
diff --git a/contrib/sepgsql/expected/dml.out b/contrib/sepgsql/expected/dml.out
new file mode 100644
index 0000000..6d5b1c1
--- /dev/null
+++ b/contrib/sepgsql/expected/dml.out
@@ -0,0 +1,399 @@
+--
+-- Regression Test for DML Permissions
+--
+--
+-- Setup
+--
+CREATE TABLE t1 (a int, junk int, b text);
+SECURITY LABEL ON TABLE t1 IS 'system_u:object_r:sepgsql_table_t:s0';
+ALTER TABLE t1 DROP COLUMN junk;
+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc');
+CREATE TABLE t2 (x int, y text);
+SECURITY LABEL ON TABLE t2 IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+INSERT INTO t2 VALUES (1, 'xxx'), (2, 'yyy'), (3, 'zzz');
+CREATE TABLE t3 (s int, t text);
+SECURITY LABEL ON TABLE t3 IS 'system_u:object_r:sepgsql_fixed_table_t:s0';
+INSERT INTO t3 VALUES (1, 'sss'), (2, 'ttt'), (3, 'uuu');
+CREATE TABLE t4 (m int, junk int, n text);
+SECURITY LABEL ON TABLE t4 IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+ALTER TABLE t4 DROP COLUMN junk;
+INSERT INTO t4 VALUES (1, 'mmm'), (2, 'nnn'), (3, 'ooo');
+CREATE TABLE t5 (e text, f text, g text);
+SECURITY LABEL ON TABLE t5 IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t5.e IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t5.f IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t5.g IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+---
+-- partitioned table parent
+CREATE TABLE t1p (o int, p text, q text) PARTITION BY RANGE (o);
+SECURITY LABEL ON TABLE t1p IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p.o IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p.p IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t1p.q IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+-- partitioned table children
+CREATE TABLE t1p_ones PARTITION OF t1p FOR VALUES FROM ('0') TO ('10');
+SECURITY LABEL ON COLUMN t1p_ones.o IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_ones.p IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_ones.q IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+CREATE TABLE t1p_tens PARTITION OF t1p FOR VALUES FROM ('10') TO ('100');
+SECURITY LABEL ON COLUMN t1p_tens.o IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_tens.p IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_tens.q IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+---
+CREATE TABLE customer (cid int primary key, cname text, ccredit text);
+SECURITY LABEL ON COLUMN customer.ccredit IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+INSERT INTO customer VALUES (1, 'Taro', '1111-2222-3333-4444'),
+ (2, 'Hanako', '5555-6666-7777-8888');
+CREATE FUNCTION customer_credit(int) RETURNS text
+ AS 'SELECT regexp_replace(ccredit, ''-[0-9]+$'', ''-????'') FROM customer WHERE cid = $1'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION customer_credit(int)
+ IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
+SELECT objtype, objname, label FROM pg_seclabels
+ WHERE provider = 'selinux'
+ AND objtype in ('table', 'column')
+ AND objname in ('t1', 't2', 't3', 't4',
+ 't5', 't5.e', 't5.f', 't5.g',
+ 't1p', 't1p.o', 't1p.p', 't1p.q',
+ 't1p_ones', 't1p_ones.o', 't1p_ones.p', 't1p_ones.q',
+ 't1p_tens', 't1p_tens.o', 't1p_tens.p', 't1p_tens.q')
+ORDER BY objname COLLATE "C";
+ objtype | objname | label
+---------+------------+---------------------------------------------
+ table | t1 | system_u:object_r:sepgsql_table_t:s0
+ table | t1p | system_u:object_r:sepgsql_table_t:s0
+ column | t1p.o | system_u:object_r:sepgsql_table_t:s0
+ column | t1p.p | system_u:object_r:sepgsql_ro_table_t:s0
+ column | t1p.q | system_u:object_r:sepgsql_secret_table_t:s0
+ table | t1p_ones | unconfined_u:object_r:sepgsql_table_t:s0
+ column | t1p_ones.o | system_u:object_r:sepgsql_table_t:s0
+ column | t1p_ones.p | system_u:object_r:sepgsql_ro_table_t:s0
+ column | t1p_ones.q | system_u:object_r:sepgsql_secret_table_t:s0
+ table | t1p_tens | unconfined_u:object_r:sepgsql_table_t:s0
+ column | t1p_tens.o | system_u:object_r:sepgsql_table_t:s0
+ column | t1p_tens.p | system_u:object_r:sepgsql_ro_table_t:s0
+ column | t1p_tens.q | system_u:object_r:sepgsql_secret_table_t:s0
+ table | t2 | system_u:object_r:sepgsql_ro_table_t:s0
+ table | t3 | system_u:object_r:sepgsql_fixed_table_t:s0
+ table | t4 | system_u:object_r:sepgsql_secret_table_t:s0
+ table | t5 | system_u:object_r:sepgsql_table_t:s0
+ column | t5.e | system_u:object_r:sepgsql_table_t:s0
+ column | t5.f | system_u:object_r:sepgsql_ro_table_t:s0
+ column | t5.g | system_u:object_r:sepgsql_secret_table_t:s0
+(20 rows)
+
+CREATE SCHEMA my_schema_1;
+CREATE TABLE my_schema_1.ts1 (a int, b text);
+CREATE TABLE my_schema_1.pts1 (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE my_schema_1.pts1_ones PARTITION OF my_schema_1.pts1 FOR VALUES FROM ('0') to ('10');
+CREATE SCHEMA my_schema_2;
+CREATE TABLE my_schema_2.ts2 (x int, y text);
+CREATE TABLE my_schema_2.pts2 (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE my_schema_2.pts2_tens PARTITION OF my_schema_2.pts2 FOR VALUES FROM ('10') to ('100');
+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
+ERROR: SELinux: hardwired security policy violation
+--
+-- Simple DML statements
+--
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+(1 row)
+
+SELECT * FROM t1; -- ok
+ a | b
+---+-----
+ 1 | aaa
+ 2 | bbb
+ 3 | ccc
+(3 rows)
+
+SELECT * FROM t2; -- ok
+ x | y
+---+-----
+ 1 | xxx
+ 2 | yyy
+ 3 | zzz
+(3 rows)
+
+SELECT * FROM t3; -- ok
+ s | t
+---+-----
+ 1 | sss
+ 2 | ttt
+ 3 | uuu
+(3 rows)
+
+SELECT * FROM t4; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM t5; -- failed
+ERROR: SELinux: security policy violation
+SELECT e,f FROM t5; -- ok
+ e | f
+---+---
+(0 rows)
+
+SELECT (t1.*)::record FROM t1; -- ok
+ t1
+---------
+ (1,aaa)
+ (2,bbb)
+ (3,ccc)
+(3 rows)
+
+SELECT (t4.*)::record FROM t4; -- failed
+ERROR: SELinux: security policy violation
+---
+-- partitioned table parent
+SELECT * FROM t1p; -- failed
+ERROR: SELinux: security policy violation
+SELECT o,p FROM t1p; -- ok
+ o | p
+---+---
+(0 rows)
+
+--partitioned table children
+SELECT * FROM t1p_ones; -- failed
+ERROR: SELinux: security policy violation
+SELECT o FROM t1p_ones; -- ok
+ o
+---
+(0 rows)
+
+SELECT o,p FROM t1p_ones; -- ok
+ o | p
+---+---
+(0 rows)
+
+SELECT * FROM t1p_tens; -- failed
+ERROR: SELinux: security policy violation
+SELECT o FROM t1p_tens; -- ok
+ o
+---
+(0 rows)
+
+SELECT o,p FROM t1p_tens; -- ok
+ o | p
+---+---
+(0 rows)
+
+---
+SELECT * FROM customer; -- failed
+ERROR: SELinux: security policy violation
+SELECT cid, cname, customer_credit(cid) FROM customer; -- ok
+ cid | cname | customer_credit
+-----+--------+---------------------
+ 1 | Taro | 1111-2222-3333-????
+ 2 | Hanako | 5555-6666-7777-????
+(2 rows)
+
+SELECT count(*) FROM t5; -- ok
+ count
+-------
+ 0
+(1 row)
+
+SELECT count(*) FROM t5 WHERE g IS NULL; -- failed
+ERROR: SELinux: security policy violation
+---
+-- partitioned table parent
+SELECT count(*) FROM t1p; -- ok
+ count
+-------
+ 0
+(1 row)
+
+SELECT count(*) FROM t1p WHERE q IS NULL; -- failed
+ERROR: SELinux: security policy violation
+-- partitioned table children
+SELECT count(*) FROM t1p_ones; -- ok
+ count
+-------
+ 0
+(1 row)
+
+SELECT count(*) FROM t1p_ones WHERE q IS NULL; -- failed
+ERROR: SELinux: security policy violation
+SELECT count(*) FROM t1p_tens; -- ok
+ count
+-------
+ 0
+(1 row)
+
+SELECT count(*) FROM t1p_tens WHERE q IS NULL; -- failed
+ERROR: SELinux: security policy violation
+---
+INSERT INTO t1 VALUES (4, 'abc'); -- ok
+INSERT INTO t2 VALUES (4, 'xyz'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t3 VALUES (4, 'stu'); -- ok
+INSERT INTO t4 VALUES (4, 'mno'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t5 VALUES (1,2,3); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t5 (e,f) VALUES ('abc', 'def'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t5 (e) VALUES ('abc'); -- ok
+---
+-- partitioned table parent
+INSERT INTO t1p (o,p) VALUES (9, 'mno'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t1p (o) VALUES (9); -- ok
+INSERT INTO t1p (o,p) VALUES (99, 'pqr'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t1p (o) VALUES (99); -- ok
+-- partitioned table children
+INSERT INTO t1p_ones (o,p) VALUES (9, 'mno'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t1p_ones (o) VALUES (9); -- ok
+INSERT INTO t1p_tens (o,p) VALUES (99, 'pqr'); -- failed
+ERROR: SELinux: security policy violation
+INSERT INTO t1p_tens (o) VALUES (99); -- ok
+---
+UPDATE t1 SET b = b || '_upd'; -- ok
+UPDATE t2 SET y = y || '_upd'; -- failed
+ERROR: SELinux: security policy violation
+UPDATE t3 SET t = t || '_upd'; -- failed
+ERROR: SELinux: security policy violation
+UPDATE t4 SET n = n || '_upd'; -- failed
+ERROR: SELinux: security policy violation
+UPDATE t5 SET e = 'xyz'; -- ok
+UPDATE t5 SET e = f || '_upd'; -- ok
+UPDATE t5 SET e = g || '_upd'; -- failed
+ERROR: SELinux: security policy violation
+---
+-- partitioned table parent
+UPDATE t1p SET o = 9 WHERE o < 10; -- ok
+UPDATE t1p SET o = 99 WHERE o >= 10; -- ok
+UPDATE t1p SET o = ascii(COALESCE(p,'upd'))%10 WHERE o < 10; -- ok
+UPDATE t1p SET o = ascii(COALESCE(q,'upd'))%100 WHERE o >= 10; -- failed
+ERROR: SELinux: security policy violation
+-- partitioned table children
+UPDATE t1p_ones SET o = 9; -- ok
+UPDATE t1p_ones SET o = ascii(COALESCE(p,'upd'))%10; -- ok
+UPDATE t1p_ones SET o = ascii(COALESCE(q,'upd'))%10; -- failed
+ERROR: SELinux: security policy violation
+UPDATE t1p_tens SET o = 99; -- ok
+UPDATE t1p_tens SET o = ascii(COALESCE(p,'upd'))%100; -- ok
+UPDATE t1p_tens SET o = ascii(COALESCE(q,'upd'))%100; -- failed
+ERROR: SELinux: security policy violation
+---
+DELETE FROM t1; -- ok
+DELETE FROM t2; -- failed
+ERROR: SELinux: security policy violation
+DELETE FROM t3; -- failed
+ERROR: SELinux: security policy violation
+DELETE FROM t4; -- failed
+ERROR: SELinux: security policy violation
+DELETE FROM t5; -- ok
+DELETE FROM t5 WHERE f IS NULL; -- ok
+DELETE FROM t5 WHERE g IS NULL; -- failed
+ERROR: SELinux: security policy violation
+---
+-- partitioned table parent
+DELETE FROM t1p; -- ok
+DELETE FROM t1p WHERE p IS NULL; -- ok
+DELETE FROM t1p WHERE q IS NULL; -- failed
+ERROR: SELinux: security policy violation
+-- partitioned table children
+DELETE FROM t1p_ones WHERE p IS NULL; -- ok
+DELETE FROM t1p_ones WHERE q IS NULL; -- failed;
+ERROR: SELinux: security policy violation
+DELETE FROM t1p_tens WHERE p IS NULL; -- ok
+DELETE FROM t1p_tens WHERE q IS NULL; -- failed
+ERROR: SELinux: security policy violation
+---
+--
+-- COPY TO/FROM statements
+--
+COPY t1 TO '/dev/null'; -- ok
+COPY t2 TO '/dev/null'; -- ok
+COPY t3 TO '/dev/null'; -- ok
+COPY t4 TO '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t5 TO '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t5(e,f) TO '/dev/null'; -- ok
+---
+-- partitioned table parent
+COPY (SELECT * FROM t1p) TO '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY (SELECT (o,p) FROM t1p) TO '/dev/null'; -- ok
+-- partitioned table children
+COPY t1p_ones TO '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t1p_ones(o,p) TO '/dev/null'; -- ok
+COPY t1p_tens TO '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t1p_tens(o,p) TO '/dev/null'; -- ok
+---
+COPY t1 FROM '/dev/null'; -- ok
+COPY t2 FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t3 FROM '/dev/null'; -- ok
+COPY t4 FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t5 FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t5 (e,f) FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t5 (e) FROM '/dev/null'; -- ok
+---
+-- partitioned table parent
+COPY t1p FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t1p (o) FROM '/dev/null'; -- ok
+-- partitioned table children
+COPY t1p_ones FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t1p_ones (o) FROM '/dev/null'; -- ok
+COPY t1p_tens FROM '/dev/null'; -- failed
+ERROR: SELinux: security policy violation
+COPY t1p_tens (o) 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
+ sepgsql_getcon
+---------------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255
+(1 row)
+
+DROP TABLE IF EXISTS t1 CASCADE;
+DROP TABLE IF EXISTS t2 CASCADE;
+DROP TABLE IF EXISTS t3 CASCADE;
+DROP TABLE IF EXISTS t4 CASCADE;
+DROP TABLE IF EXISTS t5 CASCADE;
+DROP TABLE IF EXISTS t1p CASCADE;
+DROP TABLE IF EXISTS customer CASCADE;
+DROP SCHEMA IF EXISTS my_schema_1 CASCADE;
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to table my_schema_1.ts1
+drop cascades to table my_schema_1.pts1
+DROP SCHEMA IF EXISTS my_schema_2 CASCADE;
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to table my_schema_2.ts2
+drop cascades to table my_schema_2.pts2
diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out
new file mode 100644
index 0000000..0300bc6
--- /dev/null
+++ b/contrib/sepgsql/expected/label.out
@@ -0,0 +1,611 @@
+--
+-- Regression Tests for Label Management
+--
+--
+-- Setup
+--
+CREATE TABLE t1 (a int, b text);
+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc');
+SELECT * INTO t2 FROM t1 WHERE a % 2 = 0;
+CREATE FUNCTION f1 () RETURNS text
+ AS 'SELECT sepgsql_getcon()'
+ LANGUAGE sql;
+CREATE FUNCTION f2 () RETURNS text
+ AS 'SELECT sepgsql_getcon()'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION f2()
+ IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
+CREATE FUNCTION f3 () RETURNS text
+ AS 'BEGIN
+ RAISE EXCEPTION ''an exception from f3()'';
+ RETURN NULL;
+ END;' LANGUAGE plpgsql;
+SECURITY LABEL ON FUNCTION f3()
+ IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
+CREATE FUNCTION f4 () RETURNS text
+ AS 'SELECT sepgsql_getcon()'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION f4()
+ IS 'system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0';
+CREATE FUNCTION f5 (text) RETURNS bool
+ AS 'SELECT sepgsql_setcon($1)'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION f5(text)
+ IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0';
+CREATE TABLE auth_tbl(uname text, credential text, label text);
+INSERT INTO auth_tbl
+ VALUES ('foo', 'acbd18db4cc2f85cedef654fccc4a4d8', 'sepgsql_regtest_foo_t:s0'),
+ ('var', 'b2145aac704ce76dbe1ac7adac535b23', 'sepgsql_regtest_var_t:s0'),
+ ('baz', 'b2145aac704ce76dbe1ac7adac535b23', 'sepgsql_regtest_baz_t:s0');
+SECURITY LABEL ON TABLE auth_tbl
+ IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+CREATE FUNCTION auth_func(text, text) RETURNS bool
+ LANGUAGE sql
+ AS 'SELECT sepgsql_setcon(regexp_replace(sepgsql_getcon(), ''_r:.*$'', ''_r:'' || label))
+ FROM auth_tbl WHERE uname = $1 AND credential = $2';
+SECURITY LABEL ON FUNCTION auth_func(text,text)
+ IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0';
+CREATE TABLE foo_tbl(a int, b text);
+INSERT INTO foo_tbl VALUES (1, 'aaa'), (2,'bbb'), (3,'ccc'), (4,'ddd');
+SECURITY LABEL ON TABLE foo_tbl
+ IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
+CREATE TABLE var_tbl(x int, y text);
+INSERT INTO var_tbl VALUES (2,'xxx'), (3,'yyy'), (4,'zzz'), (5,'xyz');
+SECURITY LABEL ON TABLE var_tbl
+ IS 'system_u:object_r:sepgsql_regtest_var_table_t:s0';
+CREATE TABLE foo_ptbl(o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE foo_ptbl_ones PARTITION OF foo_ptbl FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE foo_ptbl_tens PARTITION OF foo_ptbl FOR VALUES FROM ('10') TO ('100');
+INSERT INTO foo_ptbl VALUES (0, 'aaa'), (9,'bbb'), (10,'ccc'), (99,'ddd');
+SECURITY LABEL ON TABLE foo_ptbl
+ IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
+CREATE TABLE var_ptbl(q int, r text) PARTITION BY RANGE (q);
+CREATE TABLE var_ptbl_ones PARTITION OF var_ptbl FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE var_ptbl_tens PARTITION OF var_ptbl FOR VALUES FROM ('10') TO ('100');
+INSERT INTO var_ptbl VALUES (0,'xxx'), (9,'yyy'), (10,'zzz'), (99,'xyz');
+SECURITY LABEL ON TABLE var_ptbl
+ IS 'system_u:object_r:sepgsql_regtest_var_table_t:s0';
+--
+-- Tests for default labeling behavior
+--
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+(1 row)
+
+CREATE TABLE t3 (s int, t text);
+INSERT INTO t3 VALUES (1, 'sss'), (2, 'ttt'), (3, 'uuu');
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0
+(1 row)
+
+CREATE TABLE t4 (m int, n text);
+INSERT INTO t4 VALUES (1,'mmm'), (2,'nnn'), (3,'ooo');
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+(1 row)
+
+CREATE TABLE tpart (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE tpart_ones PARTITION OF tpart FOR VALUES FROM ('0') TO ('10');
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0
+(1 row)
+
+CREATE TABLE tpart_tens PARTITION OF tpart FOR VALUES FROM ('10') TO ('100');
+INSERT INTO tpart VALUES (0, 'aaa');
+INSERT INTO tpart VALUES (9, 'bbb');
+INSERT INTO tpart VALUES (99, 'ccc');
+SELECT objtype, objname, label FROM pg_seclabels
+ WHERE provider = 'selinux' AND objtype = 'table' AND objname in ('t1', 't2', 't3',
+ 'tpart',
+ 'tpart_ones',
+ 'tpart_tens')
+ ORDER BY objname COLLATE "C" ASC;
+ objtype | objname | label
+---------+------------+-----------------------------------------------
+ table | t1 | unconfined_u:object_r:sepgsql_table_t:s0
+ table | t2 | unconfined_u:object_r:sepgsql_table_t:s0
+ table | t3 | unconfined_u:object_r:user_sepgsql_table_t:s0
+ table | tpart | unconfined_u:object_r:user_sepgsql_table_t:s0
+ table | tpart_ones | unconfined_u:object_r:user_sepgsql_table_t:s0
+ table | tpart_tens | unconfined_u:object_r:sepgsql_table_t:s0
+(6 rows)
+
+SELECT objtype, objname, label FROM pg_seclabels
+ WHERE provider = 'selinux' AND objtype = 'column' AND (objname like 't3.%'
+ OR objname like 't4.%'
+ OR objname like 'tpart.%'
+ OR objname like 'tpart_ones.%'
+ OR objname like 'tpart_tens.%')
+ ORDER BY objname COLLATE "C" ASC;
+ objtype | objname | label
+---------+---------------------+-----------------------------------------------
+ column | t3.cmax | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.cmin | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.ctid | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.s | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.t | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.tableoid | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.xmax | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t3.xmin | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | t4.cmax | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | t4.cmin | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | t4.ctid | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | t4.m | unconfined_u:object_r:sepgsql_table_t:s0
+ column | t4.n | unconfined_u:object_r:sepgsql_table_t:s0
+ column | t4.tableoid | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | t4.xmax | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | t4.xmin | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | tpart.cmax | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.cmin | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.ctid | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.o | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.p | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.tableoid | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.xmax | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart.xmin | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.cmax | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.cmin | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.ctid | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.o | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.p | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.tableoid | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.xmax | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_ones.xmin | unconfined_u:object_r:user_sepgsql_table_t:s0
+ column | tpart_tens.cmax | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | tpart_tens.cmin | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | tpart_tens.ctid | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | tpart_tens.o | unconfined_u:object_r:sepgsql_table_t:s0
+ column | tpart_tens.p | unconfined_u:object_r:sepgsql_table_t:s0
+ column | tpart_tens.tableoid | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | tpart_tens.xmax | unconfined_u:object_r:sepgsql_sysobj_t:s0
+ column | tpart_tens.xmin | unconfined_u:object_r:sepgsql_sysobj_t:s0
+(40 rows)
+
+--
+-- Tests for SECURITY LABEL
+--
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0
+(1 row)
+
+SECURITY LABEL ON TABLE t1
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+SECURITY LABEL ON TABLE t2
+ IS 'invalid security context'; -- be failed
+ERROR: SELinux: invalid security label: "invalid security context"
+SECURITY LABEL ON COLUMN t2
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- be failed
+ERROR: column name must be qualified
+SECURITY LABEL ON COLUMN t2.b
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+SECURITY LABEL ON TABLE tpart
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+SECURITY LABEL ON TABLE tpart
+ IS 'invalid security context'; -- failed
+ERROR: SELinux: invalid security label: "invalid security context"
+SECURITY LABEL ON COLUMN tpart
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- failed
+ERROR: column name must be qualified
+SECURITY LABEL ON COLUMN tpart.o
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+--
+-- Tests for Trusted Procedures
+--
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+-----------------------------------------------------
+ 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="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()"
+ 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="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="pg_catalog.sepgsql_getcon()"
+ 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="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()
+CONTEXT: PL/pgSQL function f3() line 2 at RAISE
+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="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="pg_catalog.sepgsql_getcon()"
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+(1 row)
+
+--
+-- Test for Dynamic Domain Transition
+--
+-- validation of transaction aware dynamic-transition
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+-----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c25
+(1 row)
+
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c15');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c15
+(1 row)
+
+SELECT sepgsql_setcon(NULL); -- failed to reset
+ERROR: SELinux: security policy violation
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c15
+(1 row)
+
+BEGIN;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c12');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c12
+(1 row)
+
+SAVEPOINT svpt_1;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c9');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c9
+(1 row)
+
+SAVEPOINT svpt_2;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c6');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c6
+(1 row)
+
+SAVEPOINT svpt_3;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c3');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c3
+(1 row)
+
+ROLLBACK TO SAVEPOINT svpt_2;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c9'
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c9
+(1 row)
+
+ROLLBACK TO SAVEPOINT svpt_1;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c12'
+ sepgsql_getcon
+-----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c12
+(1 row)
+
+ABORT;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c15'
+ sepgsql_getcon
+-----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c15
+(1 row)
+
+BEGIN;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c8');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c8
+(1 row)
+
+SAVEPOINT svpt_1;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c4');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c4
+(1 row)
+
+ROLLBACK TO SAVEPOINT svpt_1;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c8'
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c8
+(1 row)
+
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c6');
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+COMMIT;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c6'
+ sepgsql_getcon
+----------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c6
+(1 row)
+
+-- sepgsql_regtest_user_t is not available dynamic-transition,
+-- unless sepgsql_setcon() is called inside of trusted-procedure
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15
+(1 row)
+
+-- sepgsql_regtest_user_t has no permission to switch current label
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0'); -- failed
+ERROR: SELinux: security policy violation
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15
+(1 row)
+
+-- trusted procedure allows to switch, but unavailable to override MCS rules
+SELECT f5('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c7'); -- OK
+ f5
+----
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c7
+(1 row)
+
+SELECT f5('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c31'); -- Failed
+ERROR: SELinux: security policy violation
+CONTEXT: SQL function "f5" statement 1
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c7
+(1 row)
+
+SELECT f5(NULL); -- Failed
+ERROR: SELinux: security policy violation
+CONTEXT: SQL function "f5" statement 1
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c7
+(1 row)
+
+BEGIN;
+SELECT f5('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c3'); -- OK
+ f5
+----
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c3
+(1 row)
+
+ABORT;
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c7
+(1 row)
+
+--
+-- Test for simulation of typical connection pooling server
+--
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_pool_t:s0
+(1 row)
+
+-- we shouldn't allow to switch client label without trusted procedure
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_foo_t:s0');
+ERROR: SELinux: security policy violation
+SELECT * FROM auth_tbl; -- failed, no permission to reference
+ERROR: SELinux: security policy violation
+-- switch to "foo"
+SELECT auth_func('foo', 'acbd18db4cc2f85cedef654fccc4a4d8');
+ auth_func
+-----------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_foo_t:s0
+(1 row)
+
+SELECT * FROM foo_tbl; -- OK
+ a | b
+---+-----
+ 1 | aaa
+ 2 | bbb
+ 3 | ccc
+ 4 | ddd
+(4 rows)
+
+SELECT * FROM foo_ptbl; -- OK
+ o | p
+----+-----
+ 0 | aaa
+ 9 | bbb
+ 10 | ccc
+ 99 | ddd
+(4 rows)
+
+SELECT * FROM var_tbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM var_ptbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM auth_tbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT sepgsql_setcon(NULL); -- end of session
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_pool_t:s0
+(1 row)
+
+-- the pooler cannot touch these tables directly
+SELECT * FROM foo_tbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM foo_ptbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM var_tbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM var_ptbl; -- failed
+ERROR: SELinux: security policy violation
+-- switch to "var"
+SELECT auth_func('var', 'b2145aac704ce76dbe1ac7adac535b23');
+ auth_func
+-----------
+ t
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_var_t:s0
+(1 row)
+
+SELECT * FROM foo_tbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM foo_ptbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT * FROM var_tbl; -- OK
+ x | y
+---+-----
+ 2 | xxx
+ 3 | yyy
+ 4 | zzz
+ 5 | xyz
+(4 rows)
+
+SELECT * FROM var_ptbl; -- OK
+ q | r
+----+-----
+ 0 | xxx
+ 9 | yyy
+ 10 | zzz
+ 99 | xyz
+(4 rows)
+
+SELECT * FROM auth_tbl; -- failed
+ERROR: SELinux: security policy violation
+SELECT sepgsql_setcon(NULL); -- end of session
+ sepgsql_setcon
+----------------
+ t
+(1 row)
+
+-- misc checks
+SELECT auth_func('var', 'invalid credential'); -- not works
+ auth_func
+-----------
+
+(1 row)
+
+SELECT sepgsql_getcon();
+ sepgsql_getcon
+-----------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_pool_t:s0
+(1 row)
+
+--
+-- Clean up
+--
+SELECT sepgsql_getcon(); -- confirm client privilege
+ sepgsql_getcon
+---------------------------------------------------------------------
+ unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255
+(1 row)
+
+DROP TABLE IF EXISTS t1 CASCADE;
+DROP TABLE IF EXISTS t2 CASCADE;
+DROP TABLE IF EXISTS t3 CASCADE;
+DROP TABLE IF EXISTS t4 CASCADE;
+DROP TABLE IF EXISTS tpart CASCADE;
+DROP FUNCTION IF EXISTS f1() CASCADE;
+DROP FUNCTION IF EXISTS f2() CASCADE;
+DROP FUNCTION IF EXISTS f3() CASCADE;
+DROP FUNCTION IF EXISTS f4() CASCADE;
+DROP FUNCTION IF EXISTS f5(text) CASCADE;
diff --git a/contrib/sepgsql/expected/misc.out b/contrib/sepgsql/expected/misc.out
new file mode 100644
index 0000000..b2c01e0
--- /dev/null
+++ b/contrib/sepgsql/expected/misc.out
@@ -0,0 +1,231 @@
+--
+-- Regression Test for Misc Permission Checks
+--
+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);
+CREATE TABLE t1p (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE t1p_ones PARTITION OF t1p FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE t1p_tens PARTITION OF t1p FOR VALUES FROM ('10') TO ('100');
+INSERT INTO t1p (SELECT x, md5(x::text) FROM generate_series(0,99) 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column x of table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column y of table t1"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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
+ 89 | 7647966b7343c29048673252e490f736
+ 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 91 | 54229abfcfa5649e7003b83dd4755294
+ 99 | ac627ab1ccbdb62ec96e702f07f6425b
+ 100 | f899139df5e1059396431415e770c6dd
+(6 rows)
+
+SELECT * FROM t1p WHERE o > 50 AND p like '%64%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_tens"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+ o | p
+----+----------------------------------
+ 77 | 28dd2c7955ce926456240b2ff0100bde
+ 89 | 7647966b7343c29048673252e490f736
+ 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 91 | 54229abfcfa5649e7003b83dd4755294
+ 99 | ac627ab1ccbdb62ec96e702f07f6425b
+(5 rows)
+
+SELECT * FROM t1p_ones WHERE o > 50 AND p like '%64%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_ones"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+ o | p
+---+---
+(0 rows)
+
+SELECT * FROM t1p_tens WHERE o > 50 AND p like '%64%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_tens"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+ o | p
+----+----------------------------------
+ 77 | 28dd2c7955ce926456240b2ff0100bde
+ 89 | 7647966b7343c29048673252e490f736
+ 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 91 | 54229abfcfa5649e7003b83dd4755294
+ 99 | ac627ab1ccbdb62ec96e702f07f6425b
+(5 rows)
+
+-- aggregate function
+SELECT MIN(x), AVG(x) FROM t1;
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column x of table t1"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4smaller(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int8_avg(bigint[])"
+ min | avg
+-----+---------------------
+ 1 | 50.5000000000000000
+(1 row)
+
+SELECT MIN(o), AVG(o) FROM t1p;
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_tens"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4smaller(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int8_avg(bigint[])"
+ min | avg
+-----+---------------------
+ 0 | 49.5000000000000000
+(1 row)
+
+SELECT MIN(o), AVG(o) FROM t1p_ones;
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_ones"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4smaller(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int8_avg(bigint[])"
+ min | avg
+-----+--------------------
+ 0 | 4.5000000000000000
+(1 row)
+
+SELECT MIN(o), AVG(o) FROM t1p_tens;
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_tens"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4smaller(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int8_avg(bigint[])"
+ min | avg
+-----+---------------------
+ 10 | 54.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:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column x of table t1"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column y of table t1"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4eq(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.row_number()"
+ 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)
+
+SELECT row_number() OVER (order by o), * FROM t1p WHERE p like '%86%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_tens"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4eq(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.row_number()"
+ row_number | o | p
+------------+----+----------------------------------
+ 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)
+
+SELECT row_number() OVER (order by o), * FROM t1p_ones WHERE p like '%86%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_ones"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_ones"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4eq(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.row_number()"
+ row_number | o | p
+------------+---+----------------------------------
+ 1 | 2 | c81e728d9d4c2f636f067f89cc14862c
+(1 row)
+
+SELECT row_number() OVER (order by o), * FROM t1p_tens WHERE p like '%86%';
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column o of table t1p_tens"
+LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="column p of table t1p_tens"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.textlike(pg_catalog.text,pg_catalog.text)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.int4eq(integer,integer)"
+LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="pg_catalog.row_number()"
+ row_number | o | p
+------------+----+----------------------------------
+ 1 | 17 | 70efdf2ec9b086079795c442636b55fb
+ 2 | 22 | b6d767d2f8ed5d21a44b0e5886680cb9
+ 3 | 27 | 02e74f10e0327ad868d138f2b4fdd6f0
+ 4 | 33 | 182be0c5cdcd5072bb1864cdee4d3d6e
+ 5 | 43 | 17e62166fc8586dfa4d1bc0e1742c08b
+ 6 | 54 | a684eceee76fc522773286a895bc8436
+ 7 | 73 | d2ddea18f00665ce8623e36bd4e3c7c5
+ 8 | 76 | fbd7939d674997cdb4692d34de8633c4
+ 9 | 89 | 7647966b7343c29048673252e490f736
+ 10 | 90 | 8613985ec49eb8f757ae6439e879bb2a
+ 11 | 94 | f4b9ec30ad9f68f89b29639786cb62ef
+(11 rows)
+
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+--
+-- Cleanup
+--
+DROP TABLE IF EXISTS t1 CASCADE;
+DROP TABLE IF EXISTS t1p CASCADE;
diff --git a/contrib/sepgsql/expected/truncate.out b/contrib/sepgsql/expected/truncate.out
new file mode 100644
index 0000000..e2cabd7
--- /dev/null
+++ b/contrib/sepgsql/expected/truncate.out
@@ -0,0 +1,46 @@
+--
+-- Regression Test for TRUNCATE
+--
+--
+-- Setup
+--
+CREATE TABLE julio_claudians (name text, birth_date date);
+SECURITY LABEL ON TABLE julio_claudians IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
+INSERT INTO julio_claudians VALUES ('Augustus', 'September 23, 63 BC'), ('Tiberius', 'November 16, 42 BC'), ('Caligula', 'August 31, 0012'), ('Claudius', 'August 1, 0010'), ('Nero', 'December 15, 0037');
+CREATE TABLE flavians (name text, birth_date date);
+SECURITY LABEL ON TABLE flavians IS 'system_u:object_r:sepgsql_table_t:s0';
+INSERT INTO flavians VALUES ('Vespasian', 'November 17, 0009'), ('Titus', 'December 30, 0039'), ('Domitian', 'October 24, 0051');
+SELECT * from julio_claudians;
+ name | birth_date
+----------+---------------
+ Augustus | 09-23-0063 BC
+ Tiberius | 11-16-0042 BC
+ Caligula | 08-31-0012
+ Claudius | 08-01-0010
+ Nero | 12-15-0037
+(5 rows)
+
+SELECT * from flavians;
+ name | birth_date
+-----------+------------
+ Vespasian | 11-17-0009
+ Titus | 12-30-0039
+ Domitian | 10-24-0051
+(3 rows)
+
+TRUNCATE TABLE julio_claudians; -- ok
+TRUNCATE TABLE flavians; -- failed
+ERROR: SELinux: security policy violation
+SELECT * from julio_claudians;
+ name | birth_date
+------+------------
+(0 rows)
+
+SELECT * from flavians;
+ name | birth_date
+-----------+------------
+ Vespasian | 11-17-0009
+ Titus | 12-30-0039
+ Domitian | 10-24-0051
+(3 rows)
+
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
new file mode 100644
index 0000000..853b5b0
--- /dev/null
+++ b/contrib/sepgsql/hooks.c
@@ -0,0 +1,481 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/hooks.c
+ *
+ * Entrypoints of the hooks in PostgreSQL, and dispatches the callbacks.
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/dependency.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_database.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
+#include "commands/seclabel.h"
+#include "executor/executor.h"
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "sepgsql.h"
+#include "tcop/utility.h"
+#include "utils/guc.h"
+#include "utils/queryenvironment.h"
+
+PG_MODULE_MAGIC;
+
+/*
+ * Declarations
+ */
+void _PG_init(void);
+
+/*
+ * Saved hook entries (if stacked)
+ */
+static object_access_hook_type next_object_access_hook = NULL;
+static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
+static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
+
+/*
+ * Contextual information on DDL commands
+ */
+typedef struct
+{
+ NodeTag cmdtype;
+
+ /*
+ * Name of the template database given by users on CREATE DATABASE
+ * command. Elsewhere (including the case of default) NULL.
+ */
+ const char *createdb_dtemplate;
+} sepgsql_context_info_t;
+
+static sepgsql_context_info_t sepgsql_context_info;
+
+/*
+ * GUC: sepgsql.permissive = (on|off)
+ */
+static bool sepgsql_permissive;
+
+bool
+sepgsql_get_permissive(void)
+{
+ return sepgsql_permissive;
+}
+
+/*
+ * GUC: sepgsql.debug_audit = (on|off)
+ */
+static bool sepgsql_debug_audit;
+
+bool
+sepgsql_get_debug_audit(void)
+{
+ return sepgsql_debug_audit;
+}
+
+/*
+ * sepgsql_object_access
+ *
+ * Entrypoint of the object_access_hook. This routine performs as
+ * a dispatcher of invocation based on access type and object classes.
+ */
+static void
+sepgsql_object_access(ObjectAccessType access,
+ Oid classId,
+ Oid objectId,
+ int subId,
+ void *arg)
+{
+ if (next_object_access_hook)
+ (*next_object_access_hook) (access, classId, objectId, subId, arg);
+
+ switch (access)
+ {
+ case OAT_POST_CREATE:
+ {
+ ObjectAccessPostCreate *pc_arg = arg;
+ bool is_internal;
+
+ is_internal = pc_arg ? pc_arg->is_internal : false;
+
+ switch (classId)
+ {
+ case DatabaseRelationId:
+ Assert(!is_internal);
+ sepgsql_database_post_create(objectId,
+ sepgsql_context_info.createdb_dtemplate);
+ break;
+
+ case NamespaceRelationId:
+ Assert(!is_internal);
+ sepgsql_schema_post_create(objectId);
+ break;
+
+ case RelationRelationId:
+ if (subId == 0)
+ {
+ /*
+ * The cases in which we want to apply permission
+ * checks on creation of a new relation correspond
+ * to direct user invocation. For internal uses,
+ * that is creation of toast tables, index rebuild
+ * or ALTER TABLE commands, we need neither
+ * assignment of security labels nor permission
+ * checks.
+ */
+ if (is_internal)
+ break;
+
+ sepgsql_relation_post_create(objectId);
+ }
+ else
+ sepgsql_attribute_post_create(objectId, subId);
+ break;
+
+ case ProcedureRelationId:
+ Assert(!is_internal);
+ sepgsql_proc_post_create(objectId);
+ break;
+
+ default:
+ /* Ignore unsupported object classes */
+ break;
+ }
+ }
+ break;
+
+ case OAT_DROP:
+ {
+ ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
+
+ /*
+ * No need to apply permission checks on object deletion due
+ * to internal cleanups; such as removal of temporary database
+ * object on session closed.
+ */
+ if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
+ break;
+
+ switch (classId)
+ {
+ case DatabaseRelationId:
+ sepgsql_database_drop(objectId);
+ break;
+
+ case NamespaceRelationId:
+ sepgsql_schema_drop(objectId);
+ break;
+
+ case RelationRelationId:
+ if (subId == 0)
+ sepgsql_relation_drop(objectId);
+ else
+ sepgsql_attribute_drop(objectId, subId);
+ break;
+
+ case ProcedureRelationId:
+ sepgsql_proc_drop(objectId);
+ break;
+
+ default:
+ /* Ignore unsupported object classes */
+ break;
+ }
+ }
+ break;
+
+ case OAT_TRUNCATE:
+ {
+ switch (classId)
+ {
+ case RelationRelationId:
+ sepgsql_relation_truncate(objectId);
+ break;
+ default:
+ /* Ignore unsupported object classes */
+ break;
+ }
+ }
+ break;
+
+ case OAT_POST_ALTER:
+ {
+ ObjectAccessPostAlter *pa_arg = arg;
+ bool is_internal = pa_arg->is_internal;
+
+ switch (classId)
+ {
+ case DatabaseRelationId:
+ Assert(!is_internal);
+ sepgsql_database_setattr(objectId);
+ break;
+
+ case NamespaceRelationId:
+ Assert(!is_internal);
+ sepgsql_schema_setattr(objectId);
+ break;
+
+ case RelationRelationId:
+ if (subId == 0)
+ {
+ /*
+ * A case when we don't want to apply permission
+ * check is that relation is internally altered
+ * without user's intention. E.g, no need to check
+ * on toast table/index to be renamed at end of
+ * the table rewrites.
+ */
+ if (is_internal)
+ break;
+
+ sepgsql_relation_setattr(objectId);
+ }
+ else
+ sepgsql_attribute_setattr(objectId, subId);
+ break;
+
+ case ProcedureRelationId:
+ Assert(!is_internal);
+ sepgsql_proc_setattr(objectId);
+ break;
+
+ default:
+ /* Ignore unsupported object classes */
+ break;
+ }
+ }
+ break;
+
+ case OAT_NAMESPACE_SEARCH:
+ {
+ ObjectAccessNamespaceSearch *ns_arg = arg;
+
+ /*
+ * If stacked extension already decided not to allow users to
+ * search this schema, we just stick with that decision.
+ */
+ if (!ns_arg->result)
+ break;
+
+ Assert(classId == NamespaceRelationId);
+ Assert(ns_arg->result);
+ ns_arg->result
+ = sepgsql_schema_search(objectId,
+ ns_arg->ereport_on_violation);
+ }
+ break;
+
+ case OAT_FUNCTION_EXECUTE:
+ {
+ Assert(classId == ProcedureRelationId);
+ sepgsql_proc_execute(objectId);
+ }
+ break;
+
+ default:
+ elog(ERROR, "unexpected object access type: %d", (int) access);
+ break;
+ }
+}
+
+/*
+ * sepgsql_exec_check_perms
+ *
+ * Entrypoint of DML permissions
+ */
+static bool
+sepgsql_exec_check_perms(List *rangeTabls, bool abort)
+{
+ /*
+ * If security provider is stacking and one of them replied 'false' at
+ * least, we don't need to check any more.
+ */
+ if (next_exec_check_perms_hook &&
+ !(*next_exec_check_perms_hook) (rangeTabls, abort))
+ return false;
+
+ if (!sepgsql_dml_privileges(rangeTabls, abort))
+ return false;
+
+ return true;
+}
+
+/*
+ * sepgsql_utility_command
+ *
+ * It tries to rough-grained control on utility commands; some of them can
+ * break whole of the things if nefarious user would use.
+ */
+static void
+sepgsql_utility_command(PlannedStmt *pstmt,
+ const char *queryString,
+ ProcessUtilityContext context,
+ ParamListInfo params,
+ QueryEnvironment *queryEnv,
+ DestReceiver *dest,
+ QueryCompletion *qc)
+{
+ Node *parsetree = pstmt->utilityStmt;
+ sepgsql_context_info_t saved_context_info = sepgsql_context_info;
+ ListCell *cell;
+
+ PG_TRY();
+ {
+ /*
+ * Check command tag to avoid nefarious operations, and save the
+ * current contextual information to determine whether we should apply
+ * permission checks here, or not.
+ */
+ sepgsql_context_info.cmdtype = nodeTag(parsetree);
+
+ switch (nodeTag(parsetree))
+ {
+ case T_CreatedbStmt:
+
+ /*
+ * We hope to reference name of the source database, but it
+ * does not appear in system catalog. So, we save it here.
+ */
+ foreach(cell, ((CreatedbStmt *) parsetree)->options)
+ {
+ DefElem *defel = (DefElem *) lfirst(cell);
+
+ if (strcmp(defel->defname, "template") == 0)
+ {
+ sepgsql_context_info.createdb_dtemplate
+ = strVal(defel->arg);
+ break;
+ }
+ }
+ break;
+
+ case T_LoadStmt:
+
+ /*
+ * We reject LOAD command across the board on enforcing mode,
+ * because a binary module can arbitrarily override hooks.
+ */
+ if (sepgsql_getenforce())
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: LOAD is not permitted")));
+ }
+ break;
+ default:
+
+ /*
+ * Right now we don't check any other utility commands,
+ * because it needs more detailed information to make access
+ * control decision here, but we don't want to have two parse
+ * and analyze routines individually.
+ */
+ break;
+ }
+
+ if (next_ProcessUtility_hook)
+ (*next_ProcessUtility_hook) (pstmt, queryString,
+ context, params, queryEnv,
+ dest, qc);
+ else
+ standard_ProcessUtility(pstmt, queryString,
+ context, params, queryEnv,
+ dest, qc);
+ }
+ PG_FINALLY();
+ {
+ sepgsql_context_info = saved_context_info;
+ }
+ PG_END_TRY();
+}
+
+/*
+ * Module load/unload callback
+ */
+void
+_PG_init(void)
+{
+ /*
+ * We allow to load the SE-PostgreSQL module on single-user-mode or
+ * shared_preload_libraries settings only.
+ */
+ if (IsUnderPostmaster)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("sepgsql must be loaded via shared_preload_libraries")));
+
+ /*
+ * Check availability of SELinux on the platform. If disabled, we cannot
+ * activate any SE-PostgreSQL features, and we have to skip rest of
+ * initialization.
+ */
+ if (is_selinux_enabled() < 1)
+ {
+ sepgsql_set_mode(SEPGSQL_MODE_DISABLED);
+ return;
+ }
+
+ /*
+ * sepgsql.permissive = (on|off)
+ *
+ * This variable controls performing mode of SE-PostgreSQL on user's
+ * session.
+ */
+ DefineCustomBoolVariable("sepgsql.permissive",
+ "Turn on/off permissive mode in SE-PostgreSQL",
+ NULL,
+ &sepgsql_permissive,
+ false,
+ PGC_SIGHUP,
+ GUC_NOT_IN_SAMPLE,
+ NULL,
+ NULL,
+ NULL);
+
+ /*
+ * sepgsql.debug_audit = (on|off)
+ *
+ * This variable allows users to turn on/off audit logs on access control
+ * decisions, independent from auditallow/auditdeny setting in the
+ * security policy. We intend to use this option for debugging purpose.
+ */
+ DefineCustomBoolVariable("sepgsql.debug_audit",
+ "Turn on/off debug audit messages",
+ NULL,
+ &sepgsql_debug_audit,
+ false,
+ PGC_USERSET,
+ GUC_NOT_IN_SAMPLE,
+ NULL,
+ NULL,
+ NULL);
+
+ /* Initialize userspace access vector cache */
+ sepgsql_avc_init();
+
+ /* Initialize security label of the client and related stuff */
+ sepgsql_init_client_label();
+
+ /* Security label provider hook */
+ register_label_provider(SEPGSQL_LABEL_TAG,
+ sepgsql_object_relabel);
+
+ /* Object access hook */
+ next_object_access_hook = object_access_hook;
+ object_access_hook = sepgsql_object_access;
+
+ /* DML permission check */
+ next_exec_check_perms_hook = ExecutorCheckPerms_hook;
+ ExecutorCheckPerms_hook = sepgsql_exec_check_perms;
+
+ /* ProcessUtility hook */
+ next_ProcessUtility_hook = ProcessUtility_hook;
+ ProcessUtility_hook = sepgsql_utility_command;
+
+ /* init contextual info */
+ memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
+}
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
new file mode 100644
index 0000000..147ab67
--- /dev/null
+++ b/contrib/sepgsql/label.c
@@ -0,0 +1,938 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/label.c
+ *
+ * Routines to support SELinux labels (security context)
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <selinux/label.h>
+
+#include "access/genam.h"
+#include "access/htup_details.h"
+#include "access/table.h"
+#include "access/xact.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_attribute.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_database.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
+#include "commands/dbcommands.h"
+#include "commands/seclabel.h"
+#include "libpq/auth.h"
+#include "libpq/libpq-be.h"
+#include "miscadmin.h"
+#include "sepgsql.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/guc.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+
+/*
+ * Saved hook entries (if stacked)
+ */
+static ClientAuthentication_hook_type next_client_auth_hook = NULL;
+static needs_fmgr_hook_type next_needs_fmgr_hook = NULL;
+static fmgr_hook_type next_fmgr_hook = NULL;
+
+/*
+ * client_label_*
+ *
+ * security label of the database client. Initially the client security label
+ * is equal to client_label_peer, and can be changed by one or more calls to
+ * sepgsql_setcon(), and also be temporarily overridden during execution of a
+ * trusted-procedure.
+ *
+ * sepgsql_setcon() is a transaction-aware operation; a (sub-)transaction
+ * rollback should also rollback the current client security label. Therefore
+ * we use the list client_label_pending of pending_label to keep track of which
+ * labels were set during the (sub-)transactions.
+ */
+static char *client_label_peer = NULL; /* set by getpeercon(3) */
+static List *client_label_pending = NIL; /* pending list being set by
+ * sepgsql_setcon() */
+static char *client_label_committed = NULL; /* set by sepgsql_setcon(), and
+ * already committed */
+static char *client_label_func = NULL; /* set by trusted procedure */
+
+typedef struct
+{
+ SubTransactionId subid;
+ char *label;
+} pending_label;
+
+/*
+ * sepgsql_get_client_label
+ *
+ * Returns the current security label of the client. All code should use this
+ * routine to get the current label, instead of referring to the client_label_*
+ * variables above.
+ */
+char *
+sepgsql_get_client_label(void)
+{
+ /* trusted procedure client label override */
+ if (client_label_func)
+ return client_label_func;
+
+ /* uncommitted sepgsql_setcon() value */
+ if (client_label_pending)
+ {
+ pending_label *plabel = llast(client_label_pending);
+
+ if (plabel->label)
+ return plabel->label;
+ }
+ else if (client_label_committed)
+ return client_label_committed; /* set by sepgsql_setcon() committed */
+
+ /* default label */
+ Assert(client_label_peer != NULL);
+ return client_label_peer;
+}
+
+/*
+ * sepgsql_set_client_label
+ *
+ * This routine tries to switch the current security label of the client, and
+ * checks related permissions. The supplied new label shall be added to the
+ * client_label_pending list, then saved at transaction-commit time to ensure
+ * transaction-awareness.
+ */
+static void
+sepgsql_set_client_label(const char *new_label)
+{
+ const char *tcontext;
+ MemoryContext oldcxt;
+ pending_label *plabel;
+
+ /* Reset to the initial client label, if NULL */
+ if (!new_label)
+ tcontext = client_label_peer;
+ else
+ {
+ if (security_check_context_raw((security_context_t) new_label) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("SELinux: invalid security label: \"%s\"",
+ new_label)));
+ tcontext = new_label;
+ }
+
+ /* Check process:{setcurrent} permission. */
+ sepgsql_avc_check_perms_label(sepgsql_get_client_label(),
+ SEPG_CLASS_PROCESS,
+ SEPG_PROCESS__SETCURRENT,
+ NULL,
+ true);
+ /* Check process:{dyntransition} permission. */
+ sepgsql_avc_check_perms_label(tcontext,
+ SEPG_CLASS_PROCESS,
+ SEPG_PROCESS__DYNTRANSITION,
+ NULL,
+ true);
+
+ /*
+ * Append the supplied new_label on the pending list until the current
+ * transaction is committed.
+ */
+ oldcxt = MemoryContextSwitchTo(CurTransactionContext);
+
+ plabel = palloc0(sizeof(pending_label));
+ plabel->subid = GetCurrentSubTransactionId();
+ if (new_label)
+ plabel->label = pstrdup(new_label);
+ client_label_pending = lappend(client_label_pending, plabel);
+
+ MemoryContextSwitchTo(oldcxt);
+}
+
+/*
+ * sepgsql_xact_callback
+ *
+ * A callback routine of transaction commit/abort/prepare. Commit or abort
+ * changes in the client_label_pending list.
+ */
+static void
+sepgsql_xact_callback(XactEvent event, void *arg)
+{
+ if (event == XACT_EVENT_COMMIT)
+ {
+ if (client_label_pending != NIL)
+ {
+ pending_label *plabel = llast(client_label_pending);
+ char *new_label;
+
+ if (plabel->label)
+ new_label = MemoryContextStrdup(TopMemoryContext,
+ plabel->label);
+ else
+ new_label = NULL;
+
+ if (client_label_committed)
+ pfree(client_label_committed);
+
+ client_label_committed = new_label;
+
+ /*
+ * XXX - Note that items of client_label_pending are allocated on
+ * CurTransactionContext, thus, all acquired memory region shall
+ * be released implicitly.
+ */
+ client_label_pending = NIL;
+ }
+ }
+ else if (event == XACT_EVENT_ABORT)
+ client_label_pending = NIL;
+}
+
+/*
+ * sepgsql_subxact_callback
+ *
+ * A callback routine of sub-transaction start/abort/commit. Releases all
+ * security labels that are set within the sub-transaction that is aborted.
+ */
+static void
+sepgsql_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
+ SubTransactionId parentSubid, void *arg)
+{
+ ListCell *cell;
+
+ if (event == SUBXACT_EVENT_ABORT_SUB)
+ {
+ foreach(cell, client_label_pending)
+ {
+ pending_label *plabel = lfirst(cell);
+
+ if (plabel->subid == mySubid)
+ client_label_pending
+ = foreach_delete_current(client_label_pending, cell);
+ }
+ }
+}
+
+/*
+ * sepgsql_client_auth
+ *
+ * Entrypoint of the client authentication hook.
+ * It switches the client label according to getpeercon(), and the current
+ * performing mode according to the GUC setting.
+ */
+static void
+sepgsql_client_auth(Port *port, int status)
+{
+ if (next_client_auth_hook)
+ (*next_client_auth_hook) (port, status);
+
+ /*
+ * In the case when authentication failed, the supplied socket shall be
+ * closed soon, so we don't need to do anything here.
+ */
+ if (status != STATUS_OK)
+ return;
+
+ /*
+ * Getting security label of the peer process using API of libselinux.
+ */
+ if (getpeercon_raw(port->sock, &client_label_peer) < 0)
+ ereport(FATAL,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: unable to get peer label: %m")));
+
+ /*
+ * Switch the current performing mode from INTERNAL to either DEFAULT or
+ * PERMISSIVE.
+ */
+ if (sepgsql_get_permissive())
+ sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE);
+ else
+ sepgsql_set_mode(SEPGSQL_MODE_DEFAULT);
+}
+
+/*
+ * sepgsql_needs_fmgr_hook
+ *
+ * It informs the core whether the supplied function is trusted procedure,
+ * or not. If true, sepgsql_fmgr_hook shall be invoked at start, end, and
+ * abort time of function invocation.
+ */
+static bool
+sepgsql_needs_fmgr_hook(Oid functionId)
+{
+ ObjectAddress object;
+
+ if (next_needs_fmgr_hook &&
+ (*next_needs_fmgr_hook) (functionId))
+ return true;
+
+ /*
+ * SELinux needs the function to be called via security_definer wrapper,
+ * if this invocation will take a domain-transition. We call these
+ * functions as trusted-procedure, if the security policy has a rule that
+ * switches security label of the client on execution.
+ */
+ if (sepgsql_avc_trusted_proc(functionId) != NULL)
+ return true;
+
+ /*
+ * Even if not a trusted-procedure, this function should not be inlined
+ * unless the client has db_procedure:{execute} permission. Please note
+ * that it shall be actually failed later because of same reason with
+ * ACL_EXECUTE.
+ */
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ if (!sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__EXECUTE |
+ SEPG_DB_PROCEDURE__ENTRYPOINT,
+ SEPGSQL_AVC_NOAUDIT, false))
+ return true;
+
+ return false;
+}
+
+/*
+ * sepgsql_fmgr_hook
+ *
+ * It switches security label of the client on execution of trusted
+ * procedures.
+ */
+static void
+sepgsql_fmgr_hook(FmgrHookEventType event,
+ FmgrInfo *flinfo, Datum *private)
+{
+ struct
+ {
+ char *old_label;
+ char *new_label;
+ Datum next_private;
+ } *stack;
+
+ switch (event)
+ {
+ case FHET_START:
+ stack = (void *) DatumGetPointer(*private);
+ if (!stack)
+ {
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
+ stack = palloc(sizeof(*stack));
+ stack->old_label = NULL;
+ stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
+ stack->next_private = 0;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ /*
+ * 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);
+ if (stack->new_label)
+ {
+ stack->old_label = client_label_func;
+ client_label_func = stack->new_label;
+ }
+ if (next_fmgr_hook)
+ (*next_fmgr_hook) (event, flinfo, &stack->next_private);
+ break;
+
+ case FHET_END:
+ case FHET_ABORT:
+ stack = (void *) DatumGetPointer(*private);
+
+ if (next_fmgr_hook)
+ (*next_fmgr_hook) (event, flinfo, &stack->next_private);
+
+ if (stack->new_label)
+ {
+ client_label_func = stack->old_label;
+ stack->old_label = NULL;
+ }
+ break;
+
+ default:
+ elog(ERROR, "unexpected event type: %d", (int) event);
+ break;
+ }
+}
+
+/*
+ * sepgsql_init_client_label
+ *
+ * Initializes the client security label and sets up related hooks for client
+ * label management.
+ */
+void
+sepgsql_init_client_label(void)
+{
+ /*
+ * Set up dummy client label.
+ *
+ * XXX - note that PostgreSQL launches background worker process like
+ * autovacuum without authentication steps. So, we initialize sepgsql_mode
+ * with SEPGSQL_MODE_INTERNAL, and client_label with the security context
+ * of server process. Later, it also launches background of user session.
+ * In this case, the process is always hooked on post-authentication, and
+ * we can initialize the sepgsql_mode and client_label correctly.
+ */
+ if (getcon_raw(&client_label_peer) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: failed to get server security label: %m")));
+
+ /* Client authentication hook */
+ next_client_auth_hook = ClientAuthentication_hook;
+ ClientAuthentication_hook = sepgsql_client_auth;
+
+ /* Trusted procedure hooks */
+ next_needs_fmgr_hook = needs_fmgr_hook;
+ needs_fmgr_hook = sepgsql_needs_fmgr_hook;
+
+ next_fmgr_hook = fmgr_hook;
+ fmgr_hook = sepgsql_fmgr_hook;
+
+ /* Transaction/Sub-transaction callbacks */
+ RegisterXactCallback(sepgsql_xact_callback, NULL);
+ RegisterSubXactCallback(sepgsql_subxact_callback, NULL);
+}
+
+/*
+ * sepgsql_get_label
+ *
+ * It returns a security context of the specified database object.
+ * If unlabeled or incorrectly labeled, the system "unlabeled" label
+ * shall be returned.
+ */
+char *
+sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
+{
+ ObjectAddress object;
+ char *label;
+
+ object.classId = classId;
+ object.objectId = objectId;
+ object.objectSubId = subId;
+
+ label = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
+ if (!label || security_check_context_raw((security_context_t) label))
+ {
+ security_context_t unlabeled;
+
+ if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: failed to get initial security label: %m")));
+ PG_TRY();
+ {
+ label = pstrdup(unlabeled);
+ }
+ PG_FINALLY();
+ {
+ freecon(unlabeled);
+ }
+ PG_END_TRY();
+ }
+ return label;
+}
+
+/*
+ * sepgsql_object_relabel
+ *
+ * An entrypoint of SECURITY LABEL statement
+ */
+void
+sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
+{
+ /*
+ * validate format of the supplied security label, if it is security
+ * context of selinux.
+ */
+ if (seclabel &&
+ security_check_context_raw((security_context_t) seclabel) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("SELinux: invalid security label: \"%s\"", seclabel)));
+
+ /*
+ * Do actual permission checks for each object classes
+ */
+ switch (object->classId)
+ {
+ case DatabaseRelationId:
+ sepgsql_database_relabel(object->objectId, seclabel);
+ break;
+
+ case NamespaceRelationId:
+ sepgsql_schema_relabel(object->objectId, seclabel);
+ break;
+
+ case RelationRelationId:
+ if (object->objectSubId == 0)
+ sepgsql_relation_relabel(object->objectId,
+ seclabel);
+ else
+ sepgsql_attribute_relabel(object->objectId,
+ object->objectSubId,
+ seclabel);
+ break;
+
+ case ProcedureRelationId:
+ sepgsql_proc_relabel(object->objectId, seclabel);
+ break;
+
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("sepgsql provider does not support labels on %s",
+ getObjectTypeDescription(object))));
+ break;
+ }
+}
+
+/*
+ * TEXT sepgsql_getcon(VOID)
+ *
+ * It returns the security label of the client.
+ */
+PG_FUNCTION_INFO_V1(sepgsql_getcon);
+Datum
+sepgsql_getcon(PG_FUNCTION_ARGS)
+{
+ char *client_label;
+
+ if (!sepgsql_is_enabled())
+ PG_RETURN_NULL();
+
+ client_label = sepgsql_get_client_label();
+
+ PG_RETURN_TEXT_P(cstring_to_text(client_label));
+}
+
+/*
+ * BOOL sepgsql_setcon(TEXT)
+ *
+ * It switches the security label of the client.
+ */
+PG_FUNCTION_INFO_V1(sepgsql_setcon);
+Datum
+sepgsql_setcon(PG_FUNCTION_ARGS)
+{
+ const char *new_label;
+
+ if (PG_ARGISNULL(0))
+ new_label = NULL;
+ else
+ new_label = TextDatumGetCString(PG_GETARG_DATUM(0));
+
+ sepgsql_set_client_label(new_label);
+
+ PG_RETURN_BOOL(true);
+}
+
+/*
+ * TEXT sepgsql_mcstrans_in(TEXT)
+ *
+ * It translate the given qualified MLS/MCS range into raw format
+ * when mcstrans daemon is working.
+ */
+PG_FUNCTION_INFO_V1(sepgsql_mcstrans_in);
+Datum
+sepgsql_mcstrans_in(PG_FUNCTION_ARGS)
+{
+ text *label = PG_GETARG_TEXT_PP(0);
+ char *raw_label;
+ char *result;
+
+ if (!sepgsql_is_enabled())
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("sepgsql is not enabled")));
+
+ if (selinux_trans_to_raw_context(text_to_cstring(label),
+ &raw_label) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: could not translate security label: %m")));
+
+ PG_TRY();
+ {
+ result = pstrdup(raw_label);
+ }
+ PG_FINALLY();
+ {
+ freecon(raw_label);
+ }
+ PG_END_TRY();
+
+ PG_RETURN_TEXT_P(cstring_to_text(result));
+}
+
+/*
+ * TEXT sepgsql_mcstrans_out(TEXT)
+ *
+ * It translate the given raw MLS/MCS range into qualified format
+ * when mcstrans daemon is working.
+ */
+PG_FUNCTION_INFO_V1(sepgsql_mcstrans_out);
+Datum
+sepgsql_mcstrans_out(PG_FUNCTION_ARGS)
+{
+ text *label = PG_GETARG_TEXT_PP(0);
+ char *qual_label;
+ char *result;
+
+ if (!sepgsql_is_enabled())
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("sepgsql is not currently enabled")));
+
+ if (selinux_raw_to_trans_context(text_to_cstring(label),
+ &qual_label) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: could not translate security label: %m")));
+
+ PG_TRY();
+ {
+ result = pstrdup(qual_label);
+ }
+ PG_FINALLY();
+ {
+ freecon(qual_label);
+ }
+ PG_END_TRY();
+
+ PG_RETURN_TEXT_P(cstring_to_text(result));
+}
+
+/*
+ * quote_object_name
+ *
+ * It tries to quote the supplied identifiers
+ */
+static char *
+quote_object_name(const char *src1, const char *src2,
+ const char *src3, const char *src4)
+{
+ StringInfoData result;
+ const char *temp;
+
+ initStringInfo(&result);
+
+ if (src1)
+ {
+ temp = quote_identifier(src1);
+ appendStringInfoString(&result, temp);
+ if (src1 != temp)
+ pfree((void *) temp);
+ }
+ if (src2)
+ {
+ temp = quote_identifier(src2);
+ appendStringInfo(&result, ".%s", temp);
+ if (src2 != temp)
+ pfree((void *) temp);
+ }
+ if (src3)
+ {
+ temp = quote_identifier(src3);
+ appendStringInfo(&result, ".%s", temp);
+ if (src3 != temp)
+ pfree((void *) temp);
+ }
+ if (src4)
+ {
+ temp = quote_identifier(src4);
+ appendStringInfo(&result, ".%s", temp);
+ if (src4 != temp)
+ pfree((void *) temp);
+ }
+ return result.data;
+}
+
+/*
+ * exec_object_restorecon
+ *
+ * This routine is a helper called by sepgsql_restorecon; it set up
+ * initial security labels of database objects within the supplied
+ * catalog OID.
+ */
+static void
+exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
+{
+ Relation rel;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ char *database_name = get_database_name(MyDatabaseId);
+ char *namespace_name;
+ Oid namespace_id;
+ char *relation_name;
+
+ /*
+ * Open the target catalog. We don't want to allow writable accesses by
+ * other session during initial labeling.
+ */
+ rel = table_open(catalogId, AccessShareLock);
+
+ sscan = systable_beginscan(rel, InvalidOid, false,
+ NULL, 0, NULL);
+ while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
+ {
+ Form_pg_database datForm;
+ Form_pg_namespace nspForm;
+ Form_pg_class relForm;
+ Form_pg_attribute attForm;
+ Form_pg_proc proForm;
+ char *objname;
+ int objtype = 1234;
+ ObjectAddress object;
+ security_context_t context;
+
+ /*
+ * The way to determine object name depends on object classes. So, any
+ * branches set up `objtype', `objname' and `object' here.
+ */
+ switch (catalogId)
+ {
+ case DatabaseRelationId:
+ datForm = (Form_pg_database) GETSTRUCT(tuple);
+
+ objtype = SELABEL_DB_DATABASE;
+
+ objname = quote_object_name(NameStr(datForm->datname),
+ NULL, NULL, NULL);
+
+ object.classId = DatabaseRelationId;
+ object.objectId = datForm->oid;
+ object.objectSubId = 0;
+ break;
+
+ case NamespaceRelationId:
+ nspForm = (Form_pg_namespace) GETSTRUCT(tuple);
+
+ objtype = SELABEL_DB_SCHEMA;
+
+ objname = quote_object_name(database_name,
+ NameStr(nspForm->nspname),
+ NULL, NULL);
+
+ object.classId = NamespaceRelationId;
+ object.objectId = nspForm->oid;
+ object.objectSubId = 0;
+ break;
+
+ case RelationRelationId:
+ relForm = (Form_pg_class) GETSTRUCT(tuple);
+
+ if (relForm->relkind == RELKIND_RELATION ||
+ relForm->relkind == RELKIND_PARTITIONED_TABLE)
+ objtype = SELABEL_DB_TABLE;
+ else if (relForm->relkind == RELKIND_SEQUENCE)
+ objtype = SELABEL_DB_SEQUENCE;
+ else if (relForm->relkind == RELKIND_VIEW)
+ objtype = SELABEL_DB_VIEW;
+ else
+ continue; /* no need to assign security label */
+
+ namespace_name = get_namespace_name(relForm->relnamespace);
+ objname = quote_object_name(database_name,
+ namespace_name,
+ NameStr(relForm->relname),
+ NULL);
+ pfree(namespace_name);
+
+ object.classId = RelationRelationId;
+ object.objectId = relForm->oid;
+ object.objectSubId = 0;
+ break;
+
+ case AttributeRelationId:
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
+
+ if (get_rel_relkind(attForm->attrelid) != RELKIND_RELATION &&
+ get_rel_relkind(attForm->attrelid) != RELKIND_PARTITIONED_TABLE)
+ continue; /* no need to assign security label */
+
+ objtype = SELABEL_DB_COLUMN;
+
+ namespace_id = get_rel_namespace(attForm->attrelid);
+ namespace_name = get_namespace_name(namespace_id);
+ relation_name = get_rel_name(attForm->attrelid);
+ objname = quote_object_name(database_name,
+ namespace_name,
+ relation_name,
+ NameStr(attForm->attname));
+ pfree(namespace_name);
+ pfree(relation_name);
+
+ object.classId = RelationRelationId;
+ object.objectId = attForm->attrelid;
+ object.objectSubId = attForm->attnum;
+ break;
+
+ case ProcedureRelationId:
+ proForm = (Form_pg_proc) GETSTRUCT(tuple);
+
+ objtype = SELABEL_DB_PROCEDURE;
+
+ namespace_name = get_namespace_name(proForm->pronamespace);
+ objname = quote_object_name(database_name,
+ namespace_name,
+ NameStr(proForm->proname),
+ NULL);
+ pfree(namespace_name);
+
+ object.classId = ProcedureRelationId;
+ object.objectId = proForm->oid;
+ object.objectSubId = 0;
+ break;
+
+ default:
+ elog(ERROR, "unexpected catalog id: %u", catalogId);
+ objname = NULL; /* for compiler quiet */
+ break;
+ }
+
+ if (selabel_lookup_raw(sehnd, &context, objname, objtype) == 0)
+ {
+ PG_TRY();
+ {
+ /*
+ * Check SELinux permission to relabel the fetched object,
+ * then do the actual relabeling.
+ */
+ sepgsql_object_relabel(&object, context);
+
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, context);
+ }
+ PG_FINALLY();
+ {
+ freecon(context);
+ }
+ PG_END_TRY();
+ }
+ else if (errno == ENOENT)
+ ereport(WARNING,
+ (errmsg("SELinux: no initial label assigned for %s (type=%d), skipping",
+ objname, objtype)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: could not determine initial security label for %s (type=%d): %m", objname, objtype)));
+
+ pfree(objname);
+ }
+ systable_endscan(sscan);
+
+ table_close(rel, NoLock);
+}
+
+/*
+ * BOOL sepgsql_restorecon(TEXT specfile)
+ *
+ * This function tries to assign initial security labels on all the object
+ * within the current database, according to the system setting.
+ * It is typically invoked by sepgsql-install script just after initdb, to
+ * assign initial security labels.
+ *
+ * If @specfile is not NULL, it uses explicitly specified specfile, instead
+ * of the system default.
+ */
+PG_FUNCTION_INFO_V1(sepgsql_restorecon);
+Datum
+sepgsql_restorecon(PG_FUNCTION_ARGS)
+{
+ struct selabel_handle *sehnd;
+ struct selinux_opt seopts;
+
+ /*
+ * SELinux has to be enabled on the running platform.
+ */
+ if (!sepgsql_is_enabled())
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("sepgsql is not currently enabled")));
+
+ /*
+ * Check DAC permission. Only superuser can set up initial security
+ * labels, like root-user in filesystems
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: must be superuser to restore initial contexts")));
+
+ /*
+ * Open selabel_lookup(3) stuff. It provides a set of mapping between an
+ * initial security label and object class/name due to the system setting.
+ */
+ if (PG_ARGISNULL(0))
+ {
+ seopts.type = SELABEL_OPT_UNUSED;
+ seopts.value = NULL;
+ }
+ else
+ {
+ seopts.type = SELABEL_OPT_PATH;
+ seopts.value = TextDatumGetCString(PG_GETARG_DATUM(0));
+ }
+ sehnd = selabel_open(SELABEL_CTX_DB, &seopts, 1);
+ if (!sehnd)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: failed to initialize labeling handle: %m")));
+ PG_TRY();
+ {
+ exec_object_restorecon(sehnd, DatabaseRelationId);
+ exec_object_restorecon(sehnd, NamespaceRelationId);
+ exec_object_restorecon(sehnd, RelationRelationId);
+ exec_object_restorecon(sehnd, AttributeRelationId);
+ exec_object_restorecon(sehnd, ProcedureRelationId);
+ }
+ PG_FINALLY();
+ {
+ selabel_close(sehnd);
+ }
+ PG_END_TRY();
+
+ PG_RETURN_BOOL(true);
+}
diff --git a/contrib/sepgsql/launcher b/contrib/sepgsql/launcher
new file mode 100755
index 0000000..0fddaf5
--- /dev/null
+++ b/contrib/sepgsql/launcher
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# A wrapper script to launch psql command in regression test
+#
+# Copyright (c) 2010-2020, PostgreSQL Global Development Group
+#
+# -------------------------------------------------------------------------
+
+if [ $# -lt 1 ]; then
+ echo "usage: `basename $0` <command> [options...]"
+ exit 1
+fi
+
+RUNCON=`which runcon`
+if [ ! -e "$RUNCON" ]; then
+ echo "runcon command is not found"
+ exit 1
+fi
+
+#
+# Read SQL from stdin
+#
+TEMP=`mktemp`
+CONTEXT="unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255"
+
+while IFS='\\n' read LINE
+do
+ if echo "$LINE" | grep -q "^-- @SECURITY-CONTEXT="; then
+ if [ -s "$TEMP" ]; then
+ if [ -n "$CONTEXT" ]; then
+ "$RUNCON" "$CONTEXT" $* < "$TEMP"
+ else
+ $* < $TEMP
+ fi
+ truncate -s0 $TEMP
+ fi
+ CONTEXT=`echo "$LINE" | sed 's/^-- @SECURITY-CONTEXT=//g'`
+ LINE="SELECT sepgsql_getcon(); -- confirm client privilege"
+ fi
+ echo "$LINE" >> $TEMP
+done
+
+if [ -s "$TEMP" ]; then
+ if [ -n "$CONTEXT" ]; then
+ "$RUNCON" "$CONTEXT" $* < "$TEMP"
+ else
+ $* < $TEMP
+ fi
+fi
+
+# cleanup temp file
+rm -f $TEMP
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
new file mode 100644
index 0000000..2c244a9
--- /dev/null
+++ b/contrib/sepgsql/proc.c
@@ -0,0 +1,334 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/proc.c
+ *
+ * Routines corresponding to procedure objects
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "access/table.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "commands/seclabel.h"
+#include "lib/stringinfo.h"
+#include "sepgsql.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/snapmgr.h"
+#include "utils/syscache.h"
+
+/*
+ * sepgsql_proc_post_create
+ *
+ * This routine assigns a default security label on a newly defined
+ * procedure.
+ */
+void
+sepgsql_proc_post_create(Oid functionId)
+{
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ char *nsp_name;
+ char *scontext;
+ char *tcontext;
+ char *ncontext;
+ uint32 required;
+ int i;
+ StringInfoData audit_name;
+ ObjectAddress object;
+ Form_pg_proc proForm;
+
+ /*
+ * Fetch namespace of the new procedure. Because pg_proc entry is not
+ * visible right now, we need to scan the catalog using SnapshotSelf.
+ */
+ rel = table_open(ProcedureRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_proc_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(functionId));
+
+ sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
+ SnapshotSelf, 1, &skey);
+
+ tuple = systable_getnext(sscan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for function %u", functionId);
+
+ proForm = (Form_pg_proc) GETSTRUCT(tuple);
+
+ /*
+ * check db_schema:{add_name} permission of the namespace
+ */
+ object.classId = NamespaceRelationId;
+ object.objectId = proForm->pronamespace;
+ object.objectSubId = 0;
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__ADD_NAME,
+ getObjectIdentity(&object),
+ true);
+
+ /*
+ * XXX - db_language:{implement} also should be checked here
+ */
+
+
+ /*
+ * Compute a default security label when we create a new procedure object
+ * under the specified namespace.
+ */
+ scontext = sepgsql_get_client_label();
+ tcontext = sepgsql_get_label(NamespaceRelationId,
+ proForm->pronamespace, 0);
+ ncontext = sepgsql_compute_create(scontext, tcontext,
+ SEPG_CLASS_DB_PROCEDURE,
+ NameStr(proForm->proname));
+
+ /*
+ * check db_procedure:{create (install)} permission
+ */
+ initStringInfo(&audit_name);
+ nsp_name = get_namespace_name(proForm->pronamespace);
+ appendStringInfo(&audit_name, "%s(",
+ quote_qualified_identifier(nsp_name, NameStr(proForm->proname)));
+ for (i = 0; i < proForm->pronargs; i++)
+ {
+ if (i > 0)
+ appendStringInfoChar(&audit_name, ',');
+
+ object.classId = TypeRelationId;
+ object.objectId = proForm->proargtypes.values[i];
+ object.objectSubId = 0;
+ appendStringInfoString(&audit_name, getObjectIdentity(&object));
+ }
+ appendStringInfoChar(&audit_name, ')');
+
+ required = SEPG_DB_PROCEDURE__CREATE;
+ if (proForm->proleakproof)
+ required |= SEPG_DB_PROCEDURE__INSTALL;
+
+ sepgsql_avc_check_perms_label(ncontext,
+ SEPG_CLASS_DB_PROCEDURE,
+ required,
+ audit_name.data,
+ true);
+
+ /*
+ * Assign the default security label on a new procedure
+ */
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
+
+ /*
+ * Cleanup
+ */
+ systable_endscan(sscan);
+ table_close(rel, AccessShareLock);
+
+ pfree(audit_name.data);
+ pfree(tcontext);
+ pfree(ncontext);
+}
+
+/*
+ * sepgsql_proc_drop
+ *
+ * It checks privileges to drop the supplied function.
+ */
+void
+sepgsql_proc_drop(Oid functionId)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * check db_schema:{remove_name} permission
+ */
+ object.classId = NamespaceRelationId;
+ object.objectId = get_func_namespace(functionId);
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__REMOVE_NAME,
+ audit_name,
+ true);
+ pfree(audit_name);
+
+ /*
+ * check db_procedure:{drop} permission
+ */
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__DROP,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_proc_relabel
+ *
+ * It checks privileges to relabel the supplied function
+ * by the `seclabel'.
+ */
+void
+sepgsql_proc_relabel(Oid functionId, const char *seclabel)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ /*
+ * check db_procedure:{setattr relabelfrom} permission
+ */
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__SETATTR |
+ SEPG_DB_PROCEDURE__RELABELFROM,
+ audit_name,
+ true);
+
+ /*
+ * check db_procedure:{relabelto} permission
+ */
+ sepgsql_avc_check_perms_label(seclabel,
+ SEPG_CLASS_DB_PROCEDURE,
+ SEPG_DB_PROCEDURE__RELABELTO,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_proc_setattr
+ *
+ * It checks privileges to alter the supplied function.
+ */
+void
+sepgsql_proc_setattr(Oid functionId)
+{
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple oldtup;
+ HeapTuple newtup;
+ Form_pg_proc oldform;
+ Form_pg_proc newform;
+ uint32 required;
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * Fetch newer catalog
+ */
+ rel = table_open(ProcedureRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_proc_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(functionId));
+
+ sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
+ SnapshotSelf, 1, &skey);
+ newtup = systable_getnext(sscan);
+ if (!HeapTupleIsValid(newtup))
+ elog(ERROR, "could not find tuple for function %u", functionId);
+ newform = (Form_pg_proc) GETSTRUCT(newtup);
+
+ /*
+ * Fetch older catalog
+ */
+ oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
+ if (!HeapTupleIsValid(oldtup))
+ elog(ERROR, "cache lookup failed for function %u", functionId);
+ oldform = (Form_pg_proc) GETSTRUCT(oldtup);
+
+ /*
+ * Does this ALTER command takes operation to namespace?
+ */
+ if (newform->pronamespace != oldform->pronamespace)
+ {
+ sepgsql_schema_remove_name(oldform->pronamespace);
+ sepgsql_schema_add_name(oldform->pronamespace);
+ }
+ if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0)
+ sepgsql_schema_rename(oldform->pronamespace);
+
+ /*
+ * check db_procedure:{setattr (install)} permission
+ */
+ required = SEPG_DB_PROCEDURE__SETATTR;
+ if (!oldform->proleakproof && newform->proleakproof)
+ required |= SEPG_DB_PROCEDURE__INSTALL;
+
+ object.classId = ProcedureRelationId;
+ object.objectId = functionId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_PROCEDURE,
+ required,
+ audit_name,
+ true);
+ /* cleanups */
+ pfree(audit_name);
+
+ ReleaseSysCache(oldtup);
+ systable_endscan(sscan);
+ table_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 = getObjectIdentity(&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/relation.c b/contrib/sepgsql/relation.c
new file mode 100644
index 0000000..380bc60
--- /dev/null
+++ b/contrib/sepgsql/relation.c
@@ -0,0 +1,774 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/relation.c
+ *
+ * Routines corresponding to relation/attribute objects
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "access/table.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_attribute.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_namespace.h"
+#include "commands/seclabel.h"
+#include "lib/stringinfo.h"
+#include "sepgsql.h"
+#include "utils/builtins.h"
+#include "utils/catcache.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/rel.h"
+#include "utils/snapmgr.h"
+#include "utils/syscache.h"
+
+static void sepgsql_index_modify(Oid indexOid);
+
+/*
+ * sepgsql_attribute_post_create
+ *
+ * This routine assigns a default security label on a newly defined
+ * column, using ALTER TABLE ... ADD COLUMN.
+ * Note that this routine is not invoked in the case of CREATE TABLE,
+ * although it also defines columns in addition to table.
+ */
+void
+sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
+{
+ Relation rel;
+ ScanKeyData skey[2];
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ char *scontext;
+ char *tcontext;
+ char *ncontext;
+ ObjectAddress object;
+ Form_pg_attribute attForm;
+ StringInfoData audit_name;
+ char relkind = get_rel_relkind(relOid);
+
+ /*
+ * Only attributes within regular relations or partition relations have
+ * individual security labels.
+ */
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
+ return;
+
+ /*
+ * Compute a default security label of the new column underlying the
+ * specified relation, and check permission to create it.
+ */
+ rel = table_open(AttributeRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_attribute_attrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relOid));
+ ScanKeyInit(&skey[1],
+ Anum_pg_attribute_attnum,
+ BTEqualStrategyNumber, F_INT2EQ,
+ Int16GetDatum(attnum));
+
+ sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true,
+ SnapshotSelf, 2, &skey[0]);
+
+ tuple = systable_getnext(sscan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for column %d of relation %u",
+ attnum, relOid);
+
+ attForm = (Form_pg_attribute) GETSTRUCT(tuple);
+
+ scontext = sepgsql_get_client_label();
+ tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
+ ncontext = sepgsql_compute_create(scontext, tcontext,
+ SEPG_CLASS_DB_COLUMN,
+ NameStr(attForm->attname));
+
+ /*
+ * check db_column:{create} permission
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+
+ initStringInfo(&audit_name);
+ appendStringInfo(&audit_name, "%s.%s",
+ getObjectIdentity(&object),
+ quote_identifier(NameStr(attForm->attname)));
+ sepgsql_avc_check_perms_label(ncontext,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__CREATE,
+ audit_name.data,
+ true);
+
+ /*
+ * Assign the default security label on a new procedure
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attnum;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
+
+ systable_endscan(sscan);
+ table_close(rel, AccessShareLock);
+
+ pfree(tcontext);
+ pfree(ncontext);
+}
+
+/*
+ * sepgsql_attribute_drop
+ *
+ * It checks privileges to drop the supplied column.
+ */
+void
+sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
+{
+ ObjectAddress object;
+ char *audit_name;
+ char relkind = get_rel_relkind(relOid);
+
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
+ return;
+
+ /*
+ * check db_column:{drop} permission
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attnum;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__DROP,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_attribute_relabel
+ *
+ * It checks privileges to relabel the supplied column
+ * by the `seclabel'.
+ */
+void
+sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
+ const char *seclabel)
+{
+ ObjectAddress object;
+ char *audit_name;
+ char relkind = get_rel_relkind(relOid);
+
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot set security label on non-regular columns")));
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attnum;
+ audit_name = getObjectIdentity(&object);
+
+ /*
+ * check db_column:{setattr relabelfrom} permission
+ */
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__SETATTR |
+ SEPG_DB_COLUMN__RELABELFROM,
+ audit_name,
+ true);
+
+ /*
+ * check db_column:{relabelto} permission
+ */
+ sepgsql_avc_check_perms_label(seclabel,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_PROCEDURE__RELABELTO,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_attribute_setattr
+ *
+ * It checks privileges to alter the supplied column.
+ */
+void
+sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
+{
+ ObjectAddress object;
+ char *audit_name;
+ char relkind = get_rel_relkind(relOid);
+
+ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
+ return;
+
+ /*
+ * check db_column:{setattr} permission
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attnum;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__SETATTR,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_relation_post_create
+ *
+ * The post creation hook of relation/attribute
+ */
+void
+sepgsql_relation_post_create(Oid relOid)
+{
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ ObjectAddress object;
+ uint16_t tclass;
+ char *scontext; /* subject */
+ char *tcontext; /* schema */
+ char *rcontext; /* relation */
+ char *ccontext; /* column */
+ char *nsp_name;
+ StringInfoData audit_name;
+
+ /*
+ * Fetch catalog record of the new relation. Because pg_class entry is not
+ * visible right now, we need to scan the catalog using SnapshotSelf.
+ */
+ rel = table_open(RelationRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_class_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relOid));
+
+ sscan = systable_beginscan(rel, ClassOidIndexId, true,
+ SnapshotSelf, 1, &skey);
+
+ tuple = systable_getnext(sscan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for relation %u", relOid);
+
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+
+ /* ignore indexes on toast tables */
+ if (classForm->relkind == RELKIND_INDEX &&
+ classForm->relnamespace == PG_TOAST_NAMESPACE)
+ goto out;
+
+ /*
+ * check db_schema:{add_name} permission of the namespace
+ */
+ object.classId = NamespaceRelationId;
+ object.objectId = classForm->relnamespace;
+ object.objectSubId = 0;
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__ADD_NAME,
+ getObjectIdentity(&object),
+ true);
+
+ switch (classForm->relkind)
+ {
+ case RELKIND_RELATION:
+ case RELKIND_PARTITIONED_TABLE:
+ tclass = SEPG_CLASS_DB_TABLE;
+ break;
+ case RELKIND_SEQUENCE:
+ tclass = SEPG_CLASS_DB_SEQUENCE;
+ break;
+ case RELKIND_VIEW:
+ tclass = SEPG_CLASS_DB_VIEW;
+ break;
+ case RELKIND_INDEX:
+ /* deal with indexes specially; no need for tclass */
+ sepgsql_index_modify(relOid);
+ goto out;
+ default:
+ /* ignore other relkinds */
+ goto out;
+ }
+
+ /*
+ * Compute a default security label when we create a new relation object
+ * under the specified namespace.
+ */
+ scontext = sepgsql_get_client_label();
+ tcontext = sepgsql_get_label(NamespaceRelationId,
+ classForm->relnamespace, 0);
+ rcontext = sepgsql_compute_create(scontext, tcontext, tclass,
+ NameStr(classForm->relname));
+
+ /*
+ * check db_xxx:{create} permission
+ */
+ nsp_name = get_namespace_name(classForm->relnamespace);
+ initStringInfo(&audit_name);
+ appendStringInfo(&audit_name, "%s.%s",
+ quote_identifier(nsp_name),
+ quote_identifier(NameStr(classForm->relname)));
+ sepgsql_avc_check_perms_label(rcontext,
+ tclass,
+ SEPG_DB_DATABASE__CREATE,
+ audit_name.data,
+ true);
+
+ /*
+ * Assign the default security label on the new regular or partitioned
+ * relation.
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
+
+ /*
+ * We also assign a default security label on columns of a new table.
+ */
+ if (classForm->relkind == RELKIND_RELATION ||
+ classForm->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ Relation arel;
+ ScanKeyData akey;
+ SysScanDesc ascan;
+ HeapTuple atup;
+ Form_pg_attribute attForm;
+
+ arel = table_open(AttributeRelationId, AccessShareLock);
+
+ ScanKeyInit(&akey,
+ Anum_pg_attribute_attrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relOid));
+
+ ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
+ SnapshotSelf, 1, &akey);
+
+ while (HeapTupleIsValid(atup = systable_getnext(ascan)))
+ {
+ attForm = (Form_pg_attribute) GETSTRUCT(atup);
+
+ resetStringInfo(&audit_name);
+ appendStringInfo(&audit_name, "%s.%s.%s",
+ quote_identifier(nsp_name),
+ quote_identifier(NameStr(classForm->relname)),
+ quote_identifier(NameStr(attForm->attname)));
+
+ ccontext = sepgsql_compute_create(scontext,
+ rcontext,
+ SEPG_CLASS_DB_COLUMN,
+ NameStr(attForm->attname));
+
+ /*
+ * check db_column:{create} permission
+ */
+ sepgsql_avc_check_perms_label(ccontext,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__CREATE,
+ audit_name.data,
+ true);
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attForm->attnum;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
+
+ pfree(ccontext);
+ }
+ systable_endscan(ascan);
+ table_close(arel, AccessShareLock);
+ }
+ pfree(rcontext);
+
+out:
+ systable_endscan(sscan);
+ table_close(rel, AccessShareLock);
+}
+
+/*
+ * sepgsql_relation_drop
+ *
+ * It checks privileges to drop the supplied relation.
+ */
+void
+sepgsql_relation_drop(Oid relOid)
+{
+ ObjectAddress object;
+ char *audit_name;
+ uint16_t tclass = 0;
+ char relkind = get_rel_relkind(relOid);
+
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ case RELKIND_PARTITIONED_TABLE:
+ tclass = SEPG_CLASS_DB_TABLE;
+ break;
+ case RELKIND_SEQUENCE:
+ tclass = SEPG_CLASS_DB_SEQUENCE;
+ break;
+ case RELKIND_VIEW:
+ tclass = SEPG_CLASS_DB_VIEW;
+ break;
+ case RELKIND_INDEX:
+ /* ignore indexes on toast tables */
+ if (get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
+ return;
+ /* other indexes are handled specially below; no need for tclass */
+ break;
+ default:
+ /* ignore other relkinds */
+ return;
+ }
+
+ /*
+ * check db_schema:{remove_name} permission
+ */
+ object.classId = NamespaceRelationId;
+ object.objectId = get_rel_namespace(relOid);
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__REMOVE_NAME,
+ audit_name,
+ true);
+ pfree(audit_name);
+
+ /* deal with indexes specially */
+ if (relkind == RELKIND_INDEX)
+ {
+ sepgsql_index_modify(relOid);
+ return;
+ }
+
+ /*
+ * check db_table/sequence/view:{drop} permission
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ tclass,
+ SEPG_DB_TABLE__DROP,
+ audit_name,
+ true);
+ pfree(audit_name);
+
+ /*
+ * check db_column:{drop} permission
+ */
+ if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ Form_pg_attribute attForm;
+ CatCList *attrList;
+ HeapTuple atttup;
+ int i;
+
+ attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
+ for (i = 0; i < attrList->n_members; i++)
+ {
+ atttup = &attrList->members[i]->tuple;
+ attForm = (Form_pg_attribute) GETSTRUCT(atttup);
+
+ if (attForm->attisdropped)
+ continue;
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = attForm->attnum;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__DROP,
+ audit_name,
+ true);
+ pfree(audit_name);
+ }
+ ReleaseCatCacheList(attrList);
+ }
+}
+
+/*
+ * sepgsql_relation_truncate
+ *
+ * Check privileges to TRUNCATE the supplied relation.
+ */
+void
+sepgsql_relation_truncate(Oid relOid)
+{
+ ObjectAddress object;
+ char *audit_name;
+ uint16_t tclass = 0;
+ char relkind = get_rel_relkind(relOid);
+
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ case RELKIND_PARTITIONED_TABLE:
+ tclass = SEPG_CLASS_DB_TABLE;
+ break;
+ default:
+ /* ignore other relkinds */
+ return;
+ }
+
+ /*
+ * check db_table:{truncate} permission
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ tclass,
+ SEPG_DB_TABLE__TRUNCATE,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_relation_relabel
+ *
+ * It checks privileges to relabel the supplied relation by the `seclabel'.
+ */
+void
+sepgsql_relation_relabel(Oid relOid, const char *seclabel)
+{
+ ObjectAddress object;
+ char *audit_name;
+ char relkind = get_rel_relkind(relOid);
+ uint16_t tclass = 0;
+
+ if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
+ tclass = SEPG_CLASS_DB_TABLE;
+ else if (relkind == RELKIND_SEQUENCE)
+ tclass = SEPG_CLASS_DB_SEQUENCE;
+ else if (relkind == RELKIND_VIEW)
+ tclass = SEPG_CLASS_DB_VIEW;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot set security labels on relations except "
+ "for tables, sequences or views")));
+
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ /*
+ * check db_xxx:{setattr relabelfrom} permission
+ */
+ sepgsql_avc_check_perms(&object,
+ tclass,
+ SEPG_DB_TABLE__SETATTR |
+ SEPG_DB_TABLE__RELABELFROM,
+ audit_name,
+ true);
+
+ /*
+ * check db_xxx:{relabelto} permission
+ */
+ sepgsql_avc_check_perms_label(seclabel,
+ tclass,
+ SEPG_DB_TABLE__RELABELTO,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_relation_setattr
+ *
+ * It checks privileges to set attribute of the supplied relation
+ */
+void
+sepgsql_relation_setattr(Oid relOid)
+{
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple oldtup;
+ HeapTuple newtup;
+ Form_pg_class oldform;
+ Form_pg_class newform;
+ ObjectAddress object;
+ char *audit_name;
+ uint16_t tclass;
+
+ switch (get_rel_relkind(relOid))
+ {
+ case RELKIND_RELATION:
+ case RELKIND_PARTITIONED_TABLE:
+ tclass = SEPG_CLASS_DB_TABLE;
+ break;
+ case RELKIND_SEQUENCE:
+ tclass = SEPG_CLASS_DB_SEQUENCE;
+ break;
+ case RELKIND_VIEW:
+ tclass = SEPG_CLASS_DB_VIEW;
+ break;
+ case RELKIND_INDEX:
+ /* deal with indexes specially */
+ sepgsql_index_modify(relOid);
+ return;
+ default:
+ /* other relkinds don't need additional work */
+ return;
+ }
+
+ /*
+ * Fetch newer catalog
+ */
+ rel = table_open(RelationRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_class_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relOid));
+
+ sscan = systable_beginscan(rel, ClassOidIndexId, true,
+ SnapshotSelf, 1, &skey);
+
+ newtup = systable_getnext(sscan);
+ if (!HeapTupleIsValid(newtup))
+ elog(ERROR, "could not find tuple for relation %u", relOid);
+ newform = (Form_pg_class) GETSTRUCT(newtup);
+
+ /*
+ * Fetch older catalog
+ */
+ oldtup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
+ if (!HeapTupleIsValid(oldtup))
+ elog(ERROR, "cache lookup failed for relation %u", relOid);
+ oldform = (Form_pg_class) GETSTRUCT(oldtup);
+
+ /*
+ * Does this ALTER command takes operation to namespace?
+ */
+ if (newform->relnamespace != oldform->relnamespace)
+ {
+ sepgsql_schema_remove_name(oldform->relnamespace);
+ sepgsql_schema_add_name(newform->relnamespace);
+ }
+ if (strcmp(NameStr(newform->relname), NameStr(oldform->relname)) != 0)
+ sepgsql_schema_rename(oldform->relnamespace);
+
+ /*
+ * XXX - In the future version, db_tuple:{use} of system catalog entry
+ * shall be checked, if tablespace configuration is changed.
+ */
+
+ /*
+ * check db_xxx:{setattr} permission
+ */
+ object.classId = RelationRelationId;
+ object.objectId = relOid;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ tclass,
+ SEPG_DB_TABLE__SETATTR,
+ audit_name,
+ true);
+ pfree(audit_name);
+
+ ReleaseSysCache(oldtup);
+ systable_endscan(sscan);
+ table_close(rel, AccessShareLock);
+}
+
+/*
+ * sepgsql_relation_setattr_extra
+ *
+ * It checks permission of the relation being referenced by extra attributes,
+ * such as pg_index entries. Like core PostgreSQL, sepgsql also does not deal
+ * with such entries as individual "objects", thus, modification of these
+ * entries shall be considered as setting an attribute of the underlying
+ * relation.
+ */
+static void
+sepgsql_relation_setattr_extra(Relation catalog,
+ Oid catindex_id,
+ Oid extra_oid,
+ AttrNumber anum_relation_id,
+ AttrNumber anum_extra_id)
+{
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ Datum datum;
+ bool isnull;
+
+ ScanKeyInit(&skey, anum_extra_id,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(extra_oid));
+
+ sscan = systable_beginscan(catalog, catindex_id, true,
+ SnapshotSelf, 1, &skey);
+ tuple = systable_getnext(sscan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for object %u in catalog \"%s\"",
+ extra_oid, RelationGetRelationName(catalog));
+
+ datum = heap_getattr(tuple, anum_relation_id,
+ RelationGetDescr(catalog), &isnull);
+ Assert(!isnull);
+
+ sepgsql_relation_setattr(DatumGetObjectId(datum));
+
+ systable_endscan(sscan);
+}
+
+/*
+ * sepgsql_index_modify
+ * Handle index create, update, drop
+ *
+ * Unlike other relation kinds, indexes do not have their own security labels,
+ * so instead of doing checks directly, treat them as extra attributes of their
+ * owning tables; so check 'setattr' permissions on the table.
+ */
+static void
+sepgsql_index_modify(Oid indexOid)
+{
+ Relation catalog = table_open(IndexRelationId, AccessShareLock);
+
+ /* check db_table:{setattr} permission of the table being indexed */
+ sepgsql_relation_setattr_extra(catalog,
+ IndexRelidIndexId,
+ indexOid,
+ Anum_pg_index_indrelid,
+ Anum_pg_index_indexrelid);
+ table_close(catalog, AccessShareLock);
+}
diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c
new file mode 100644
index 0000000..90ecbc1
--- /dev/null
+++ b/contrib/sepgsql/schema.c
@@ -0,0 +1,236 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/schema.c
+ *
+ * Routines corresponding to schema objects
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/htup_details.h"
+#include "access/sysattr.h"
+#include "access/table.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_database.h"
+#include "catalog/pg_namespace.h"
+#include "commands/seclabel.h"
+#include "lib/stringinfo.h"
+#include "miscadmin.h"
+#include "sepgsql.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/snapmgr.h"
+
+/*
+ * sepgsql_schema_post_create
+ *
+ * This routine assigns a default security label on a newly defined
+ * schema.
+ */
+void
+sepgsql_schema_post_create(Oid namespaceId)
+{
+ Relation rel;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+ char *tcontext;
+ char *ncontext;
+ const char *nsp_name;
+ ObjectAddress object;
+ Form_pg_namespace nspForm;
+ StringInfoData audit_name;
+
+ /*
+ * Compute a default security label when we create a new schema object
+ * under the working database.
+ *
+ * XXX - upcoming version of libselinux supports to take object name to
+ * handle special treatment on default security label; such as special
+ * label on "pg_temp" schema.
+ */
+ rel = table_open(NamespaceRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_namespace_oid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(namespaceId));
+
+ sscan = systable_beginscan(rel, NamespaceOidIndexId, true,
+ SnapshotSelf, 1, &skey);
+ tuple = systable_getnext(sscan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for namespace %u", namespaceId);
+
+ nspForm = (Form_pg_namespace) GETSTRUCT(tuple);
+ nsp_name = NameStr(nspForm->nspname);
+ if (strncmp(nsp_name, "pg_temp_", 8) == 0)
+ nsp_name = "pg_temp";
+ else if (strncmp(nsp_name, "pg_toast_temp_", 14) == 0)
+ nsp_name = "pg_toast_temp";
+
+ tcontext = sepgsql_get_label(DatabaseRelationId, MyDatabaseId, 0);
+ ncontext = sepgsql_compute_create(sepgsql_get_client_label(),
+ tcontext,
+ SEPG_CLASS_DB_SCHEMA,
+ nsp_name);
+
+ /*
+ * check db_schema:{create}
+ */
+ initStringInfo(&audit_name);
+ appendStringInfo(&audit_name, "%s", quote_identifier(nsp_name));
+ sepgsql_avc_check_perms_label(ncontext,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__CREATE,
+ audit_name.data,
+ true);
+ systable_endscan(sscan);
+ table_close(rel, AccessShareLock);
+
+ /*
+ * Assign the default security label on a new procedure
+ */
+ object.classId = NamespaceRelationId;
+ object.objectId = namespaceId;
+ object.objectSubId = 0;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
+
+ pfree(ncontext);
+ pfree(tcontext);
+}
+
+/*
+ * sepgsql_schema_drop
+ *
+ * It checks privileges to drop the supplied schema object.
+ */
+void
+sepgsql_schema_drop(Oid namespaceId)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ /*
+ * check db_schema:{drop} permission
+ */
+ object.classId = NamespaceRelationId;
+ object.objectId = namespaceId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__DROP,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_schema_relabel
+ *
+ * It checks privileges to relabel the supplied schema
+ * by the `seclabel'.
+ */
+void
+sepgsql_schema_relabel(Oid namespaceId, const char *seclabel)
+{
+ ObjectAddress object;
+ char *audit_name;
+
+ object.classId = NamespaceRelationId;
+ object.objectId = namespaceId;
+ object.objectSubId = 0;
+ audit_name = getObjectIdentity(&object);
+
+ /*
+ * check db_schema:{setattr relabelfrom} permission
+ */
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__SETATTR |
+ SEPG_DB_SCHEMA__RELABELFROM,
+ audit_name,
+ true);
+
+ /*
+ * check db_schema:{relabelto} permission
+ */
+ sepgsql_avc_check_perms_label(seclabel,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__RELABELTO,
+ audit_name,
+ true);
+ pfree(audit_name);
+}
+
+/*
+ * sepgsql_schema_check_perms
+ *
+ * utility routine to check db_schema:{xxx} permissions
+ */
+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 = getObjectIdentity(&object);
+
+ 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, 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, true);
+}
+
+void
+sepgsql_schema_remove_name(Oid namespaceId)
+{
+ check_schema_perms(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true);
+}
+
+void
+sepgsql_schema_rename(Oid namespaceId)
+{
+ check_schema_perms(namespaceId,
+ SEPG_DB_SCHEMA__ADD_NAME |
+ SEPG_DB_SCHEMA__REMOVE_NAME,
+ true);
+}
diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c
new file mode 100644
index 0000000..9fdc810
--- /dev/null
+++ b/contrib/sepgsql/selinux.c
@@ -0,0 +1,945 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/selinux.c
+ *
+ * Interactions between userspace and selinux in kernelspace,
+ * using libselinux api.
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "lib/stringinfo.h"
+
+#include "sepgsql.h"
+
+/*
+ * selinux_catalog
+ *
+ * This mapping table enables to translate the name of object classes and
+ * access vectors to/from their own codes.
+ * When we ask SELinux whether the required privileges are allowed or not,
+ * we use security_compute_av(3). It needs us to represent object classes
+ * and access vectors using 'external' codes defined in the security policy.
+ * It is determined in the runtime, not build time. So, it needs an internal
+ * service to translate object class/access vectors which we want to check
+ * into the code which kernel want to be given.
+ */
+static struct
+{
+ const char *class_name;
+ uint16 class_code;
+ struct
+ {
+ const char *av_name;
+ uint32 av_code;
+ } av[32];
+} selinux_catalog[] =
+
+{
+ {
+ "process", SEPG_CLASS_PROCESS,
+ {
+ {
+ "transition", SEPG_PROCESS__TRANSITION
+ },
+ {
+ "dyntransition", SEPG_PROCESS__DYNTRANSITION
+ },
+ {
+ "setcurrent", SEPG_PROCESS__SETCURRENT
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "file", SEPG_CLASS_FILE,
+ {
+ {
+ "read", SEPG_FILE__READ
+ },
+ {
+ "write", SEPG_FILE__WRITE
+ },
+ {
+ "create", SEPG_FILE__CREATE
+ },
+ {
+ "getattr", SEPG_FILE__GETATTR
+ },
+ {
+ "unlink", SEPG_FILE__UNLINK
+ },
+ {
+ "rename", SEPG_FILE__RENAME
+ },
+ {
+ "append", SEPG_FILE__APPEND
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "dir", SEPG_CLASS_DIR,
+ {
+ {
+ "read", SEPG_DIR__READ
+ },
+ {
+ "write", SEPG_DIR__WRITE
+ },
+ {
+ "create", SEPG_DIR__CREATE
+ },
+ {
+ "getattr", SEPG_DIR__GETATTR
+ },
+ {
+ "unlink", SEPG_DIR__UNLINK
+ },
+ {
+ "rename", SEPG_DIR__RENAME
+ },
+ {
+ "search", SEPG_DIR__SEARCH
+ },
+ {
+ "add_name", SEPG_DIR__ADD_NAME
+ },
+ {
+ "remove_name", SEPG_DIR__REMOVE_NAME
+ },
+ {
+ "rmdir", SEPG_DIR__RMDIR
+ },
+ {
+ "reparent", SEPG_DIR__REPARENT
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "lnk_file", SEPG_CLASS_LNK_FILE,
+ {
+ {
+ "read", SEPG_LNK_FILE__READ
+ },
+ {
+ "write", SEPG_LNK_FILE__WRITE
+ },
+ {
+ "create", SEPG_LNK_FILE__CREATE
+ },
+ {
+ "getattr", SEPG_LNK_FILE__GETATTR
+ },
+ {
+ "unlink", SEPG_LNK_FILE__UNLINK
+ },
+ {
+ "rename", SEPG_LNK_FILE__RENAME
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "chr_file", SEPG_CLASS_CHR_FILE,
+ {
+ {
+ "read", SEPG_CHR_FILE__READ
+ },
+ {
+ "write", SEPG_CHR_FILE__WRITE
+ },
+ {
+ "create", SEPG_CHR_FILE__CREATE
+ },
+ {
+ "getattr", SEPG_CHR_FILE__GETATTR
+ },
+ {
+ "unlink", SEPG_CHR_FILE__UNLINK
+ },
+ {
+ "rename", SEPG_CHR_FILE__RENAME
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "blk_file", SEPG_CLASS_BLK_FILE,
+ {
+ {
+ "read", SEPG_BLK_FILE__READ
+ },
+ {
+ "write", SEPG_BLK_FILE__WRITE
+ },
+ {
+ "create", SEPG_BLK_FILE__CREATE
+ },
+ {
+ "getattr", SEPG_BLK_FILE__GETATTR
+ },
+ {
+ "unlink", SEPG_BLK_FILE__UNLINK
+ },
+ {
+ "rename", SEPG_BLK_FILE__RENAME
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "sock_file", SEPG_CLASS_SOCK_FILE,
+ {
+ {
+ "read", SEPG_SOCK_FILE__READ
+ },
+ {
+ "write", SEPG_SOCK_FILE__WRITE
+ },
+ {
+ "create", SEPG_SOCK_FILE__CREATE
+ },
+ {
+ "getattr", SEPG_SOCK_FILE__GETATTR
+ },
+ {
+ "unlink", SEPG_SOCK_FILE__UNLINK
+ },
+ {
+ "rename", SEPG_SOCK_FILE__RENAME
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "fifo_file", SEPG_CLASS_FIFO_FILE,
+ {
+ {
+ "read", SEPG_FIFO_FILE__READ
+ },
+ {
+ "write", SEPG_FIFO_FILE__WRITE
+ },
+ {
+ "create", SEPG_FIFO_FILE__CREATE
+ },
+ {
+ "getattr", SEPG_FIFO_FILE__GETATTR
+ },
+ {
+ "unlink", SEPG_FIFO_FILE__UNLINK
+ },
+ {
+ "rename", SEPG_FIFO_FILE__RENAME
+ },
+ {
+ NULL, 0UL
+ }
+ }
+ },
+ {
+ "db_database", SEPG_CLASS_DB_DATABASE,
+ {
+ {
+ "create", SEPG_DB_DATABASE__CREATE
+ },
+ {
+ "drop", SEPG_DB_DATABASE__DROP
+ },
+ {
+ "getattr", SEPG_DB_DATABASE__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_DATABASE__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_DATABASE__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_DATABASE__RELABELTO
+ },
+ {
+ "access", SEPG_DB_DATABASE__ACCESS
+ },
+ {
+ "load_module", SEPG_DB_DATABASE__LOAD_MODULE
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_schema", SEPG_CLASS_DB_SCHEMA,
+ {
+ {
+ "create", SEPG_DB_SCHEMA__CREATE
+ },
+ {
+ "drop", SEPG_DB_SCHEMA__DROP
+ },
+ {
+ "getattr", SEPG_DB_SCHEMA__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_SCHEMA__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_SCHEMA__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_SCHEMA__RELABELTO
+ },
+ {
+ "search", SEPG_DB_SCHEMA__SEARCH
+ },
+ {
+ "add_name", SEPG_DB_SCHEMA__ADD_NAME
+ },
+ {
+ "remove_name", SEPG_DB_SCHEMA__REMOVE_NAME
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_table", SEPG_CLASS_DB_TABLE,
+ {
+ {
+ "create", SEPG_DB_TABLE__CREATE
+ },
+ {
+ "drop", SEPG_DB_TABLE__DROP
+ },
+ {
+ "getattr", SEPG_DB_TABLE__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_TABLE__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_TABLE__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_TABLE__RELABELTO
+ },
+ {
+ "select", SEPG_DB_TABLE__SELECT
+ },
+ {
+ "update", SEPG_DB_TABLE__UPDATE
+ },
+ {
+ "insert", SEPG_DB_TABLE__INSERT
+ },
+ {
+ "delete", SEPG_DB_TABLE__DELETE
+ },
+ {
+ "lock", SEPG_DB_TABLE__LOCK
+ },
+ {
+ "truncate", SEPG_DB_TABLE__TRUNCATE
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_sequence", SEPG_CLASS_DB_SEQUENCE,
+ {
+ {
+ "create", SEPG_DB_SEQUENCE__CREATE
+ },
+ {
+ "drop", SEPG_DB_SEQUENCE__DROP
+ },
+ {
+ "getattr", SEPG_DB_SEQUENCE__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_SEQUENCE__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_SEQUENCE__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_SEQUENCE__RELABELTO
+ },
+ {
+ "get_value", SEPG_DB_SEQUENCE__GET_VALUE
+ },
+ {
+ "next_value", SEPG_DB_SEQUENCE__NEXT_VALUE
+ },
+ {
+ "set_value", SEPG_DB_SEQUENCE__SET_VALUE
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_procedure", SEPG_CLASS_DB_PROCEDURE,
+ {
+ {
+ "create", SEPG_DB_PROCEDURE__CREATE
+ },
+ {
+ "drop", SEPG_DB_PROCEDURE__DROP
+ },
+ {
+ "getattr", SEPG_DB_PROCEDURE__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_PROCEDURE__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_PROCEDURE__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_PROCEDURE__RELABELTO
+ },
+ {
+ "execute", SEPG_DB_PROCEDURE__EXECUTE
+ },
+ {
+ "entrypoint", SEPG_DB_PROCEDURE__ENTRYPOINT
+ },
+ {
+ "install", SEPG_DB_PROCEDURE__INSTALL
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_column", SEPG_CLASS_DB_COLUMN,
+ {
+ {
+ "create", SEPG_DB_COLUMN__CREATE
+ },
+ {
+ "drop", SEPG_DB_COLUMN__DROP
+ },
+ {
+ "getattr", SEPG_DB_COLUMN__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_COLUMN__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_COLUMN__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_COLUMN__RELABELTO
+ },
+ {
+ "select", SEPG_DB_COLUMN__SELECT
+ },
+ {
+ "update", SEPG_DB_COLUMN__UPDATE
+ },
+ {
+ "insert", SEPG_DB_COLUMN__INSERT
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_tuple", SEPG_CLASS_DB_TUPLE,
+ {
+ {
+ "relabelfrom", SEPG_DB_TUPLE__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_TUPLE__RELABELTO
+ },
+ {
+ "select", SEPG_DB_TUPLE__SELECT
+ },
+ {
+ "update", SEPG_DB_TUPLE__UPDATE
+ },
+ {
+ "insert", SEPG_DB_TUPLE__INSERT
+ },
+ {
+ "delete", SEPG_DB_TUPLE__DELETE
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_blob", SEPG_CLASS_DB_BLOB,
+ {
+ {
+ "create", SEPG_DB_BLOB__CREATE
+ },
+ {
+ "drop", SEPG_DB_BLOB__DROP
+ },
+ {
+ "getattr", SEPG_DB_BLOB__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_BLOB__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_BLOB__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_BLOB__RELABELTO
+ },
+ {
+ "read", SEPG_DB_BLOB__READ
+ },
+ {
+ "write", SEPG_DB_BLOB__WRITE
+ },
+ {
+ "import", SEPG_DB_BLOB__IMPORT
+ },
+ {
+ "export", SEPG_DB_BLOB__EXPORT
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_language", SEPG_CLASS_DB_LANGUAGE,
+ {
+ {
+ "create", SEPG_DB_LANGUAGE__CREATE
+ },
+ {
+ "drop", SEPG_DB_LANGUAGE__DROP
+ },
+ {
+ "getattr", SEPG_DB_LANGUAGE__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_LANGUAGE__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_LANGUAGE__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_LANGUAGE__RELABELTO
+ },
+ {
+ "implement", SEPG_DB_LANGUAGE__IMPLEMENT
+ },
+ {
+ "execute", SEPG_DB_LANGUAGE__EXECUTE
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+ {
+ "db_view", SEPG_CLASS_DB_VIEW,
+ {
+ {
+ "create", SEPG_DB_VIEW__CREATE
+ },
+ {
+ "drop", SEPG_DB_VIEW__DROP
+ },
+ {
+ "getattr", SEPG_DB_VIEW__GETATTR
+ },
+ {
+ "setattr", SEPG_DB_VIEW__SETATTR
+ },
+ {
+ "relabelfrom", SEPG_DB_VIEW__RELABELFROM
+ },
+ {
+ "relabelto", SEPG_DB_VIEW__RELABELTO
+ },
+ {
+ "expand", SEPG_DB_VIEW__EXPAND
+ },
+ {
+ NULL, 0UL
+ },
+ }
+ },
+};
+
+/*
+ * sepgsql_mode
+ *
+ * SEPGSQL_MODE_DISABLED: Disabled on runtime
+ * SEPGSQL_MODE_DEFAULT: Same as system settings
+ * SEPGSQL_MODE_PERMISSIVE: Always permissive mode
+ * SEPGSQL_MODE_INTERNAL: Same as permissive, except for no audit logs
+ */
+static int sepgsql_mode = SEPGSQL_MODE_INTERNAL;
+
+/*
+ * sepgsql_is_enabled
+ */
+bool
+sepgsql_is_enabled(void)
+{
+ return (sepgsql_mode != SEPGSQL_MODE_DISABLED ? true : false);
+}
+
+/*
+ * sepgsql_get_mode
+ */
+int
+sepgsql_get_mode(void)
+{
+ return sepgsql_mode;
+}
+
+/*
+ * sepgsql_set_mode
+ */
+int
+sepgsql_set_mode(int new_mode)
+{
+ int old_mode = sepgsql_mode;
+
+ sepgsql_mode = new_mode;
+
+ return old_mode;
+}
+
+/*
+ * sepgsql_getenforce
+ *
+ * It returns whether the current working mode tries to enforce access
+ * control decision, or not. It shall be enforced when sepgsql_mode is
+ * SEPGSQL_MODE_DEFAULT and system is running in enforcing mode.
+ */
+bool
+sepgsql_getenforce(void)
+{
+ if (sepgsql_mode == SEPGSQL_MODE_DEFAULT &&
+ selinux_status_getenforce() > 0)
+ return true;
+
+ return false;
+}
+
+/*
+ * sepgsql_audit_log
+ *
+ * It generates a security audit record. It writes out audit records
+ * into standard PG's logfile.
+ *
+ * SELinux can control what should be audited and should not using
+ * "auditdeny" and "auditallow" rules in the security policy. In the
+ * default, all the access violations are audited, and all the access
+ * allowed are not audited. But we can set up the security policy, so
+ * we can have exceptions. So, it is necessary to follow the suggestion
+ * come from the security policy. (av_decision.auditallow and auditdeny)
+ *
+ * Security audit is an important feature, because it enables us to check
+ * what was happen if we have a security incident. In fact, ISO/IEC15408
+ * defines several security functionalities for audit features.
+ */
+void
+sepgsql_audit_log(bool denied,
+ const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ uint32 audited,
+ const char *audit_name)
+{
+ StringInfoData buf;
+ const char *class_name;
+ const char *av_name;
+ int i;
+
+ /* lookup name of the object class */
+ Assert(tclass < SEPG_CLASS_MAX);
+ class_name = selinux_catalog[tclass].class_name;
+
+ /* lookup name of the permissions */
+ initStringInfo(&buf);
+ appendStringInfo(&buf, "%s {",
+ (denied ? "denied" : "allowed"));
+ for (i = 0; selinux_catalog[tclass].av[i].av_name; i++)
+ {
+ if (audited & (1UL << i))
+ {
+ av_name = selinux_catalog[tclass].av[i].av_name;
+ appendStringInfo(&buf, " %s", av_name);
+ }
+ }
+ appendStringInfoString(&buf, " }");
+
+ /*
+ * Call external audit module, if loaded
+ */
+ appendStringInfo(&buf, " scontext=%s tcontext=%s tclass=%s",
+ scontext, tcontext, class_name);
+ if (audit_name)
+ appendStringInfo(&buf, " name=\"%s\"", audit_name);
+
+ ereport(LOG, (errmsg("SELinux: %s", buf.data)));
+}
+
+/*
+ * sepgsql_compute_avd
+ *
+ * It actually asks SELinux what permissions are allowed on a pair of
+ * the security contexts and object class. It also returns what permissions
+ * should be audited on access violation or allowed.
+ * In most cases, subject's security context (scontext) is a client, and
+ * target security context (tcontext) is a database object.
+ *
+ * The access control decision shall be set on the given av_decision.
+ * The av_decision.allowed has a bitmask of SEPG_<class>__<perms>
+ * to suggest a set of allowed actions in this object class.
+ */
+void
+sepgsql_compute_avd(const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ struct av_decision *avd)
+{
+ const char *tclass_name;
+ security_class_t tclass_ex;
+ struct av_decision avd_ex;
+ int i,
+ deny_unknown = security_deny_unknown();
+
+ /* Get external code of the object class */
+ Assert(tclass < SEPG_CLASS_MAX);
+ Assert(tclass == selinux_catalog[tclass].class_code);
+
+ tclass_name = selinux_catalog[tclass].class_name;
+ tclass_ex = string_to_security_class(tclass_name);
+
+ if (tclass_ex == 0)
+ {
+ /*
+ * If the current security policy does not support permissions
+ * corresponding to database objects, we fill up them with dummy data.
+ * If security_deny_unknown() returns positive value, undefined
+ * permissions should be denied. Otherwise, allowed
+ */
+ avd->allowed = (security_deny_unknown() > 0 ? 0 : ~0);
+ avd->auditallow = 0U;
+ avd->auditdeny = ~0U;
+ avd->flags = 0;
+
+ return;
+ }
+
+ /*
+ * Ask SELinux what is allowed set of permissions on a pair of the
+ * security contexts and the given object class.
+ */
+ if (security_compute_av_flags_raw((security_context_t) scontext,
+ (security_context_t) tcontext,
+ tclass_ex, 0, &avd_ex) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux could not compute av_decision: "
+ "scontext=%s tcontext=%s tclass=%s: %m",
+ scontext, tcontext, tclass_name)));
+
+ /*
+ * SELinux returns its access control decision as a set of permissions
+ * represented in external code which depends on run-time environment. So,
+ * we need to translate it to the internal representation before returning
+ * results for the caller.
+ */
+ memset(avd, 0, sizeof(struct av_decision));
+
+ for (i = 0; selinux_catalog[tclass].av[i].av_name; i++)
+ {
+ access_vector_t av_code_ex;
+ const char *av_name = selinux_catalog[tclass].av[i].av_name;
+ uint32 av_code = selinux_catalog[tclass].av[i].av_code;
+
+ av_code_ex = string_to_av_perm(tclass_ex, av_name);
+ if (av_code_ex == 0)
+ {
+ /* fill up undefined permissions */
+ if (!deny_unknown)
+ avd->allowed |= av_code;
+ avd->auditdeny |= av_code;
+
+ continue;
+ }
+
+ if (avd_ex.allowed & av_code_ex)
+ avd->allowed |= av_code;
+ if (avd_ex.auditallow & av_code_ex)
+ avd->auditallow |= av_code;
+ if (avd_ex.auditdeny & av_code_ex)
+ avd->auditdeny |= av_code;
+ }
+}
+
+/*
+ * sepgsql_compute_create
+ *
+ * It returns a default security context to be assigned on a new database
+ * object. SELinux compute it based on a combination of client, upper object
+ * which owns the new object and object class.
+ *
+ * For example, when a client (staff_u:staff_r:staff_t:s0) tries to create
+ * a new table within a schema (system_u:object_r:sepgsql_schema_t:s0),
+ * SELinux looks-up its security policy. If it has a special rule on the
+ * combination of these security contexts and object class (db_table),
+ * it returns the security context suggested by the special rule.
+ * Otherwise, it returns the security context of schema, as is.
+ *
+ * We expect the caller already applies sanity/validation checks on the
+ * given security context.
+ *
+ * scontext: security context of the subject (mostly, peer process).
+ * tcontext: security context of the upper database object.
+ * tclass: class code (SEPG_CLASS_*) of the new object in creation
+ */
+char *
+sepgsql_compute_create(const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ const char *objname)
+{
+ security_context_t ncontext;
+ security_class_t tclass_ex;
+ const char *tclass_name;
+ char *result;
+
+ /* Get external code of the object class */
+ Assert(tclass < SEPG_CLASS_MAX);
+
+ tclass_name = selinux_catalog[tclass].class_name;
+ tclass_ex = string_to_security_class(tclass_name);
+
+ /*
+ * Ask SELinux what is the default context for the given object class on a
+ * pair of security contexts
+ */
+ if (security_compute_create_name_raw((security_context_t) scontext,
+ (security_context_t) tcontext,
+ tclass_ex,
+ objname,
+ &ncontext) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux could not compute a new context: "
+ "scontext=%s tcontext=%s tclass=%s: %m",
+ scontext, tcontext, tclass_name)));
+
+ /*
+ * libselinux returns malloc()'ed string, so we need to copy it on the
+ * palloc()'ed region.
+ */
+ PG_TRY();
+ {
+ result = pstrdup(ncontext);
+ }
+ PG_FINALLY();
+ {
+ freecon(ncontext);
+ }
+ PG_END_TRY();
+
+ return result;
+}
+
+/*
+ * sepgsql_check_perms
+ *
+ * It makes access control decision without userspace caching mechanism.
+ * If SELinux denied the required accesses on the pair of security labels,
+ * it raises an error or returns false.
+ *
+ * scontext: security label of the subject (mostly, peer process)
+ * tcontext: security label of the object being referenced
+ * tclass: class code (SEPG_CLASS_*) of the object being referenced
+ * required: a mask of required permissions (SEPG_<class>__<perm>)
+ * audit_name: a human readable object name for audit logs, or NULL.
+ * abort_on_violation: true, if error shall be raised on access violation
+ */
+bool
+sepgsql_check_perms(const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ uint32 required,
+ const char *audit_name,
+ bool abort_on_violation)
+{
+ struct av_decision avd;
+ uint32 denied;
+ uint32 audited;
+ bool result = true;
+
+ sepgsql_compute_avd(scontext, tcontext, tclass, &avd);
+
+ denied = required & ~avd.allowed;
+
+ if (sepgsql_get_debug_audit())
+ audited = (denied ? denied : required);
+ else
+ audited = (denied ? (denied & avd.auditdeny)
+ : (required & avd.auditallow));
+
+ if (denied &&
+ sepgsql_getenforce() > 0 &&
+ (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) == 0)
+ result = false;
+
+ /*
+ * It records a security audit for the request, if needed. But, when
+ * SE-PgSQL performs 'internal' mode, it needs to keep silent.
+ */
+ if (audited && sepgsql_mode != SEPGSQL_MODE_INTERNAL)
+ {
+ sepgsql_audit_log(denied,
+ scontext,
+ tcontext,
+ tclass,
+ audited,
+ audit_name);
+ }
+
+ if (!result && abort_on_violation)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: security policy violation")));
+ return result;
+}
diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te
new file mode 100644
index 0000000..569c4da
--- /dev/null
+++ b/contrib/sepgsql/sepgsql-regtest.te
@@ -0,0 +1,261 @@
+policy_module(sepgsql-regtest, 1.08)
+
+gen_require(`
+ all_userspace_class_perms
+')
+
+## <desc>
+## <p>
+## Allow to launch regression test of SE-PostgreSQL
+## Don't switch to TRUE in normal cases
+## </p>
+## </desc>
+gen_tunable(sepgsql_regression_test_mode, false)
+
+#
+# Type definitions for regression test
+#
+type sepgsql_regtest_trusted_proc_exec_t;
+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 self defined unconfined / superuser
+#
+role sepgsql_regtest_superuser_r;
+userdom_base_user_template(sepgsql_regtest_superuser)
+userdom_manage_home_role(sepgsql_regtest_superuser_r, sepgsql_regtest_superuser_t)
+userdom_exec_user_home_content_files(sepgsql_regtest_superuser_t)
+userdom_write_user_tmp_sockets(sepgsql_regtest_superuser_t)
+
+auth_read_passwd(sepgsql_regtest_superuser_t)
+
+optional_policy(`
+ postgresql_stream_connect(sepgsql_regtest_superuser_t)
+ postgresql_unconfined(sepgsql_regtest_superuser_t)
+')
+optional_policy(`
+ unconfined_stream_connect(sepgsql_regtest_superuser_t)
+ unconfined_rw_pipes(sepgsql_regtest_superuser_t)
+')
+optional_policy(`
+ gen_require(`
+ attribute sepgsql_client_type;
+ ')
+ allow sepgsql_regtest_superuser_t self : process { setcurrent };
+ allow sepgsql_regtest_superuser_t { self sepgsql_client_type } : process { dyntransition };
+')
+
+# Type transition rules
+allow sepgsql_regtest_user_t sepgsql_regtest_dba_t : process { transition };
+type_transition sepgsql_regtest_user_t sepgsql_regtest_trusted_proc_exec_t:process sepgsql_regtest_dba_t;
+type_transition sepgsql_regtest_user_t sepgsql_nosuch_trusted_proc_exec_t:process sepgsql_regtest_nosuch_t;
+
+#
+# Test domains for database administrators
+#
+role sepgsql_regtest_dba_r;
+userdom_base_user_template(sepgsql_regtest_dba)
+userdom_manage_home_role(sepgsql_regtest_dba_r, sepgsql_regtest_dba_t)
+userdom_exec_user_home_content_files(sepgsql_regtest_dba_t)
+userdom_write_user_tmp_sockets(sepgsql_regtest_user_t)
+
+auth_read_passwd(sepgsql_regtest_dba_t)
+
+optional_policy(`
+ postgresql_admin(sepgsql_regtest_dba_t, sepgsql_regtest_dba_r)
+ postgresql_stream_connect(sepgsql_regtest_dba_t)
+')
+optional_policy(`
+ unconfined_stream_connect(sepgsql_regtest_dba_t)
+ unconfined_rw_pipes(sepgsql_regtest_dba_t)
+')
+
+# Type transition rules
+allow sepgsql_regtest_dba_t self : process { setcurrent };
+allow sepgsql_regtest_dba_t sepgsql_regtest_user_t : process { dyntransition };
+allow sepgsql_regtest_dba_t sepgsql_regtest_foo_t : process { dyntransition };
+allow sepgsql_regtest_dba_t sepgsql_regtest_var_t : process { dyntransition };
+
+# special rule for system columns
+optional_policy(`
+ gen_require(`
+ attribute sepgsql_table_type;
+ type sepgsql_sysobj_t;
+ ')
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "ctid";
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "oid";
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "xmin";
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "xmax";
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "cmin";
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "cmax";
+ type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "tableoid";
+')
+
+#
+# Dummy domain for unpriv users
+#
+role sepgsql_regtest_user_r;
+userdom_base_user_template(sepgsql_regtest_user)
+userdom_manage_home_role(sepgsql_regtest_user_r, sepgsql_regtest_user_t)
+userdom_exec_user_home_content_files(sepgsql_regtest_user_t)
+userdom_write_user_tmp_sockets(sepgsql_regtest_user_t)
+
+auth_read_passwd(sepgsql_regtest_user_t)
+
+optional_policy(`
+ postgresql_role(sepgsql_regtest_user_r, sepgsql_regtest_user_t)
+ postgresql_stream_connect(sepgsql_regtest_user_t)
+')
+optional_policy(`
+ unconfined_stream_connect(sepgsql_regtest_user_t)
+ unconfined_rw_pipes(sepgsql_regtest_user_t)
+')
+# Type transition rules
+allow sepgsql_regtest_user_t sepgsql_regtest_dba_t : process { transition };
+type_transition sepgsql_regtest_user_t sepgsql_regtest_trusted_proc_exec_t:process sepgsql_regtest_dba_t;
+type_transition sepgsql_regtest_user_t sepgsql_nosuch_trusted_proc_exec_t:process sepgsql_regtest_nosuch_t;
+
+#
+# Dummy domain for (virtual) connection pooler software
+#
+# XXX - this test scenario assumes sepgsql_regtest_pool_t domain performs
+# as a typical connection pool server; that switches the client label of
+# this session prior to any user queries. The sepgsql_regtest_(foo|var)_t
+# is allowed to access its own table types, but not allowed to reference
+# other's one.
+#
+role sepgsql_regtest_pool_r;
+userdom_base_user_template(sepgsql_regtest_pool)
+userdom_manage_home_role(sepgsql_regtest_pool_r, sepgsql_regtest_pool_t)
+userdom_exec_user_home_content_files(sepgsql_regtest_pool_t)
+userdom_write_user_tmp_sockets(sepgsql_regtest_pool_t)
+
+auth_read_passwd(sepgsql_regtest_pool_t)
+
+type sepgsql_regtest_foo_t;
+type sepgsql_regtest_var_t;
+type sepgsql_regtest_foo_table_t;
+type sepgsql_regtest_var_table_t;
+
+allow sepgsql_regtest_foo_t sepgsql_regtest_foo_table_t:db_table { getattr select update insert delete lock };
+allow sepgsql_regtest_foo_t sepgsql_regtest_foo_table_t:db_column { getattr select update insert };
+allow sepgsql_regtest_foo_t sepgsql_regtest_foo_table_t:db_tuple { select update insert delete };
+
+allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_table { getattr select update insert delete lock };
+allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_column { getattr select update insert };
+allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_tuple { select update insert delete };
+
+optional_policy(`
+ gen_require(`
+ class db_table { truncate };
+ ')
+
+ allow sepgsql_regtest_superuser_t sepgsql_regtest_foo_table_t:db_table { truncate };
+')
+
+optional_policy(`
+ gen_require(`
+ role unconfined_r;
+ ')
+ postgresql_role(unconfined_r, sepgsql_regtest_foo_t)
+ postgresql_role(unconfined_r, sepgsql_regtest_var_t)
+ postgresql_table_object(sepgsql_regtest_foo_table_t)
+ postgresql_table_object(sepgsql_regtest_var_table_t)
+')
+optional_policy(`
+ postgresql_stream_connect(sepgsql_regtest_pool_t)
+ postgresql_role(sepgsql_regtest_pool_r, sepgsql_regtest_pool_t)
+')
+optional_policy(`
+ unconfined_stream_connect(sepgsql_regtest_pool_t)
+ unconfined_rw_pipes(sepgsql_regtest_pool_t)
+')
+# type transitions
+allow sepgsql_regtest_pool_t self:process { setcurrent };
+allow sepgsql_regtest_pool_t sepgsql_regtest_dba_t:process { transition };
+type_transition sepgsql_regtest_pool_t sepgsql_regtest_trusted_proc_exec_t:process sepgsql_regtest_dba_t;
+
+allow { sepgsql_regtest_foo_t sepgsql_regtest_var_t } self:process { setcurrent };
+allow { sepgsql_regtest_foo_t sepgsql_regtest_var_t } sepgsql_regtest_pool_t:process { dyntransition };
+
+#
+# Dummy domain for non-exist users
+#
+role sepgsql_regtest_nosuch_r;
+userdom_base_user_template(sepgsql_regtest_nosuch)
+optional_policy(`
+ postgresql_role(sepgsql_regtest_nosuch_r, sepgsql_regtest_nosuch_t)
+')
+
+#
+# Rules to launch psql in the dummy domains
+#
+optional_policy(`
+ gen_require(`
+ role unconfined_r;
+ type unconfined_t;
+ type sepgsql_trusted_proc_t;
+ ')
+ tunable_policy(`sepgsql_regression_test_mode',`
+ allow unconfined_t self : process { setcurrent dyntransition };
+ allow unconfined_t sepgsql_regtest_dba_t : process { transition dyntransition };
+ allow unconfined_t sepgsql_regtest_superuser_t : process { transition dyntransition };
+ allow unconfined_t sepgsql_regtest_user_t : process { transition dyntransition };
+ allow unconfined_t sepgsql_regtest_pool_t : process { transition dyntransition };
+ ')
+ role unconfined_r types sepgsql_regtest_dba_t;
+ role unconfined_r types sepgsql_regtest_superuser_t;
+ role unconfined_r types sepgsql_regtest_user_t;
+ role unconfined_r types sepgsql_regtest_nosuch_t;
+ role unconfined_r types sepgsql_trusted_proc_t;
+
+ role unconfined_r types sepgsql_regtest_pool_t;
+ role unconfined_r types sepgsql_regtest_foo_t;
+ role unconfined_r types sepgsql_regtest_var_t;
+')
+
+#
+# Rule to make MCS policy work on regression test
+#
+# NOTE: MCS (multi category security) policy was enabled by default, to
+# allow DAC style access control, in the previous selinux policy.
+# However, its definition was changed later, then a limited number of
+# applications are restricted by MCS policy, for container features
+# mainly. The rules below enables MCS policy for domains of regression
+# test also, even if base security policy does not apply. If base policy
+# is old and MCS is enabled in default, rules below does nothing.
+#
+optional_policy(`
+ gen_require(`
+ type sepgsql_trusted_proc_t;
+ ')
+ mcs_constrained(sepgsql_regtest_dba_t)
+ mcs_constrained(sepgsql_regtest_superuser_t)
+ mcs_constrained(sepgsql_regtest_user_t)
+ mcs_constrained(sepgsql_regtest_nosuch_t)
+ mcs_constrained(sepgsql_trusted_proc_t)
+
+ mcs_constrained(sepgsql_regtest_pool_t)
+ mcs_constrained(sepgsql_regtest_foo_t)
+ mcs_constrained(sepgsql_regtest_var_t)
+')
+
+#
+# Rule to execute original trusted procedures
+#
+# 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 entrypoint };
+')
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
new file mode 100644
index 0000000..38302b5
--- /dev/null
+++ b/contrib/sepgsql/sepgsql.h
@@ -0,0 +1,329 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/sepgsql.h
+ *
+ * Definitions corresponding to SE-PostgreSQL
+ *
+ * Copyright (c) 2010-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#ifndef SEPGSQL_H
+#define SEPGSQL_H
+
+#include "catalog/objectaddress.h"
+#include "fmgr.h"
+
+#include <selinux/selinux.h>
+#include <selinux/avc.h>
+
+/*
+ * SE-PostgreSQL Label Tag
+ */
+#define SEPGSQL_LABEL_TAG "selinux"
+
+/*
+ * SE-PostgreSQL performing mode
+ */
+#define SEPGSQL_MODE_DEFAULT 1
+#define SEPGSQL_MODE_PERMISSIVE 2
+#define SEPGSQL_MODE_INTERNAL 3
+#define SEPGSQL_MODE_DISABLED 4
+
+/*
+ * Internally used code of object classes
+ */
+#define SEPG_CLASS_PROCESS 0
+#define SEPG_CLASS_FILE 1
+#define SEPG_CLASS_DIR 2
+#define SEPG_CLASS_LNK_FILE 3
+#define SEPG_CLASS_CHR_FILE 4
+#define SEPG_CLASS_BLK_FILE 5
+#define SEPG_CLASS_SOCK_FILE 6
+#define SEPG_CLASS_FIFO_FILE 7
+#define SEPG_CLASS_DB_DATABASE 8
+#define SEPG_CLASS_DB_SCHEMA 9
+#define SEPG_CLASS_DB_TABLE 10
+#define SEPG_CLASS_DB_SEQUENCE 11
+#define SEPG_CLASS_DB_PROCEDURE 12
+#define SEPG_CLASS_DB_COLUMN 13
+#define SEPG_CLASS_DB_TUPLE 14
+#define SEPG_CLASS_DB_BLOB 15
+#define SEPG_CLASS_DB_LANGUAGE 16
+#define SEPG_CLASS_DB_VIEW 17
+#define SEPG_CLASS_MAX 18
+
+/*
+ * Internally used code of access vectors
+ */
+#define SEPG_PROCESS__TRANSITION (1<<0)
+#define SEPG_PROCESS__DYNTRANSITION (1<<1)
+#define SEPG_PROCESS__SETCURRENT (1<<2)
+
+#define SEPG_FILE__READ (1<<0)
+#define SEPG_FILE__WRITE (1<<1)
+#define SEPG_FILE__CREATE (1<<2)
+#define SEPG_FILE__GETATTR (1<<3)
+#define SEPG_FILE__UNLINK (1<<4)
+#define SEPG_FILE__RENAME (1<<5)
+#define SEPG_FILE__APPEND (1<<6)
+
+#define SEPG_DIR__READ (SEPG_FILE__READ)
+#define SEPG_DIR__WRITE (SEPG_FILE__WRITE)
+#define SEPG_DIR__CREATE (SEPG_FILE__CREATE)
+#define SEPG_DIR__GETATTR (SEPG_FILE__GETATTR)
+#define SEPG_DIR__UNLINK (SEPG_FILE__UNLINK)
+#define SEPG_DIR__RENAME (SEPG_FILE__RENAME)
+#define SEPG_DIR__SEARCH (1<<6)
+#define SEPG_DIR__ADD_NAME (1<<7)
+#define SEPG_DIR__REMOVE_NAME (1<<8)
+#define SEPG_DIR__RMDIR (1<<9)
+#define SEPG_DIR__REPARENT (1<<10)
+
+#define SEPG_LNK_FILE__READ (SEPG_FILE__READ)
+#define SEPG_LNK_FILE__WRITE (SEPG_FILE__WRITE)
+#define SEPG_LNK_FILE__CREATE (SEPG_FILE__CREATE)
+#define SEPG_LNK_FILE__GETATTR (SEPG_FILE__GETATTR)
+#define SEPG_LNK_FILE__UNLINK (SEPG_FILE__UNLINK)
+#define SEPG_LNK_FILE__RENAME (SEPG_FILE__RENAME)
+
+#define SEPG_CHR_FILE__READ (SEPG_FILE__READ)
+#define SEPG_CHR_FILE__WRITE (SEPG_FILE__WRITE)
+#define SEPG_CHR_FILE__CREATE (SEPG_FILE__CREATE)
+#define SEPG_CHR_FILE__GETATTR (SEPG_FILE__GETATTR)
+#define SEPG_CHR_FILE__UNLINK (SEPG_FILE__UNLINK)
+#define SEPG_CHR_FILE__RENAME (SEPG_FILE__RENAME)
+
+#define SEPG_BLK_FILE__READ (SEPG_FILE__READ)
+#define SEPG_BLK_FILE__WRITE (SEPG_FILE__WRITE)
+#define SEPG_BLK_FILE__CREATE (SEPG_FILE__CREATE)
+#define SEPG_BLK_FILE__GETATTR (SEPG_FILE__GETATTR)
+#define SEPG_BLK_FILE__UNLINK (SEPG_FILE__UNLINK)
+#define SEPG_BLK_FILE__RENAME (SEPG_FILE__RENAME)
+
+#define SEPG_SOCK_FILE__READ (SEPG_FILE__READ)
+#define SEPG_SOCK_FILE__WRITE (SEPG_FILE__WRITE)
+#define SEPG_SOCK_FILE__CREATE (SEPG_FILE__CREATE)
+#define SEPG_SOCK_FILE__GETATTR (SEPG_FILE__GETATTR)
+#define SEPG_SOCK_FILE__UNLINK (SEPG_FILE__UNLINK)
+#define SEPG_SOCK_FILE__RENAME (SEPG_FILE__RENAME)
+
+#define SEPG_FIFO_FILE__READ (SEPG_FILE__READ)
+#define SEPG_FIFO_FILE__WRITE (SEPG_FILE__WRITE)
+#define SEPG_FIFO_FILE__CREATE (SEPG_FILE__CREATE)
+#define SEPG_FIFO_FILE__GETATTR (SEPG_FILE__GETATTR)
+#define SEPG_FIFO_FILE__UNLINK (SEPG_FILE__UNLINK)
+#define SEPG_FIFO_FILE__RENAME (SEPG_FILE__RENAME)
+
+#define SEPG_DB_DATABASE__CREATE (1<<0)
+#define SEPG_DB_DATABASE__DROP (1<<1)
+#define SEPG_DB_DATABASE__GETATTR (1<<2)
+#define SEPG_DB_DATABASE__SETATTR (1<<3)
+#define SEPG_DB_DATABASE__RELABELFROM (1<<4)
+#define SEPG_DB_DATABASE__RELABELTO (1<<5)
+#define SEPG_DB_DATABASE__ACCESS (1<<6)
+#define SEPG_DB_DATABASE__LOAD_MODULE (1<<7)
+
+#define SEPG_DB_SCHEMA__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_SCHEMA__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_SCHEMA__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_SCHEMA__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_SCHEMA__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_SCHEMA__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_SCHEMA__SEARCH (1<<6)
+#define SEPG_DB_SCHEMA__ADD_NAME (1<<7)
+#define SEPG_DB_SCHEMA__REMOVE_NAME (1<<8)
+
+#define SEPG_DB_TABLE__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_TABLE__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_TABLE__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_TABLE__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_TABLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_TABLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_TABLE__SELECT (1<<6)
+#define SEPG_DB_TABLE__UPDATE (1<<7)
+#define SEPG_DB_TABLE__INSERT (1<<8)
+#define SEPG_DB_TABLE__DELETE (1<<9)
+#define SEPG_DB_TABLE__LOCK (1<<10)
+#define SEPG_DB_TABLE__TRUNCATE (1<<11)
+
+#define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_SEQUENCE__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_SEQUENCE__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_SEQUENCE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_SEQUENCE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_SEQUENCE__GET_VALUE (1<<6)
+#define SEPG_DB_SEQUENCE__NEXT_VALUE (1<<7)
+#define SEPG_DB_SEQUENCE__SET_VALUE (1<<8)
+
+#define SEPG_DB_PROCEDURE__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_PROCEDURE__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_PROCEDURE__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_PROCEDURE__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_PROCEDURE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_PROCEDURE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_PROCEDURE__EXECUTE (1<<6)
+#define SEPG_DB_PROCEDURE__ENTRYPOINT (1<<7)
+#define SEPG_DB_PROCEDURE__INSTALL (1<<8)
+
+#define SEPG_DB_COLUMN__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_COLUMN__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_COLUMN__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_COLUMN__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_COLUMN__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_COLUMN__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_COLUMN__SELECT (1<<6)
+#define SEPG_DB_COLUMN__UPDATE (1<<7)
+#define SEPG_DB_COLUMN__INSERT (1<<8)
+
+#define SEPG_DB_TUPLE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_TUPLE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_TUPLE__SELECT (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_TUPLE__UPDATE (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_TUPLE__INSERT (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_TUPLE__DELETE (SEPG_DB_DATABASE__DROP)
+
+#define SEPG_DB_BLOB__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_BLOB__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_BLOB__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_BLOB__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_BLOB__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_BLOB__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_BLOB__READ (1<<6)
+#define SEPG_DB_BLOB__WRITE (1<<7)
+#define SEPG_DB_BLOB__IMPORT (1<<8)
+#define SEPG_DB_BLOB__EXPORT (1<<9)
+
+#define SEPG_DB_LANGUAGE__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_LANGUAGE__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_LANGUAGE__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_LANGUAGE__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_LANGUAGE__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_LANGUAGE__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_LANGUAGE__IMPLEMENT (1<<6)
+#define SEPG_DB_LANGUAGE__EXECUTE (1<<7)
+
+#define SEPG_DB_VIEW__CREATE (SEPG_DB_DATABASE__CREATE)
+#define SEPG_DB_VIEW__DROP (SEPG_DB_DATABASE__DROP)
+#define SEPG_DB_VIEW__GETATTR (SEPG_DB_DATABASE__GETATTR)
+#define SEPG_DB_VIEW__SETATTR (SEPG_DB_DATABASE__SETATTR)
+#define SEPG_DB_VIEW__RELABELFROM (SEPG_DB_DATABASE__RELABELFROM)
+#define SEPG_DB_VIEW__RELABELTO (SEPG_DB_DATABASE__RELABELTO)
+#define SEPG_DB_VIEW__EXPAND (1<<6)
+
+/*
+ * hooks.c
+ */
+extern bool sepgsql_get_permissive(void);
+extern bool sepgsql_get_debug_audit(void);
+
+/*
+ * selinux.c
+ */
+extern bool sepgsql_is_enabled(void);
+extern int sepgsql_get_mode(void);
+extern int sepgsql_set_mode(int new_mode);
+extern bool sepgsql_getenforce(void);
+
+extern void sepgsql_audit_log(bool denied,
+ const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ uint32 audited,
+ const char *audit_name);
+
+extern void sepgsql_compute_avd(const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ struct av_decision *avd);
+
+extern char *sepgsql_compute_create(const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ const char *objname);
+
+extern bool sepgsql_check_perms(const char *scontext,
+ const char *tcontext,
+ uint16 tclass,
+ uint32 required,
+ const char *audit_name,
+ bool abort_on_violation);
+
+/*
+ * uavc.c
+ */
+#define SEPGSQL_AVC_NOAUDIT ((void *)(-1))
+extern bool sepgsql_avc_check_perms_label(const char *tcontext,
+ uint16 tclass,
+ uint32 required,
+ const char *audit_name,
+ bool abort_on_violation);
+extern bool sepgsql_avc_check_perms(const ObjectAddress *tobject,
+ uint16 tclass,
+ uint32 required,
+ const char *audit_name,
+ bool abort_on_violation);
+extern char *sepgsql_avc_trusted_proc(Oid functionId);
+extern void sepgsql_avc_init(void);
+
+/*
+ * label.c
+ */
+extern char *sepgsql_get_client_label(void);
+extern void sepgsql_init_client_label(void);
+extern char *sepgsql_get_label(Oid classId, Oid objectId, int32 subId);
+
+extern void sepgsql_object_relabel(const ObjectAddress *object,
+ const char *seclabel);
+
+/*
+ * dml.c
+ */
+extern bool sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation);
+
+/*
+ * database.c
+ */
+extern void sepgsql_database_post_create(Oid databaseId,
+ const char *dtemplate);
+extern void sepgsql_database_drop(Oid databaseId);
+extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel);
+extern void sepgsql_database_setattr(Oid databaseId);
+
+/*
+ * schema.c
+ */
+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);
+
+/*
+ * relation.c
+ */
+extern void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum);
+extern void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum);
+extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
+ const char *seclabel);
+extern void sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum);
+extern void sepgsql_relation_post_create(Oid relOid);
+extern void sepgsql_relation_drop(Oid relOid);
+extern void sepgsql_relation_truncate(Oid relOid);
+extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
+extern void sepgsql_relation_setattr(Oid relOid);
+
+/*
+ * proc.c
+ */
+extern void sepgsql_proc_post_create(Oid functionId);
+extern void sepgsql_proc_drop(Oid functionId);
+extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
+extern void sepgsql_proc_setattr(Oid functionId);
+extern void sepgsql_proc_execute(Oid functionId);
+
+#endif /* SEPGSQL_H */
diff --git a/contrib/sepgsql/sepgsql.sql.in b/contrib/sepgsql/sepgsql.sql.in
new file mode 100644
index 0000000..917d12d
--- /dev/null
+++ b/contrib/sepgsql/sepgsql.sql.in
@@ -0,0 +1,37 @@
+--
+-- contrib/sepgsql/sepgsql.sql
+--
+-- [Step to install]
+--
+-- 1. Run initdb
+-- to set up a new database cluster.
+--
+-- 2. Edit $PGDATA/postgresql.conf
+-- to add 'MODULE_PATHNAME' to shared_preload_libraries.
+--
+-- Example)
+-- shared_preload_libraries = 'MODULE_PATHNAME'
+--
+-- 3. Run this script for each databases
+-- This script installs corresponding functions, and assigns initial
+-- security labels on target database objects.
+-- It can be run both single-user mode and multi-user mode, according
+-- to your preference.
+--
+-- Example)
+-- $ for DBNAME in template0 template1 postgres; \
+-- do \
+-- postgres --single -F -c exit_on_error=true -D $PGDATA $DBNAME \
+-- < /path/to/script/sepgsql.sql > /dev/null \
+-- done
+--
+-- 4. Start postmaster,
+-- if you initialized the database in single-user mode.
+--
+LOAD 'MODULE_PATHNAME';
+CREATE OR REPLACE FUNCTION pg_catalog.sepgsql_getcon() RETURNS text AS 'MODULE_PATHNAME', 'sepgsql_getcon' LANGUAGE C;
+CREATE OR REPLACE FUNCTION pg_catalog.sepgsql_setcon(text) RETURNS bool AS 'MODULE_PATHNAME', 'sepgsql_setcon' LANGUAGE C;
+CREATE OR REPLACE FUNCTION pg_catalog.sepgsql_mcstrans_in(text) RETURNS text AS 'MODULE_PATHNAME', 'sepgsql_mcstrans_in' LANGUAGE C STRICT;
+CREATE OR REPLACE FUNCTION pg_catalog.sepgsql_mcstrans_out(text) RETURNS text AS 'MODULE_PATHNAME', 'sepgsql_mcstrans_out' LANGUAGE C STRICT;
+CREATE OR REPLACE FUNCTION pg_catalog.sepgsql_restorecon(text) RETURNS bool AS 'MODULE_PATHNAME', 'sepgsql_restorecon' LANGUAGE C;
+SELECT sepgsql_restorecon(NULL);
diff --git a/contrib/sepgsql/sql/alter.sql b/contrib/sepgsql/sql/alter.sql
new file mode 100644
index 0000000..f114449
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,197 @@
+--
+-- Test for various ALTER statements
+--
+
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS sepgsql_test_regression_1;
+DROP DATABASE IF EXISTS sepgsql_test_regression;
+DROP USER IF EXISTS regress_sepgsql_test_user;
+RESET client_min_messages;
+
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0
+
+--
+-- CREATE Objects to be altered (with debug_audit being silent)
+--
+CREATE DATABASE sepgsql_test_regression_1;
+
+CREATE USER regress_sepgsql_test_user;
+
+CREATE SCHEMA regtest_schema_1;
+CREATE SCHEMA regtest_schema_2;
+
+GRANT ALL ON SCHEMA regtest_schema_1 TO public;
+GRANT ALL ON SCHEMA regtest_schema_2 TO public;
+
+SET search_path = regtest_schema_1, regtest_schema_2, public;
+
+CREATE TABLE regtest_table_1 (a int, b text);
+
+CREATE TABLE regtest_table_2 (c text) inherits (regtest_table_1);
+
+CREATE TABLE regtest_table_3 (x int primary key, y text);
+
+---
+-- partitioned table parent
+CREATE TABLE regtest_ptable_1 (o int, p text) PARTITION BY RANGE (o);
+
+-- partitioned table children
+CREATE TABLE regtest_ptable_1_ones PARTITION OF regtest_ptable_1 FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE regtest_ptable_1_tens PARTITION OF regtest_ptable_1 FOR VALUES FROM ('10') TO ('100');
+---
+
+CREATE SEQUENCE regtest_seq_1;
+
+CREATE VIEW regtest_view_1 AS SELECT * FROM regtest_table_1 WHERE a > 0;
+
+CREATE FUNCTION regtest_func_1 (text) RETURNS bool
+ AS 'BEGIN RETURN true; END' LANGUAGE 'plpgsql';
+
+-- switch on debug_audit
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+
+--
+-- ALTER xxx OWNER TO
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+-- owner is not actually changed.
+--
+ALTER DATABASE sepgsql_test_regression_1 OWNER TO regress_sepgsql_test_user;
+ALTER DATABASE sepgsql_test_regression_1 OWNER TO regress_sepgsql_test_user;
+ALTER SCHEMA regtest_schema_1 OWNER TO regress_sepgsql_test_user;
+ALTER SCHEMA regtest_schema_1 OWNER TO regress_sepgsql_test_user;
+ALTER TABLE regtest_table_1 OWNER TO regress_sepgsql_test_user;
+ALTER TABLE regtest_table_1 OWNER TO regress_sepgsql_test_user;
+ALTER TABLE regtest_ptable_1 OWNER TO regress_sepgsql_test_user;
+ALTER TABLE regtest_ptable_1_ones OWNER TO regress_sepgsql_test_user;
+ALTER SEQUENCE regtest_seq_1 OWNER TO regress_sepgsql_test_user;
+ALTER SEQUENCE regtest_seq_1 OWNER TO regress_sepgsql_test_user;
+ALTER VIEW regtest_view_1 OWNER TO regress_sepgsql_test_user;
+ALTER VIEW regtest_view_1 OWNER TO regress_sepgsql_test_user;
+ALTER FUNCTION regtest_func_1(text) OWNER TO regress_sepgsql_test_user;
+ALTER FUNCTION regtest_func_1(text) OWNER TO regress_sepgsql_test_user;
+
+--
+-- ALTER xxx SET SCHEMA
+--
+ALTER TABLE regtest_table_1 SET SCHEMA regtest_schema_2;
+ALTER TABLE regtest_ptable_1 SET SCHEMA regtest_schema_2;
+ALTER TABLE regtest_ptable_1_ones SET SCHEMA regtest_schema_2;
+ALTER SEQUENCE regtest_seq_1 SET SCHEMA regtest_schema_2;
+ALTER VIEW regtest_view_1 SET SCHEMA regtest_schema_2;
+ALTER FUNCTION regtest_func_1(text) SET SCHEMA regtest_schema_2;
+
+--
+-- ALTER xxx RENAME TO
+--
+ALTER DATABASE sepgsql_test_regression_1 RENAME TO sepgsql_test_regression;
+ALTER SCHEMA regtest_schema_1 RENAME TO regtest_schema;
+ALTER TABLE regtest_table_1 RENAME TO regtest_table;
+
+---
+-- partitioned table parent
+ALTER TABLE regtest_ptable_1 RENAME TO regtest_ptable;
+-- partitioned table child
+ALTER TABLE regtest_ptable_1_ones RENAME TO regtest_table_part;
+---
+
+ALTER SEQUENCE regtest_seq_1 RENAME TO regtest_seq;
+ALTER VIEW regtest_view_1 RENAME TO regtest_view;
+ALTER FUNCTION regtest_func_1(text) RENAME TO regtest_func;
+
+SET search_path = regtest_schema, regtest_schema_2, public;
+
+--
+-- misc ALTER commands
+--
+ALTER DATABASE sepgsql_test_regression CONNECTION LIMIT 999;
+ALTER DATABASE sepgsql_test_regression SET search_path TO regtest_schema, public; -- not supported yet
+
+ALTER TABLE regtest_table ADD COLUMN d float;
+ALTER TABLE regtest_table DROP COLUMN d;
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'abcd'; -- not supported yet
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ'; -- not supported yet
+ALTER TABLE regtest_table ALTER b DROP DEFAULT; -- not supported yet
+ALTER TABLE regtest_table ALTER b SET NOT NULL;
+ALTER TABLE regtest_table ALTER b DROP NOT NULL;
+ALTER TABLE regtest_table ALTER b SET STATISTICS -1;
+ALTER TABLE regtest_table ALTER b SET (n_distinct = 999);
+ALTER TABLE regtest_table ALTER b SET STORAGE PLAIN;
+ALTER TABLE regtest_table ADD CONSTRAINT test_fk FOREIGN KEY (a) REFERENCES regtest_table_3(x); -- not supported
+ALTER TABLE regtest_table ADD CONSTRAINT test_ck CHECK (b like '%abc%') NOT VALID; -- not supported
+ALTER TABLE regtest_table VALIDATE CONSTRAINT test_ck; -- not supported
+ALTER TABLE regtest_table DROP CONSTRAINT test_ck; -- not supported
+
+CREATE TRIGGER regtest_test_trig BEFORE UPDATE ON regtest_table
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+ALTER TABLE regtest_table DISABLE TRIGGER regtest_test_trig; -- not supported
+ALTER TABLE regtest_table ENABLE TRIGGER regtest_test_trig; -- not supported
+
+CREATE RULE regtest_test_rule AS ON INSERT TO regtest_table_3 DO ALSO NOTHING;
+ALTER TABLE regtest_table_3 DISABLE RULE regtest_test_rule; -- not supported
+ALTER TABLE regtest_table_3 ENABLE RULE regtest_test_rule; -- not supported
+
+ALTER TABLE regtest_table SET (fillfactor = 75);
+ALTER TABLE regtest_table RESET (fillfactor);
+ALTER TABLE regtest_table_2 NO INHERIT regtest_table; -- not supported
+ALTER TABLE regtest_table_2 INHERIT regtest_table; -- not supported
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+
+---
+-- partitioned table parent
+ALTER TABLE regtest_ptable ADD COLUMN d float;
+ALTER TABLE regtest_ptable DROP COLUMN d;
+ALTER TABLE regtest_ptable ALTER p SET DEFAULT 'abcd'; -- not supported by sepgsql
+ALTER TABLE regtest_ptable ALTER p SET DEFAULT 'XYZ'; -- not supported by sepgsql
+ALTER TABLE regtest_ptable ALTER p DROP DEFAULT; -- not supported by sepgsql
+ALTER TABLE regtest_ptable ALTER p SET NOT NULL;
+ALTER TABLE regtest_ptable ALTER p DROP NOT NULL;
+ALTER TABLE regtest_ptable ALTER p SET STATISTICS -1;
+ALTER TABLE regtest_ptable ALTER p SET (n_distinct = 999);
+ALTER TABLE regtest_ptable ALTER p SET STORAGE PLAIN;
+ALTER TABLE regtest_ptable ADD CONSTRAINT test_ck CHECK (p like '%abc%') NOT VALID; -- not supported by sepgsql
+ALTER TABLE regtest_ptable DROP CONSTRAINT test_ck; -- not supported by sepgsql
+
+ALTER TABLE regtest_ptable SET TABLESPACE pg_default;
+
+-- partitioned table child
+ALTER TABLE regtest_table_part ALTER p SET DEFAULT 'abcd'; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ALTER p SET DEFAULT 'XYZ'; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ALTER p DROP DEFAULT; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ALTER p SET NOT NULL;
+ALTER TABLE regtest_table_part ALTER p DROP NOT NULL;
+ALTER TABLE regtest_table_part ALTER p SET STATISTICS -1;
+ALTER TABLE regtest_table_part ALTER p SET (n_distinct = 999);
+ALTER TABLE regtest_table_part ALTER p SET STORAGE PLAIN;
+ALTER TABLE regtest_table_part ADD CONSTRAINT test_ck CHECK (p like '%abc%') NOT VALID; -- not supported by sepgsql
+ALTER TABLE regtest_table_part VALIDATE CONSTRAINT test_ck; -- not supported by sepgsql
+ALTER TABLE regtest_table_part DROP CONSTRAINT test_ck; -- not supported by sepgsql
+
+CREATE TRIGGER regtest_part_test_trig BEFORE UPDATE ON regtest_table_part
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+ALTER TABLE regtest_table_part DISABLE TRIGGER regtest_part_test_trig; -- not supported by sepgsql
+ALTER TABLE regtest_table_part ENABLE TRIGGER regtest_part_test_trig; -- not supported by sepgsql
+
+ALTER TABLE regtest_table_part SET (fillfactor = 75);
+ALTER TABLE regtest_table_part RESET (fillfactor);
+
+ALTER TABLE regtest_table_part SET TABLESPACE pg_default;
+---
+
+ALTER VIEW regtest_view SET (security_barrier);
+
+ALTER SEQUENCE regtest_seq INCREMENT BY 10 START WITH 1000;
+
+--
+-- clean-up objects
+--
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+DROP DATABASE sepgsql_test_regression;
+DROP SCHEMA regtest_schema CASCADE;
+DROP SCHEMA regtest_schema_2 CASCADE;
+DROP USER regress_sepgsql_test_user;
diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql
new file mode 100644
index 0000000..3deadb6
--- /dev/null
+++ b/contrib/sepgsql/sql/ddl.sql
@@ -0,0 +1,125 @@
+--
+-- Regression Test for DDL of Object Permission Checks
+--
+
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS sepgsql_test_regression;
+DROP USER IF EXISTS regress_sepgsql_test_user;
+RESET client_min_messages;
+
+-- confirm required permissions using audit messages
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+
+--
+-- CREATE Permission checks
+--
+CREATE DATABASE sepgsql_test_regression;
+
+CREATE USER regress_sepgsql_test_user;
+
+CREATE SCHEMA regtest_schema;
+
+GRANT ALL ON SCHEMA regtest_schema TO regress_sepgsql_test_user;
+
+SET search_path = regtest_schema, public;
+
+CREATE TABLE regtest_table (x serial primary key, y text);
+
+ALTER TABLE regtest_table ADD COLUMN z int;
+
+CREATE TABLE regtest_table_2 (a int);
+
+CREATE TABLE regtest_ptable (a int) PARTITION BY RANGE (a);
+CREATE TABLE regtest_ptable_ones PARTITION OF regtest_ptable FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE regtest_ptable_tens PARTITION OF regtest_ptable FOR VALUES FROM ('10') TO ('100');
+
+ALTER TABLE regtest_ptable ADD COLUMN q int;
+
+-- corresponding toast table should not have label and permission checks
+ALTER TABLE regtest_table_2 ADD COLUMN b text;
+
+-- VACUUM FULL internally create a new table and swap them later.
+VACUUM FULL regtest_table;
+VACUUM FULL regtest_ptable;
+
+CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
+CREATE VIEW regtest_pview AS SELECT * FROM regtest_ptable WHERE a < 99;
+
+CREATE SEQUENCE regtest_seq;
+
+CREATE TYPE regtest_comptype AS (a int, b text);
+
+CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
+ AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
+
+CREATE AGGREGATE regtest_agg (
+ sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0'
+);
+
+-- CREATE objects owned by others
+SET SESSION AUTHORIZATION regress_sepgsql_test_user;
+
+SET search_path = regtest_schema, public;
+
+CREATE TABLE regtest_table_3 (x int, y serial);
+CREATE TABLE regtest_ptable_3 (o int, p serial) PARTITION BY RANGE (o);
+CREATE TABLE regtest_ptable_3_ones PARTITION OF regtest_ptable_3 FOR VALUES FROM ('0') to ('10');
+CREATE TABLE regtest_ptable_3_tens PARTITION OF regtest_ptable_3 FOR VALUES FROM ('10') to ('100');
+
+CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < y;
+CREATE VIEW regtest_pview_2 AS SELECT * FROM regtest_ptable_3 WHERE o < p;
+
+CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql
+ AS 'BEGIN RETURN $1 * $1 < 100; END';
+
+RESET SESSION AUTHORIZATION;
+
+--
+-- ALTER and CREATE/DROP extra attribute permissions
+--
+CREATE TABLE regtest_table_4 (x int primary key, y int, z int);
+CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
+CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
+ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
+DROP INDEX regtest_index_tbl4_y;
+ALTER TABLE regtest_table_4
+ ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
+DROP TABLE regtest_table_4 CASCADE;
+
+-- For partitioned tables
+CREATE TABLE regtest_ptable_4 (x int, y int, z int) PARTITION BY RANGE (x);
+CREATE TABLE regtest_ptable_4_ones PARTITION OF regtest_ptable_4 FOR VALUES FROM ('0') TO ('10');
+
+CREATE INDEX regtest_pindex_tbl4_y ON regtest_ptable_4_ones(y);
+CREATE INDEX regtest_pindex_tbl4_z ON regtest_ptable_4_ones(z);
+ALTER TABLE regtest_ptable_4 ALTER COLUMN y TYPE float;
+DROP INDEX regtest_pindex_tbl4_y;
+ALTER TABLE regtest_ptable_4_ones
+ ADD CONSTRAINT regtest_ptbl4_con EXCLUDE USING btree (z WITH =);
+DROP TABLE regtest_ptable_4 CASCADE;
+
+--
+-- DROP Permission checks (with clean-up)
+--
+
+DROP FUNCTION regtest_func(text,int[]);
+DROP AGGREGATE regtest_agg(int);
+
+DROP SEQUENCE regtest_seq;
+DROP VIEW regtest_view;
+
+ALTER TABLE regtest_table DROP COLUMN y;
+
+ALTER TABLE regtest_ptable DROP COLUMN q CASCADE;
+
+DROP TABLE regtest_table;
+DROP TABLE regtest_ptable CASCADE;
+
+DROP OWNED BY regress_sepgsql_test_user;
+
+DROP DATABASE sepgsql_test_regression;
+DROP USER regress_sepgsql_test_user;
+DROP SCHEMA IF EXISTS regtest_schema CASCADE;
diff --git a/contrib/sepgsql/sql/dml.sql b/contrib/sepgsql/sql/dml.sql
new file mode 100644
index 0000000..4a47b4a
--- /dev/null
+++ b/contrib/sepgsql/sql/dml.sql
@@ -0,0 +1,257 @@
+--
+-- Regression Test for DML Permissions
+--
+
+--
+-- Setup
+--
+CREATE TABLE t1 (a int, junk int, b text);
+SECURITY LABEL ON TABLE t1 IS 'system_u:object_r:sepgsql_table_t:s0';
+ALTER TABLE t1 DROP COLUMN junk;
+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc');
+
+CREATE TABLE t2 (x int, y text);
+SECURITY LABEL ON TABLE t2 IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+INSERT INTO t2 VALUES (1, 'xxx'), (2, 'yyy'), (3, 'zzz');
+
+CREATE TABLE t3 (s int, t text);
+SECURITY LABEL ON TABLE t3 IS 'system_u:object_r:sepgsql_fixed_table_t:s0';
+INSERT INTO t3 VALUES (1, 'sss'), (2, 'ttt'), (3, 'uuu');
+
+CREATE TABLE t4 (m int, junk int, n text);
+SECURITY LABEL ON TABLE t4 IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+ALTER TABLE t4 DROP COLUMN junk;
+INSERT INTO t4 VALUES (1, 'mmm'), (2, 'nnn'), (3, 'ooo');
+
+CREATE TABLE t5 (e text, f text, g text);
+SECURITY LABEL ON TABLE t5 IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t5.e IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t5.f IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t5.g IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+
+---
+-- partitioned table parent
+CREATE TABLE t1p (o int, p text, q text) PARTITION BY RANGE (o);
+SECURITY LABEL ON TABLE t1p IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p.o IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p.p IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t1p.q IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+
+-- partitioned table children
+CREATE TABLE t1p_ones PARTITION OF t1p FOR VALUES FROM ('0') TO ('10');
+SECURITY LABEL ON COLUMN t1p_ones.o IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_ones.p IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_ones.q IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+CREATE TABLE t1p_tens PARTITION OF t1p FOR VALUES FROM ('10') TO ('100');
+SECURITY LABEL ON COLUMN t1p_tens.o IS 'system_u:object_r:sepgsql_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_tens.p IS 'system_u:object_r:sepgsql_ro_table_t:s0';
+SECURITY LABEL ON COLUMN t1p_tens.q IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+
+---
+
+CREATE TABLE customer (cid int primary key, cname text, ccredit text);
+SECURITY LABEL ON COLUMN customer.ccredit IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+INSERT INTO customer VALUES (1, 'Taro', '1111-2222-3333-4444'),
+ (2, 'Hanako', '5555-6666-7777-8888');
+CREATE FUNCTION customer_credit(int) RETURNS text
+ AS 'SELECT regexp_replace(ccredit, ''-[0-9]+$'', ''-????'') FROM customer WHERE cid = $1'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION customer_credit(int)
+ IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
+
+SELECT objtype, objname, label FROM pg_seclabels
+ WHERE provider = 'selinux'
+ AND objtype in ('table', 'column')
+ AND objname in ('t1', 't2', 't3', 't4',
+ 't5', 't5.e', 't5.f', 't5.g',
+ 't1p', 't1p.o', 't1p.p', 't1p.q',
+ 't1p_ones', 't1p_ones.o', 't1p_ones.p', 't1p_ones.q',
+ 't1p_tens', 't1p_tens.o', 't1p_tens.p', 't1p_tens.q')
+ORDER BY objname COLLATE "C";
+
+CREATE SCHEMA my_schema_1;
+CREATE TABLE my_schema_1.ts1 (a int, b text);
+CREATE TABLE my_schema_1.pts1 (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE my_schema_1.pts1_ones PARTITION OF my_schema_1.pts1 FOR VALUES FROM ('0') to ('10');
+
+CREATE SCHEMA my_schema_2;
+CREATE TABLE my_schema_2.ts2 (x int, y text);
+CREATE TABLE my_schema_2.pts2 (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE my_schema_2.pts2_tens PARTITION OF my_schema_2.pts2 FOR VALUES FROM ('10') to ('100');
+
+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
+
+--
+-- Simple DML statements
+--
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+
+SELECT * FROM t1; -- ok
+SELECT * FROM t2; -- ok
+SELECT * FROM t3; -- ok
+SELECT * FROM t4; -- failed
+SELECT * FROM t5; -- failed
+SELECT e,f FROM t5; -- ok
+SELECT (t1.*)::record FROM t1; -- ok
+SELECT (t4.*)::record FROM t4; -- failed
+
+---
+-- partitioned table parent
+SELECT * FROM t1p; -- failed
+SELECT o,p FROM t1p; -- ok
+--partitioned table children
+SELECT * FROM t1p_ones; -- failed
+SELECT o FROM t1p_ones; -- ok
+SELECT o,p FROM t1p_ones; -- ok
+SELECT * FROM t1p_tens; -- failed
+SELECT o FROM t1p_tens; -- ok
+SELECT o,p FROM t1p_tens; -- ok
+---
+
+SELECT * FROM customer; -- failed
+SELECT cid, cname, customer_credit(cid) FROM customer; -- ok
+
+SELECT count(*) FROM t5; -- ok
+SELECT count(*) FROM t5 WHERE g IS NULL; -- failed
+
+---
+-- partitioned table parent
+SELECT count(*) FROM t1p; -- ok
+SELECT count(*) FROM t1p WHERE q IS NULL; -- failed
+-- partitioned table children
+SELECT count(*) FROM t1p_ones; -- ok
+SELECT count(*) FROM t1p_ones WHERE q IS NULL; -- failed
+SELECT count(*) FROM t1p_tens; -- ok
+SELECT count(*) FROM t1p_tens WHERE q IS NULL; -- failed
+---
+
+INSERT INTO t1 VALUES (4, 'abc'); -- ok
+INSERT INTO t2 VALUES (4, 'xyz'); -- failed
+INSERT INTO t3 VALUES (4, 'stu'); -- ok
+INSERT INTO t4 VALUES (4, 'mno'); -- failed
+INSERT INTO t5 VALUES (1,2,3); -- failed
+INSERT INTO t5 (e,f) VALUES ('abc', 'def'); -- failed
+INSERT INTO t5 (e) VALUES ('abc'); -- ok
+
+---
+-- partitioned table parent
+INSERT INTO t1p (o,p) VALUES (9, 'mno'); -- failed
+INSERT INTO t1p (o) VALUES (9); -- ok
+INSERT INTO t1p (o,p) VALUES (99, 'pqr'); -- failed
+INSERT INTO t1p (o) VALUES (99); -- ok
+-- partitioned table children
+INSERT INTO t1p_ones (o,p) VALUES (9, 'mno'); -- failed
+INSERT INTO t1p_ones (o) VALUES (9); -- ok
+INSERT INTO t1p_tens (o,p) VALUES (99, 'pqr'); -- failed
+INSERT INTO t1p_tens (o) VALUES (99); -- ok
+---
+
+UPDATE t1 SET b = b || '_upd'; -- ok
+UPDATE t2 SET y = y || '_upd'; -- failed
+UPDATE t3 SET t = t || '_upd'; -- failed
+UPDATE t4 SET n = n || '_upd'; -- failed
+UPDATE t5 SET e = 'xyz'; -- ok
+UPDATE t5 SET e = f || '_upd'; -- ok
+UPDATE t5 SET e = g || '_upd'; -- failed
+
+---
+-- partitioned table parent
+UPDATE t1p SET o = 9 WHERE o < 10; -- ok
+UPDATE t1p SET o = 99 WHERE o >= 10; -- ok
+UPDATE t1p SET o = ascii(COALESCE(p,'upd'))%10 WHERE o < 10; -- ok
+UPDATE t1p SET o = ascii(COALESCE(q,'upd'))%100 WHERE o >= 10; -- failed
+-- partitioned table children
+UPDATE t1p_ones SET o = 9; -- ok
+UPDATE t1p_ones SET o = ascii(COALESCE(p,'upd'))%10; -- ok
+UPDATE t1p_ones SET o = ascii(COALESCE(q,'upd'))%10; -- failed
+UPDATE t1p_tens SET o = 99; -- ok
+UPDATE t1p_tens SET o = ascii(COALESCE(p,'upd'))%100; -- ok
+UPDATE t1p_tens SET o = ascii(COALESCE(q,'upd'))%100; -- failed
+---
+
+DELETE FROM t1; -- ok
+DELETE FROM t2; -- failed
+DELETE FROM t3; -- failed
+DELETE FROM t4; -- failed
+DELETE FROM t5; -- ok
+DELETE FROM t5 WHERE f IS NULL; -- ok
+DELETE FROM t5 WHERE g IS NULL; -- failed
+
+---
+-- partitioned table parent
+DELETE FROM t1p; -- ok
+DELETE FROM t1p WHERE p IS NULL; -- ok
+DELETE FROM t1p WHERE q IS NULL; -- failed
+-- partitioned table children
+DELETE FROM t1p_ones WHERE p IS NULL; -- ok
+DELETE FROM t1p_ones WHERE q IS NULL; -- failed;
+DELETE FROM t1p_tens WHERE p IS NULL; -- ok
+DELETE FROM t1p_tens WHERE q IS NULL; -- failed
+---
+
+--
+-- COPY TO/FROM statements
+--
+COPY t1 TO '/dev/null'; -- ok
+COPY t2 TO '/dev/null'; -- ok
+COPY t3 TO '/dev/null'; -- ok
+COPY t4 TO '/dev/null'; -- failed
+COPY t5 TO '/dev/null'; -- failed
+COPY t5(e,f) TO '/dev/null'; -- ok
+
+---
+-- partitioned table parent
+COPY (SELECT * FROM t1p) TO '/dev/null'; -- failed
+COPY (SELECT (o,p) FROM t1p) TO '/dev/null'; -- ok
+-- partitioned table children
+COPY t1p_ones TO '/dev/null'; -- failed
+COPY t1p_ones(o,p) TO '/dev/null'; -- ok
+COPY t1p_tens TO '/dev/null'; -- failed
+COPY t1p_tens(o,p) TO '/dev/null'; -- ok
+---
+
+COPY t1 FROM '/dev/null'; -- ok
+COPY t2 FROM '/dev/null'; -- failed
+COPY t3 FROM '/dev/null'; -- ok
+COPY t4 FROM '/dev/null'; -- failed
+COPY t5 FROM '/dev/null'; -- failed
+COPY t5 (e,f) FROM '/dev/null'; -- failed
+COPY t5 (e) FROM '/dev/null'; -- ok
+
+---
+-- partitioned table parent
+COPY t1p FROM '/dev/null'; -- failed
+COPY t1p (o) FROM '/dev/null'; -- ok
+-- partitioned table children
+COPY t1p_ones FROM '/dev/null'; -- failed
+COPY t1p_ones (o) FROM '/dev/null'; -- ok
+COPY t1p_tens FROM '/dev/null'; -- failed
+COPY t1p_tens (o) 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:sepgsql_regtest_superuser_t:s0-s0:c0.c255
+DROP TABLE IF EXISTS t1 CASCADE;
+DROP TABLE IF EXISTS t2 CASCADE;
+DROP TABLE IF EXISTS t3 CASCADE;
+DROP TABLE IF EXISTS t4 CASCADE;
+DROP TABLE IF EXISTS t5 CASCADE;
+DROP TABLE IF EXISTS t1p 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/contrib/sepgsql/sql/label.sql b/contrib/sepgsql/sql/label.sql
new file mode 100644
index 0000000..d19c6ed
--- /dev/null
+++ b/contrib/sepgsql/sql/label.sql
@@ -0,0 +1,294 @@
+--
+-- Regression Tests for Label Management
+--
+
+--
+-- Setup
+--
+CREATE TABLE t1 (a int, b text);
+INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'), (3, 'ccc');
+SELECT * INTO t2 FROM t1 WHERE a % 2 = 0;
+
+CREATE FUNCTION f1 () RETURNS text
+ AS 'SELECT sepgsql_getcon()'
+ LANGUAGE sql;
+
+CREATE FUNCTION f2 () RETURNS text
+ AS 'SELECT sepgsql_getcon()'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION f2()
+ IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
+
+CREATE FUNCTION f3 () RETURNS text
+ AS 'BEGIN
+ RAISE EXCEPTION ''an exception from f3()'';
+ RETURN NULL;
+ END;' LANGUAGE plpgsql;
+SECURITY LABEL ON FUNCTION f3()
+ IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
+
+CREATE FUNCTION f4 () RETURNS text
+ AS 'SELECT sepgsql_getcon()'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION f4()
+ IS 'system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0';
+
+CREATE FUNCTION f5 (text) RETURNS bool
+ AS 'SELECT sepgsql_setcon($1)'
+ LANGUAGE sql;
+SECURITY LABEL ON FUNCTION f5(text)
+ IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0';
+
+CREATE TABLE auth_tbl(uname text, credential text, label text);
+INSERT INTO auth_tbl
+ VALUES ('foo', 'acbd18db4cc2f85cedef654fccc4a4d8', 'sepgsql_regtest_foo_t:s0'),
+ ('var', 'b2145aac704ce76dbe1ac7adac535b23', 'sepgsql_regtest_var_t:s0'),
+ ('baz', 'b2145aac704ce76dbe1ac7adac535b23', 'sepgsql_regtest_baz_t:s0');
+SECURITY LABEL ON TABLE auth_tbl
+ IS 'system_u:object_r:sepgsql_secret_table_t:s0';
+
+CREATE FUNCTION auth_func(text, text) RETURNS bool
+ LANGUAGE sql
+ AS 'SELECT sepgsql_setcon(regexp_replace(sepgsql_getcon(), ''_r:.*$'', ''_r:'' || label))
+ FROM auth_tbl WHERE uname = $1 AND credential = $2';
+SECURITY LABEL ON FUNCTION auth_func(text,text)
+ IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0';
+
+CREATE TABLE foo_tbl(a int, b text);
+INSERT INTO foo_tbl VALUES (1, 'aaa'), (2,'bbb'), (3,'ccc'), (4,'ddd');
+SECURITY LABEL ON TABLE foo_tbl
+ IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
+
+CREATE TABLE var_tbl(x int, y text);
+INSERT INTO var_tbl VALUES (2,'xxx'), (3,'yyy'), (4,'zzz'), (5,'xyz');
+SECURITY LABEL ON TABLE var_tbl
+ IS 'system_u:object_r:sepgsql_regtest_var_table_t:s0';
+
+CREATE TABLE foo_ptbl(o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE foo_ptbl_ones PARTITION OF foo_ptbl FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE foo_ptbl_tens PARTITION OF foo_ptbl FOR VALUES FROM ('10') TO ('100');
+
+INSERT INTO foo_ptbl VALUES (0, 'aaa'), (9,'bbb'), (10,'ccc'), (99,'ddd');
+SECURITY LABEL ON TABLE foo_ptbl
+ IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
+
+CREATE TABLE var_ptbl(q int, r text) PARTITION BY RANGE (q);
+CREATE TABLE var_ptbl_ones PARTITION OF var_ptbl FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE var_ptbl_tens PARTITION OF var_ptbl FOR VALUES FROM ('10') TO ('100');
+
+INSERT INTO var_ptbl VALUES (0,'xxx'), (9,'yyy'), (10,'zzz'), (99,'xyz');
+SECURITY LABEL ON TABLE var_ptbl
+ IS 'system_u:object_r:sepgsql_regtest_var_table_t:s0';
+
+--
+-- Tests for default labeling behavior
+--
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+CREATE TABLE t3 (s int, t text);
+INSERT INTO t3 VALUES (1, 'sss'), (2, 'ttt'), (3, 'uuu');
+
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0
+CREATE TABLE t4 (m int, n text);
+INSERT INTO t4 VALUES (1,'mmm'), (2,'nnn'), (3,'ooo');
+
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
+CREATE TABLE tpart (o int, p text) PARTITION BY RANGE (o);
+
+CREATE TABLE tpart_ones PARTITION OF tpart FOR VALUES FROM ('0') TO ('10');
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0
+CREATE TABLE tpart_tens PARTITION OF tpart FOR VALUES FROM ('10') TO ('100');
+
+INSERT INTO tpart VALUES (0, 'aaa');
+INSERT INTO tpart VALUES (9, 'bbb');
+INSERT INTO tpart VALUES (99, 'ccc');
+
+SELECT objtype, objname, label FROM pg_seclabels
+ WHERE provider = 'selinux' AND objtype = 'table' AND objname in ('t1', 't2', 't3',
+ 'tpart',
+ 'tpart_ones',
+ 'tpart_tens')
+ ORDER BY objname COLLATE "C" ASC;
+SELECT objtype, objname, label FROM pg_seclabels
+ WHERE provider = 'selinux' AND objtype = 'column' AND (objname like 't3.%'
+ OR objname like 't4.%'
+ OR objname like 'tpart.%'
+ OR objname like 'tpart_ones.%'
+ OR objname like 'tpart_tens.%')
+ ORDER BY objname COLLATE "C" ASC;
+
+--
+-- Tests for SECURITY LABEL
+--
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0
+SECURITY LABEL ON TABLE t1
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+SECURITY LABEL ON TABLE t2
+ IS 'invalid security context'; -- be failed
+SECURITY LABEL ON COLUMN t2
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- be failed
+SECURITY LABEL ON COLUMN t2.b
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+SECURITY LABEL ON TABLE tpart
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+SECURITY LABEL ON TABLE tpart
+ IS 'invalid security context'; -- failed
+SECURITY LABEL ON COLUMN tpart
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- failed
+SECURITY LABEL ON COLUMN tpart.o
+ IS 'system_u:object_r:sepgsql_ro_table_t:s0'; -- ok
+
+--
+-- 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
+SELECT f4(); -- failed on domain transition
+SELECT sepgsql_getcon(); -- client's label must be restored
+
+--
+-- Test for Dynamic Domain Transition
+--
+
+-- validation of transaction aware dynamic-transition
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c25
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c15');
+SELECT sepgsql_getcon();
+
+SELECT sepgsql_setcon(NULL); -- failed to reset
+SELECT sepgsql_getcon();
+
+BEGIN;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c12');
+SELECT sepgsql_getcon();
+
+SAVEPOINT svpt_1;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c9');
+SELECT sepgsql_getcon();
+
+SAVEPOINT svpt_2;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c6');
+SELECT sepgsql_getcon();
+
+SAVEPOINT svpt_3;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c3');
+SELECT sepgsql_getcon();
+
+ROLLBACK TO SAVEPOINT svpt_2;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c9'
+
+ROLLBACK TO SAVEPOINT svpt_1;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c12'
+
+ABORT;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c15'
+
+BEGIN;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c8');
+SELECT sepgsql_getcon();
+
+SAVEPOINT svpt_1;
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c4');
+SELECT sepgsql_getcon();
+
+ROLLBACK TO SAVEPOINT svpt_1;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c8'
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0:c0.c6');
+
+COMMIT;
+SELECT sepgsql_getcon(); -- should be 's0:c0.c6'
+
+-- sepgsql_regtest_user_t is not available dynamic-transition,
+-- unless sepgsql_setcon() is called inside of trusted-procedure
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15
+
+-- sepgsql_regtest_user_t has no permission to switch current label
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0'); -- failed
+SELECT sepgsql_getcon();
+
+-- trusted procedure allows to switch, but unavailable to override MCS rules
+SELECT f5('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c7'); -- OK
+SELECT sepgsql_getcon();
+
+SELECT f5('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c31'); -- Failed
+SELECT sepgsql_getcon();
+
+SELECT f5(NULL); -- Failed
+SELECT sepgsql_getcon();
+
+BEGIN;
+SELECT f5('unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c3'); -- OK
+SELECT sepgsql_getcon();
+
+ABORT;
+SELECT sepgsql_getcon();
+
+--
+-- Test for simulation of typical connection pooling server
+--
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_pool_t:s0
+
+-- we shouldn't allow to switch client label without trusted procedure
+SELECT sepgsql_setcon('unconfined_u:unconfined_r:sepgsql_regtest_foo_t:s0');
+
+SELECT * FROM auth_tbl; -- failed, no permission to reference
+
+-- switch to "foo"
+SELECT auth_func('foo', 'acbd18db4cc2f85cedef654fccc4a4d8');
+
+SELECT sepgsql_getcon();
+
+SELECT * FROM foo_tbl; -- OK
+SELECT * FROM foo_ptbl; -- OK
+
+SELECT * FROM var_tbl; -- failed
+SELECT * FROM var_ptbl; -- failed
+
+SELECT * FROM auth_tbl; -- failed
+
+SELECT sepgsql_setcon(NULL); -- end of session
+SELECT sepgsql_getcon();
+
+-- the pooler cannot touch these tables directly
+SELECT * FROM foo_tbl; -- failed
+SELECT * FROM foo_ptbl; -- failed
+
+SELECT * FROM var_tbl; -- failed
+SELECT * FROM var_ptbl; -- failed
+
+-- switch to "var"
+SELECT auth_func('var', 'b2145aac704ce76dbe1ac7adac535b23');
+
+SELECT sepgsql_getcon();
+
+SELECT * FROM foo_tbl; -- failed
+SELECT * FROM foo_ptbl; -- failed
+
+SELECT * FROM var_tbl; -- OK
+SELECT * FROM var_ptbl; -- OK
+
+SELECT * FROM auth_tbl; -- failed
+
+SELECT sepgsql_setcon(NULL); -- end of session
+
+-- misc checks
+SELECT auth_func('var', 'invalid credential'); -- not works
+SELECT sepgsql_getcon();
+
+--
+-- Clean up
+--
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0-s0:c0.c255
+DROP TABLE IF EXISTS t1 CASCADE;
+DROP TABLE IF EXISTS t2 CASCADE;
+DROP TABLE IF EXISTS t3 CASCADE;
+DROP TABLE IF EXISTS t4 CASCADE;
+DROP TABLE IF EXISTS tpart CASCADE;
+DROP FUNCTION IF EXISTS f1() CASCADE;
+DROP FUNCTION IF EXISTS f2() CASCADE;
+DROP FUNCTION IF EXISTS f3() CASCADE;
+DROP FUNCTION IF EXISTS f4() CASCADE;
+DROP FUNCTION IF EXISTS f5(text) CASCADE;
diff --git a/contrib/sepgsql/sql/misc.sql b/contrib/sepgsql/sql/misc.sql
new file mode 100644
index 0000000..bd5b6e2
--- /dev/null
+++ b/contrib/sepgsql/sql/misc.sql
@@ -0,0 +1,45 @@
+--
+-- Regression Test for Misc Permission Checks
+--
+
+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);
+
+CREATE TABLE t1p (o int, p text) PARTITION BY RANGE (o);
+CREATE TABLE t1p_ones PARTITION OF t1p FOR VALUES FROM ('0') TO ('10');
+CREATE TABLE t1p_tens PARTITION OF t1p FOR VALUES FROM ('10') TO ('100');
+INSERT INTO t1p (SELECT x, md5(x::text) FROM generate_series(0,99) 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%';
+SELECT * FROM t1p WHERE o > 50 AND p like '%64%';
+SELECT * FROM t1p_ones WHERE o > 50 AND p like '%64%';
+SELECT * FROM t1p_tens WHERE o > 50 AND p like '%64%';
+
+-- aggregate function
+SELECT MIN(x), AVG(x) FROM t1;
+SELECT MIN(o), AVG(o) FROM t1p;
+SELECT MIN(o), AVG(o) FROM t1p_ones;
+SELECT MIN(o), AVG(o) FROM t1p_tens;
+
+-- window function
+SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
+SELECT row_number() OVER (order by o), * FROM t1p WHERE p like '%86%';
+SELECT row_number() OVER (order by o), * FROM t1p_ones WHERE p like '%86%';
+SELECT row_number() OVER (order by o), * FROM t1p_tens WHERE p like '%86%';
+
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+--
+-- Cleanup
+--
+DROP TABLE IF EXISTS t1 CASCADE;
+DROP TABLE IF EXISTS t1p CASCADE;
diff --git a/contrib/sepgsql/sql/truncate.sql b/contrib/sepgsql/sql/truncate.sql
new file mode 100644
index 0000000..3748a1b
--- /dev/null
+++ b/contrib/sepgsql/sql/truncate.sql
@@ -0,0 +1,24 @@
+--
+-- Regression Test for TRUNCATE
+--
+
+--
+-- Setup
+--
+CREATE TABLE julio_claudians (name text, birth_date date);
+SECURITY LABEL ON TABLE julio_claudians IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
+INSERT INTO julio_claudians VALUES ('Augustus', 'September 23, 63 BC'), ('Tiberius', 'November 16, 42 BC'), ('Caligula', 'August 31, 0012'), ('Claudius', 'August 1, 0010'), ('Nero', 'December 15, 0037');
+
+CREATE TABLE flavians (name text, birth_date date);
+SECURITY LABEL ON TABLE flavians IS 'system_u:object_r:sepgsql_table_t:s0';
+
+INSERT INTO flavians VALUES ('Vespasian', 'November 17, 0009'), ('Titus', 'December 30, 0039'), ('Domitian', 'October 24, 0051');
+
+SELECT * from julio_claudians;
+SELECT * from flavians;
+
+TRUNCATE TABLE julio_claudians; -- ok
+TRUNCATE TABLE flavians; -- failed
+
+SELECT * from julio_claudians;
+SELECT * from flavians;
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
new file mode 100755
index 0000000..3a29556
--- /dev/null
+++ b/contrib/sepgsql/test_sepgsql
@@ -0,0 +1,306 @@
+#!/bin/sh
+#
+# Run the sepgsql regression tests, after making a lot of environmental checks
+# to try to ensure that the SELinux environment is set up appropriately and
+# the database is configured correctly.
+#
+# Note that this must be run against an installed Postgres database.
+# There's no equivalent of "make check", and that wouldn't be terribly useful
+# since much of the value is in checking that you installed sepgsql into
+# your database correctly.
+#
+# This must be run in the contrib/sepgsql directory of a Postgres build tree.
+#
+
+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 =============="
+
+# matchpathcon must be present to assess whether the installation environment
+# is OK.
+echo -n "checking for matchpathcon ... "
+if ! matchpathcon -n . >/dev/null 2>&1; then
+ echo "not found"
+ echo ""
+ echo "The matchpathcon command must be available."
+ echo "Please install it or update your PATH to include it"
+ echo "(it is typically in '/usr/sbin', which might not be in your PATH)."
+ echo "matchpathcon is typically included in the libselinux-utils package."
+ exit 1
+fi
+echo "ok"
+
+# runcon must be present to launch psql using the correct environment
+echo -n "checking for runcon ... "
+if ! runcon --help >/dev/null 2>&1; then
+ echo "not found"
+ echo ""
+ echo "The runcon command must be available."
+ echo "runcon is typically included in the coreutils package."
+ echo ""
+ exit 1
+fi
+echo "ok"
+
+# check sestatus too, since that lives in yet another package
+echo -n "checking for sestatus ... "
+if ! sestatus >/dev/null 2>&1; then
+ echo "not found"
+ echo ""
+ echo "The sestatus command must be available."
+ echo "sestatus is typically included in the policycoreutils package."
+ echo ""
+ exit 1
+fi
+echo "ok"
+
+# check that the user is running in the unconfined_t domain
+echo -n "checking current user domain ... "
+DOMAIN=`id -Z 2>/dev/null | sed 's/:/ /g' | awk '{print $3}'`
+echo ${DOMAIN:-failed}
+if [ "${DOMAIN}" != unconfined_t ]; then
+ echo ""
+ echo "The regression tests must be launched from the unconfined_t domain."
+ echo ""
+ echo "The unconfined_t domain is typically the default domain for user"
+ echo "shell processes. If the default has been changed on your system,"
+ echo "you can revert the changes like this:"
+ echo ""
+ echo " \$ sudo semanage login -d `whoami`"
+ echo ""
+ echo "Or, you can add a setting to log in using the unconfined_t domain:"
+ echo ""
+ echo " \$ sudo semanage login -a -s unconfined_u -r s0-s0:c0.c255 `whoami`"
+ echo ""
+ exit 1
+fi
+
+# SELinux must be configured in enforcing mode
+echo -n "checking selinux operating mode ... "
+CURRENT_MODE=`LANG=C sestatus | grep '^Current mode:' | awk '{print $3}'`
+echo ${CURRENT_MODE:-failed}
+if [ "${CURRENT_MODE}" = enforcing ]; then
+ : OK
+elif [ "${CURRENT_MODE}" = permissive -o "${CURRENT_MODE}" = disabled ]; then
+ echo ""
+ echo "Before running the regression tests, SELinux must be enabled and"
+ echo "must be running in enforcing mode."
+ echo ""
+ echo "If SELinux is currently running in permissive mode, you can"
+ echo "switch to enforcing mode using the 'setenforce' command."
+ echo
+ echo " \$ sudo setenforce 1"
+ echo ""
+ echo "The system default setting is configured in /etc/selinux/config,"
+ echo "or using a kernel boot parameter."
+ echo ""
+ exit 1
+else
+ echo ""
+ echo "Unable to determine the current selinux operating mode. Please"
+ echo "verify that the sestatus command is installed and in your PATH."
+ echo ""
+ exit 1
+fi
+
+# 'sepgsql-regtest' policy module must be loaded
+echo -n "checking for sepgsql-regtest policy ... "
+SELINUX_MNT=`LANG=C sestatus | grep '^SELinuxfs mount:' | awk '{print $3}'`
+if [ "$SELINUX_MNT" = "" ]; then
+ echo "failed"
+ echo ""
+ echo "Unable to find SELinuxfs mount point."
+ echo ""
+ echo "The sestatus command should report the location where SELinuxfs"
+ echo "is mounted, but did not do so."
+ echo ""
+ exit 1
+fi
+if [ ! -e "${SELINUX_MNT}/booleans/sepgsql_regression_test_mode" ]; then
+ echo "failed"
+ echo ""
+ echo "The 'sepgsql-regtest' policy module appears not to be installed."
+ echo "Without this policy installed, the regression tests will fail."
+ echo "You can install this module using the following commands:"
+ echo ""
+ 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 ""
+ exit 1
+fi
+echo "ok"
+
+# Verify that sepgsql_regression_test_mode is active.
+echo -n "checking whether policy is enabled ... "
+POLICY_STATUS=`getsebool sepgsql_regression_test_mode | awk '{print $3}'`
+echo ${POLICY_STATUS:-failed}
+if [ "${POLICY_STATUS}" != on ]; then
+ echo ""
+ echo "The SELinux boolean 'sepgsql_regression_test_mode' must be"
+ echo "turned on in order to enable the rules necessary to run the"
+ echo "regression tests."
+ echo ""
+ if [ "${POLICY_STATUS}" = "" ]; then
+ echo "We attempted to determine the state of this Boolean using"
+ echo "'getsebool', but that command did not produce the expected"
+ echo "output. Please verify that getsebool is available and in"
+ echo "your PATH."
+ else
+ echo "You can turn on this variable using the following commands:"
+ echo ""
+ echo " \$ sudo setsebool sepgsql_regression_test_mode on"
+ echo ""
+ echo "For security reasons, it is suggested that you turn off this"
+ echo "variable when regression testing is complete and the associated"
+ echo "rules are no longer needed."
+ fi
+ echo ""
+ exit 1
+fi
+POLICY_STATUS=`getsebool sepgsql_enable_users_ddl | awk '{print $3}'`
+echo ${POLICY_STATUS:-failed}
+if [ "${POLICY_STATUS}" != on ]; then
+ echo ""
+ echo "The SELinux boolean 'sepgsql_enable_users_ddl' must be"
+ echo "turned on in order to enable the rules necessary to run"
+ echo "the regression tests."
+ echo ""
+ if [ "${POLICY_STATUS}" = "" ]; then
+ echo "We attempted to determine the state of this Boolean using"
+ echo "'getsebool', but that command did not produce the expected"
+ echo "output. Please verify that getsebool is available and in"
+ echo "your PATH."
+ else
+ echo "You can turn on this variable using the following commands:"
+ echo ""
+ echo " \$ sudo setsebool sepgsql_enable_users_ddl on"
+ echo ""
+ echo "For security reasons, it is suggested that you turn off this"
+ echo "variable when regression testing is complete, unless you"
+ echo "don't want to allow unprivileged users DDL commands."
+ fi
+ echo ""
+ exit 1
+fi
+
+# 'psql' command must be executable from test domain
+echo -n "checking whether we can run psql ... "
+CMD_PSQL="${PG_BINDIR}/psql"
+if [ ! -e "${CMD_PSQL}" ]; then
+ echo "not found"
+ echo
+ echo "${CMD_PSQL} was not found."
+ echo "Check your PostgreSQL installation."
+ echo
+ exit 1
+fi
+runcon -t sepgsql_regtest_user_t "${CMD_PSQL}" --help >& /dev/null
+if [ $? -ne 0 ]; then
+ echo "failed"
+ echo
+ echo "${CMD_PSQL} must be executable from the"
+ echo "sepgsql_regtest_user_t domain. That domain has restricted privileges"
+ echo "compared to unconfined_t, so the problem may be the psql file's"
+ echo "SELinux label. Try"
+ echo
+ PSQL_T=`matchpathcon -n "${CMD_PSQL}" | sed 's/:/ /g' | awk '{print $3}'`
+ if [ "${PSQL_T}" = "user_home_t" ]; then
+ # Installation appears to be in /home directory
+ echo " \$ sudo restorecon -R ${PG_BINDIR}"
+ echo
+ echo "Or, using chcon"
+ echo
+ echo " \$ sudo chcon -t user_home_t ${CMD_PSQL}"
+ else
+ echo " \$ sudo restorecon -R ${PG_BINDIR}"
+ echo
+ echo "Or, using chcon"
+ echo
+ echo " \$ sudo chcon -t bin_t ${CMD_PSQL}"
+ fi
+ echo
+ exit 1
+fi
+echo "ok"
+
+# loadable module must be installed and not configured to permissive mode
+echo -n "checking sepgsql installation ... "
+VAL="`${CMD_PSQL} -X -t -c 'SHOW sepgsql.permissive' template1 2>/dev/null`"
+RETVAL="$?"
+if [ $RETVAL -eq 2 ]; then
+ echo "failed"
+ echo ""
+ echo "Could not connect to the database server."
+ echo "Please check your PostgreSQL installation."
+ echo ""
+ exit 1
+elif [ $RETVAL -ne 0 ]; then
+ echo "failed"
+ echo ""
+ echo "The sepgsql module does not appear to be loaded. Please verify"
+ echo "that the 'shared_preload_libraries' setting in postgresql.conf"
+ echo "includes 'sepgsql', and then restart the server."
+ echo ""
+ echo "See Installation section of the contrib/sepgsql documentation."
+ echo ""
+ exit 1
+elif ! echo "$VAL" | grep -q 'off$'; then
+ echo "failed"
+ echo ""
+ echo "The parameter 'sepgsql.permissive' is set to 'on'. It must be"
+ echo "turned off before running the regression tests."
+ echo ""
+ exit 1
+fi
+echo "ok"
+
+# template1 database must be labeled
+# NOTE: this test is wrong; we really ought to be checking template0.
+# But we can't connect to that without extra pushups, and it's not worth it.
+echo -n "checking for labels in template1 ... "
+NUM=`${CMD_PSQL} -XAt -c 'SELECT count(*) FROM pg_catalog.pg_seclabel' template1 2>/dev/null`
+if [ -z "${NUM}" ]; then
+ echo "failed"
+ echo ""
+ echo "In order to test sepgsql, initial labels must be assigned within"
+ echo "the 'template1' database. These labels will be copied into the"
+ echo "regression test database."
+ echo ""
+ echo "See Installation section of the contrib/sepgsql documentation."
+ echo ""
+ exit 1
+fi
+echo "found ${NUM}"
+
+#
+# checking complete - let's run the tests
+#
+
+echo
+echo "============== running sepgsql regression tests =============="
+
+tests="label dml ddl alter misc"
+
+# Check if the truncate permission exists in the loaded policy, and if so,
+# run the truncate test
+#
+# Testing the TRUNCATE regression test can be done by manually adding
+# the permission with CIL if necessary:
+# sudo semodule -cE base
+# sudo sed -i -E 's/(class db_table.*?) \)/\1 truncate\)/' base.cil
+# sudo semodule -i base.cil
+
+if [ -f /sys/fs/selinux/class/db_table/perms/truncate ]; then
+ tests+=" truncate"
+fi
+
+make REGRESS="$tests" REGRESS_OPTS="--launcher ./launcher" installcheck
+# exit with the exit code provided by "make"
diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c
new file mode 100644
index 0000000..639a52c
--- /dev/null
+++ b/contrib/sepgsql/uavc.c
@@ -0,0 +1,520 @@
+/* -------------------------------------------------------------------------
+ *
+ * contrib/sepgsql/uavc.c
+ *
+ * Implementation of userspace access vector cache; that enables to cache
+ * access control decisions recently used, and reduce number of kernel
+ * invocations to avoid unnecessary performance hit.
+ *
+ * Copyright (c) 2011-2020, PostgreSQL Global Development Group
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/pg_proc.h"
+#include "commands/seclabel.h"
+#include "common/hashfn.h"
+#include "sepgsql.h"
+#include "storage/ipc.h"
+#include "utils/guc.h"
+#include "utils/memutils.h"
+
+/*
+ * avc_cache
+ *
+ * It enables to cache access control decision (and behavior on execution of
+ * trusted procedure, db_procedure class only) for a particular pair of
+ * security labels and object class in userspace.
+ */
+typedef struct
+{
+ uint32 hash; /* hash value of this cache entry */
+ char *scontext; /* security context of the subject */
+ char *tcontext; /* security context of the target */
+ uint16 tclass; /* object class of the target */
+
+ uint32 allowed; /* permissions to be allowed */
+ uint32 auditallow; /* permissions to be audited on allowed */
+ uint32 auditdeny; /* permissions to be audited on denied */
+
+ bool permissive; /* true, if permissive rule */
+ bool hot_cache; /* true, if recently referenced */
+ bool tcontext_is_valid;
+ /* true, if tcontext is valid */
+ char *ncontext; /* temporary scontext on execution of trusted
+ * procedure, or NULL elsewhere */
+} avc_cache;
+
+/*
+ * Declaration of static variables
+ */
+#define AVC_NUM_SLOTS 512
+#define AVC_NUM_RECLAIM 16
+#define AVC_DEF_THRESHOLD 384
+
+static MemoryContext avc_mem_cxt;
+static List *avc_slots[AVC_NUM_SLOTS]; /* avc's hash buckets */
+static int avc_num_caches; /* number of caches currently used */
+static int avc_lru_hint; /* index of the buckets to be reclaimed next */
+static int avc_threshold; /* threshold to launch cache-reclaiming */
+static char *avc_unlabeled; /* system 'unlabeled' label */
+
+/*
+ * Hash function
+ */
+static uint32
+sepgsql_avc_hash(const char *scontext, const char *tcontext, uint16 tclass)
+{
+ return hash_any((const unsigned char *) scontext, strlen(scontext))
+ ^ hash_any((const unsigned char *) tcontext, strlen(tcontext))
+ ^ tclass;
+}
+
+/*
+ * Reset all the avc caches
+ */
+static void
+sepgsql_avc_reset(void)
+{
+ MemoryContextReset(avc_mem_cxt);
+
+ memset(avc_slots, 0, sizeof(List *) * AVC_NUM_SLOTS);
+ avc_num_caches = 0;
+ avc_lru_hint = 0;
+ avc_unlabeled = NULL;
+}
+
+/*
+ * Reclaim caches recently unreferenced
+ */
+static void
+sepgsql_avc_reclaim(void)
+{
+ ListCell *cell;
+ int index;
+
+ while (avc_num_caches >= avc_threshold - AVC_NUM_RECLAIM)
+ {
+ index = avc_lru_hint;
+
+ foreach(cell, avc_slots[index])
+ {
+ avc_cache *cache = lfirst(cell);
+
+ if (!cache->hot_cache)
+ {
+ avc_slots[index]
+ = foreach_delete_current(avc_slots[index], cell);
+
+ pfree(cache->scontext);
+ pfree(cache->tcontext);
+ if (cache->ncontext)
+ pfree(cache->ncontext);
+ pfree(cache);
+
+ avc_num_caches--;
+ }
+ else
+ {
+ cache->hot_cache = false;
+ }
+ }
+ avc_lru_hint = (avc_lru_hint + 1) % AVC_NUM_SLOTS;
+ }
+}
+
+/* -------------------------------------------------------------------------
+ *
+ * sepgsql_avc_check_valid
+ *
+ * This function checks whether the cached entries are still valid. If
+ * the security policy has been reloaded (or any other events that requires
+ * resetting userspace caches has occurred) since the last reference to
+ * the access vector cache, we must flush the cache.
+ *
+ * Access control decisions must be atomic, but multiple system calls may
+ * be required to make a decision; thus, when referencing the access vector
+ * cache, we must loop until we complete without an intervening cache flush
+ * event. In practice, looping even once should be very rare. Callers should
+ * do something like this:
+ *
+ * sepgsql_avc_check_valid();
+ * do {
+ * :
+ * <reference to uavc>
+ * :
+ * } while (!sepgsql_avc_check_valid())
+ *
+ * -------------------------------------------------------------------------
+ */
+static bool
+sepgsql_avc_check_valid(void)
+{
+ if (selinux_status_updated() > 0)
+ {
+ sepgsql_avc_reset();
+
+ return false;
+ }
+ return true;
+}
+
+/*
+ * sepgsql_avc_unlabeled
+ *
+ * Returns an alternative label to be applied when no label or an invalid
+ * label would otherwise be assigned.
+ */
+static char *
+sepgsql_avc_unlabeled(void)
+{
+ if (!avc_unlabeled)
+ {
+ security_context_t unlabeled;
+
+ if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: failed to get initial security label: %m")));
+ PG_TRY();
+ {
+ avc_unlabeled = MemoryContextStrdup(avc_mem_cxt, unlabeled);
+ }
+ PG_FINALLY();
+ {
+ freecon(unlabeled);
+ }
+ PG_END_TRY();
+ }
+ return avc_unlabeled;
+}
+
+/*
+ * sepgsql_avc_compute
+ *
+ * A fallback path, when cache mishit. It asks SELinux its access control
+ * decision for the supplied pair of security context and object class.
+ */
+static avc_cache *
+sepgsql_avc_compute(const char *scontext, const char *tcontext, uint16 tclass)
+{
+ char *ucontext = NULL;
+ char *ncontext = NULL;
+ MemoryContext oldctx;
+ avc_cache *cache;
+ uint32 hash;
+ int index;
+ struct av_decision avd;
+
+ hash = sepgsql_avc_hash(scontext, tcontext, tclass);
+ index = hash % AVC_NUM_SLOTS;
+
+ /*
+ * Validation check of the supplied security context. Because it always
+ * invoke system-call, frequent check should be avoided. Unless security
+ * policy is reloaded, validation status shall be kept, so we also cache
+ * whether the supplied security context was valid, or not.
+ */
+ if (security_check_context_raw((security_context_t) tcontext) != 0)
+ ucontext = sepgsql_avc_unlabeled();
+
+ /*
+ * Ask SELinux its access control decision
+ */
+ if (!ucontext)
+ sepgsql_compute_avd(scontext, tcontext, tclass, &avd);
+ else
+ sepgsql_compute_avd(scontext, ucontext, tclass, &avd);
+
+ /*
+ * It also caches a security label to be switched when a client labeled as
+ * 'scontext' executes a procedure labeled as 'tcontext', not only access
+ * control decision on the procedure. The security label to be switched
+ * shall be computed uniquely on a pair of 'scontext' and 'tcontext',
+ * thus, it is reasonable to cache the new label on avc, and enables to
+ * reduce unnecessary system calls. It shall be referenced at
+ * sepgsql_needs_fmgr_hook to check whether the supplied function is a
+ * trusted procedure, or not.
+ */
+ if (tclass == SEPG_CLASS_DB_PROCEDURE)
+ {
+ if (!ucontext)
+ ncontext = sepgsql_compute_create(scontext, tcontext,
+ SEPG_CLASS_PROCESS, NULL);
+ else
+ ncontext = sepgsql_compute_create(scontext, ucontext,
+ SEPG_CLASS_PROCESS, NULL);
+ if (strcmp(scontext, ncontext) == 0)
+ {
+ pfree(ncontext);
+ ncontext = NULL;
+ }
+ }
+
+ /*
+ * Set up an avc_cache object
+ */
+ oldctx = MemoryContextSwitchTo(avc_mem_cxt);
+
+ cache = palloc0(sizeof(avc_cache));
+
+ cache->hash = hash;
+ cache->scontext = pstrdup(scontext);
+ cache->tcontext = pstrdup(tcontext);
+ cache->tclass = tclass;
+
+ cache->allowed = avd.allowed;
+ cache->auditallow = avd.auditallow;
+ cache->auditdeny = avd.auditdeny;
+ cache->hot_cache = true;
+ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)
+ cache->permissive = true;
+ if (!ucontext)
+ cache->tcontext_is_valid = true;
+ if (ncontext)
+ cache->ncontext = pstrdup(ncontext);
+
+ avc_num_caches++;
+
+ if (avc_num_caches > avc_threshold)
+ sepgsql_avc_reclaim();
+
+ avc_slots[index] = lcons(cache, avc_slots[index]);
+
+ MemoryContextSwitchTo(oldctx);
+
+ return cache;
+}
+
+/*
+ * sepgsql_avc_lookup
+ *
+ * Look up a cache entry that matches the supplied security contexts and
+ * object class. If not found, create a new cache entry.
+ */
+static avc_cache *
+sepgsql_avc_lookup(const char *scontext, const char *tcontext, uint16 tclass)
+{
+ avc_cache *cache;
+ ListCell *cell;
+ uint32 hash;
+ int index;
+
+ hash = sepgsql_avc_hash(scontext, tcontext, tclass);
+ index = hash % AVC_NUM_SLOTS;
+
+ foreach(cell, avc_slots[index])
+ {
+ cache = lfirst(cell);
+
+ if (cache->hash == hash &&
+ cache->tclass == tclass &&
+ strcmp(cache->tcontext, tcontext) == 0 &&
+ strcmp(cache->scontext, scontext) == 0)
+ {
+ cache->hot_cache = true;
+ return cache;
+ }
+ }
+ /* not found, so insert a new cache */
+ return sepgsql_avc_compute(scontext, tcontext, tclass);
+}
+
+/*
+ * sepgsql_avc_check_perms(_label)
+ *
+ * It returns 'true', if the security policy suggested to allow the required
+ * permissions. Otherwise, it returns 'false' or raises an error according
+ * to the 'abort_on_violation' argument.
+ * The 'tobject' and 'tclass' identify the target object being referenced,
+ * and 'required' is a bitmask of permissions (SEPG_*__*) defined for each
+ * object classes.
+ * The 'audit_name' is the object name (optional). If SEPGSQL_AVC_NOAUDIT
+ * was supplied, it means to skip all the audit messages.
+ */
+bool
+sepgsql_avc_check_perms_label(const char *tcontext,
+ uint16 tclass, uint32 required,
+ const char *audit_name,
+ bool abort_on_violation)
+{
+ char *scontext = sepgsql_get_client_label();
+ avc_cache *cache;
+ uint32 denied;
+ uint32 audited;
+ bool result;
+
+ sepgsql_avc_check_valid();
+ do
+ {
+ result = true;
+
+ /*
+ * If the target object is unlabeled, we perform the check using the
+ * label supplied by sepgsql_avc_unlabeled().
+ */
+ if (tcontext)
+ cache = sepgsql_avc_lookup(scontext, tcontext, tclass);
+ else
+ cache = sepgsql_avc_lookup(scontext,
+ sepgsql_avc_unlabeled(), tclass);
+
+ denied = required & ~cache->allowed;
+
+ /*
+ * Compute permissions to be audited
+ */
+ if (sepgsql_get_debug_audit())
+ audited = (denied ? (denied & ~0) : (required & ~0));
+ else
+ audited = denied ? (denied & cache->auditdeny)
+ : (required & cache->auditallow);
+
+ if (denied)
+ {
+ /*
+ * In permissive mode or permissive domain, violated permissions
+ * shall be audited to the log files at once, and then implicitly
+ * allowed to avoid a flood of access denied logs, because the
+ * purpose of permissive mode/domain is to collect a violation log
+ * that will make it possible to fix up the security policy.
+ */
+ if (!sepgsql_getenforce() || cache->permissive)
+ cache->allowed |= required;
+ else
+ result = false;
+ }
+ } while (!sepgsql_avc_check_valid());
+
+ /*
+ * In the case when we have something auditable actions here,
+ * sepgsql_audit_log shall be called with text representation of security
+ * labels for both of subject and object. It records this access
+ * violation, so DBA will be able to find out unexpected security problems
+ * later.
+ */
+ if (audited != 0 &&
+ audit_name != SEPGSQL_AVC_NOAUDIT &&
+ sepgsql_get_mode() != SEPGSQL_MODE_INTERNAL)
+ {
+ sepgsql_audit_log(denied != 0,
+ cache->scontext,
+ cache->tcontext_is_valid ?
+ cache->tcontext : sepgsql_avc_unlabeled(),
+ cache->tclass,
+ audited,
+ audit_name);
+ }
+
+ if (abort_on_violation && !result)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("SELinux: security policy violation")));
+
+ return result;
+}
+
+bool
+sepgsql_avc_check_perms(const ObjectAddress *tobject,
+ uint16 tclass, uint32 required,
+ const char *audit_name,
+ bool abort_on_violation)
+{
+ char *tcontext = GetSecurityLabel(tobject, SEPGSQL_LABEL_TAG);
+ bool rc;
+
+ rc = sepgsql_avc_check_perms_label(tcontext,
+ tclass, required,
+ audit_name, abort_on_violation);
+ if (tcontext)
+ pfree(tcontext);
+
+ return rc;
+}
+
+/*
+ * sepgsql_avc_trusted_proc
+ *
+ * If the supplied function OID is configured as a trusted procedure, this
+ * function will return a security label to be used during the execution of
+ * that function. Otherwise, it returns NULL.
+ */
+char *
+sepgsql_avc_trusted_proc(Oid functionId)
+{
+ char *scontext = sepgsql_get_client_label();
+ char *tcontext;
+ ObjectAddress tobject;
+ avc_cache *cache;
+
+ tobject.classId = ProcedureRelationId;
+ tobject.objectId = functionId;
+ tobject.objectSubId = 0;
+ tcontext = GetSecurityLabel(&tobject, SEPGSQL_LABEL_TAG);
+
+ sepgsql_avc_check_valid();
+ do
+ {
+ if (tcontext)
+ cache = sepgsql_avc_lookup(scontext, tcontext,
+ SEPG_CLASS_DB_PROCEDURE);
+ else
+ cache = sepgsql_avc_lookup(scontext, sepgsql_avc_unlabeled(),
+ SEPG_CLASS_DB_PROCEDURE);
+ } while (!sepgsql_avc_check_valid());
+
+ return cache->ncontext;
+}
+
+/*
+ * sepgsql_avc_exit
+ *
+ * Clean up userspace AVC on process exit.
+ */
+static void
+sepgsql_avc_exit(int code, Datum arg)
+{
+ selinux_status_close();
+}
+
+/*
+ * sepgsql_avc_init
+ *
+ * Initialize the userspace AVC. This should be called from _PG_init.
+ */
+void
+sepgsql_avc_init(void)
+{
+ int rc;
+
+ /*
+ * All the avc stuff shall be allocated in avc_mem_cxt
+ */
+ avc_mem_cxt = AllocSetContextCreate(TopMemoryContext,
+ "userspace access vector cache",
+ ALLOCSET_DEFAULT_SIZES);
+ memset(avc_slots, 0, sizeof(avc_slots));
+ avc_num_caches = 0;
+ avc_lru_hint = 0;
+ avc_threshold = AVC_DEF_THRESHOLD;
+
+ /*
+ * SELinux allows to mmap(2) its kernel status page in read-only mode to
+ * inform userspace applications its status updating (such as policy
+ * reloading) without system-call invocations. This feature is only
+ * supported in Linux-2.6.38 or later, however, libselinux provides a
+ * fallback mode to know its status using netlink sockets.
+ */
+ rc = selinux_status_open(1);
+ if (rc < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("SELinux: could not open selinux status : %m")));
+ else if (rc > 0)
+ ereport(LOG,
+ (errmsg("SELinux: kernel status page uses fallback mode")));
+
+ /* Arrange to close selinux status page on process exit. */
+ on_proc_exit(sepgsql_avc_exit, 0);
+}