From 08aeaf27c3181fc42ebc9c44e612b1e5229866bc Mon Sep 17 00:00:00 2001
From: Yuli Khodorkovskiy <yuli@crunchydata.com>
Date: Mon, 26 Aug 2019 04:45:42 -0700
Subject: [PATCH 2/2] Update sepgsql to add MAC for TRUNCATE

- Use `db_table: { delete }` to check if permission is granted to TRUNCATE.
- Update regression tests to demonstrate a positive and negative test case
  for TRUNCATE.
- Update example SELinux policy to deny sepgsql_regtest_dba_t TRUNCATE.
---
 contrib/sepgsql/expected/dml.out   |  3 +++
 contrib/sepgsql/hooks.c            | 14 +++++++++++
 contrib/sepgsql/relation.c         | 40 ++++++++++++++++++++++++++++++
 contrib/sepgsql/sepgsql-regtest.te |  2 +-
 contrib/sepgsql/sepgsql.h          |  1 +
 contrib/sepgsql/sql/dml.sql        |  2 ++
 6 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/contrib/sepgsql/expected/dml.out b/contrib/sepgsql/expected/dml.out
index 31243c723b..250378a5b9 100644
--- a/contrib/sepgsql/expected/dml.out
+++ b/contrib/sepgsql/expected/dml.out
@@ -227,6 +227,9 @@ 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
+TRUNCATE TABLE t4;				-- ok
+ERROR:  SELinux: security policy violation
+TRUNCATE TABLE t5;				-- failed
 ---
 -- partitioned table parent
 INSERT INTO t1p (o,p) VALUES (9, 'mno');		-- failed
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index ebfa441b47..6f6afa2c04 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -189,6 +189,20 @@ sepgsql_object_access(ObjectAccessType access,
 			}
 			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;
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 061527559c..620fe969ad 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -517,6 +517,46 @@ sepgsql_relation_drop(Oid relOid)
 	}
 }
 
+/*
+ * 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:{delete} permission
+	 */
+	object.classId = RelationRelationId;
+	object.objectId = relOid;
+	object.objectSubId = 0;
+	audit_name = getObjectIdentity(&object);
+
+	sepgsql_avc_check_perms(&object,
+							tclass,
+							SEPG_DB_TABLE__DELETE,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
 /*
  * sepgsql_relation_relabel
  *
diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te
index 5d9af1a0dd..5991573c9b 100644
--- a/contrib/sepgsql/sepgsql-regtest.te
+++ b/contrib/sepgsql/sepgsql-regtest.te
@@ -146,7 +146,7 @@ allow sepgsql_regtest_foo_t sepgsql_regtest_foo_table_t:db_table { getattr selec
 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_table { getattr select update insert 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 };
 
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 4787934650..3bf84f3617 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -312,6 +312,7 @@ extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 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);
 
diff --git a/contrib/sepgsql/sql/dml.sql b/contrib/sepgsql/sql/dml.sql
index 19201f4b90..120b7a9aa5 100644
--- a/contrib/sepgsql/sql/dml.sql
+++ b/contrib/sepgsql/sql/dml.sql
@@ -133,6 +133,8 @@ 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
+TRUNCATE TABLE t4;				-- ok
+TRUNCATE TABLE t5;				-- failed
 
 ---
 -- partitioned table parent
-- 
2.21.0

