Example #1
0
/*
 * 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;
}
Example #2
0
/*
 * 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;
}