0001-Use-MAC-in-addition-to-DAC-for-TRUNCATE.patch

application/octet-stream

Filename: 0001-Use-MAC-in-addition-to-DAC-for-TRUNCATE.patch
Type: application/octet-stream
Part: 0
Message: add a MAC check for TRUNCATE

Patch

Format: format-patch
Series: patch 0001
Subject: Use MAC in addition to DAC for TRUNCATE
File+
contrib/sepgsql/hooks.c 14 0
contrib/sepgsql/relation.c 40 0
contrib/sepgsql/selinux.c 3 0
contrib/sepgsql/sepgsql.h 2 0
src/backend/catalog/objectaccess.c 17 0
src/backend/commands/tablecmds.c 2 0
src/include/catalog/objectaccess.h 9 1
From ce496c4dbc226a0e1110d368de9f4bf80639e42b Mon Sep 17 00:00:00 2001
From: Yuli Khodorkovskiy <yuli@crunchydata.com>
Date: Mon, 15 Jul 2019 13:58:51 -0400
Subject: [PATCH] Use MAC in addition to DAC for TRUNCATE

All DAC checks need to have corresponding MAC. The command
`TRUNCATE` is missing this check. This patch adds a new hook to
allow extensions to implement an access check for TRUNCATE.

Additionaly, update sepgsql and create a new SELinux permission
check for TRUNCATE. Since refpolicy and Redhat do not currently
have this permission implemented, access checks on TRUNCATE will be
denied unless the system's `/sys/fs/selinux/deny_unknown` flag is
set to 0.
---
 contrib/sepgsql/hooks.c            | 14 +++++++++++
 contrib/sepgsql/relation.c         | 40 ++++++++++++++++++++++++++++++
 contrib/sepgsql/selinux.c          |  3 +++
 contrib/sepgsql/sepgsql.h          |  2 ++
 src/backend/catalog/objectaccess.c | 17 +++++++++++++
 src/backend/commands/tablecmds.c   |  2 ++
 src/include/catalog/objectaccess.h | 10 +++++++-
 7 files changed, 87 insertions(+), 1 deletion(-)

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..d6170c6530 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:{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
  *
diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c
index fbc044e818..651d13ecff 100644
--- a/contrib/sepgsql/selinux.c
+++ b/contrib/sepgsql/selinux.c
@@ -359,6 +359,9 @@ static struct
 			{
 				"lock", SEPG_DB_TABLE__LOCK
 			},
+			{
+				"truncate", SEPG_DB_TABLE__TRUNCATE
+			},
 			{
 				NULL, 0UL
 			},
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 7197e3cdf0..5b55299a41 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -145,6 +145,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)
@@ -312,6 +313,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/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index b1619b859f..066fe6a37f 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -13,6 +13,7 @@
 #include "catalog/objectaccess.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_proc.h"
+#include "catalog/pg_class.h"
 
 /*
  * Hook on object accesses.  This is intended as infrastructure for security
@@ -64,6 +65,22 @@ RunObjectDropHook(Oid classId, Oid objectId, int subId,
 						   (void *) &drop_arg);
 }
 
+/*
+ * RunObjectTruncateHook
+ *
+ * It is the entrypoint of a TRUNCATE event
+ */
+void
+RunObjectTruncateHook(Oid objectId)
+{
+	/* caller should check, but just in case... */
+	Assert(object_access_hook != NULL);
+
+	(*object_access_hook) (OAT_TRUNCATE,
+						   RelationRelationId, objectId, 0,
+						   NULL);
+}
+
 /*
  * RunObjectPostAlterHook
  *
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ba59fc708a..748e7df6e0 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1915,6 +1915,8 @@ truncate_check_rel(Oid relid, Form_pg_class reltuple)
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied: \"%s\" is a system catalog",
 						relname)));
+
+	InvokeObjectTruncateHook(relid);
 }
 
 /*
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 0170f1f1e4..776120343b 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -45,7 +45,8 @@ typedef enum ObjectAccessType
 	OAT_DROP,
 	OAT_POST_ALTER,
 	OAT_NAMESPACE_SEARCH,
-	OAT_FUNCTION_EXECUTE
+	OAT_FUNCTION_EXECUTE,
+	OAT_TRUNCATE
 } ObjectAccessType;
 
 /*
@@ -131,6 +132,7 @@ extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
 									bool is_internal);
 extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  int dropflags);
+extern void RunObjectTruncateHook(Oid objectId);
 extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
 								   Oid auxiliaryId, bool is_internal);
 extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation);
@@ -160,6 +162,12 @@ extern void RunFunctionExecuteHook(Oid objectId);
 							  (dropflags));							\
 	} while(0)
 
+#define InvokeObjectTruncateHook(objectId)							\
+	do {															\
+		if (object_access_hook)										\
+			RunObjectTruncateHook(objectId);						\
+	} while(0)
+
 #define InvokeObjectPostAlterHook(classId,objectId,subId)			\
 	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),		\
 								 InvalidOid,false)
-- 
2.19.0