From ce496c4dbc226a0e1110d368de9f4bf80639e42b Mon Sep 17 00:00:00 2001 From: Yuli Khodorkovskiy 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