/* * 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: true, if caller wants to raise an error on access violation */ bool sepgsql_check_perms(const char *scontext, const char *tcontext, uint16 tclass, uint32 required, const char *audit_name, bool abort) { 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) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("SELinux: security policy violation"))); 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) { Oid relnamespace = get_rel_namespace(relOid); if (IsSystemNamespace(relnamespace) && (required & (SEPG_DB_TABLE__UPDATE | SEPG_DB_TABLE__INSERT | SEPG_DB_TABLE__DELETE)) != 0) 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; }