16cd6a6acSopenharmony_ci/* Authors: Joshua Brindle <jbrindle@tresys.com>
26cd6a6acSopenharmony_ci *
36cd6a6acSopenharmony_ci * Assertion checker for avtab entries, taken from
46cd6a6acSopenharmony_ci * checkpolicy.c by Stephen Smalley <sds@tycho.nsa.gov>
56cd6a6acSopenharmony_ci *
66cd6a6acSopenharmony_ci * Copyright (C) 2005 Tresys Technology, LLC
76cd6a6acSopenharmony_ci *
86cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
96cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
106cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
116cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
126cd6a6acSopenharmony_ci *
136cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
146cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
156cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
166cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
176cd6a6acSopenharmony_ci *
186cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
196cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
206cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
216cd6a6acSopenharmony_ci */
226cd6a6acSopenharmony_ci
236cd6a6acSopenharmony_ci#include <sepol/policydb/avtab.h>
246cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
256cd6a6acSopenharmony_ci#include <sepol/policydb/expand.h>
266cd6a6acSopenharmony_ci#include <sepol/policydb/util.h>
276cd6a6acSopenharmony_ci
286cd6a6acSopenharmony_ci#include "private.h"
296cd6a6acSopenharmony_ci#include "debug.h"
306cd6a6acSopenharmony_ci
316cd6a6acSopenharmony_cistruct avtab_match_args {
326cd6a6acSopenharmony_ci	sepol_handle_t *handle;
336cd6a6acSopenharmony_ci	policydb_t *p;
346cd6a6acSopenharmony_ci	avrule_t *avrule;
356cd6a6acSopenharmony_ci	avtab_t *avtab;
366cd6a6acSopenharmony_ci	unsigned long errors;
376cd6a6acSopenharmony_ci};
386cd6a6acSopenharmony_ci
396cd6a6acSopenharmony_cistatic const char* policy_name(policydb_t *p) {
406cd6a6acSopenharmony_ci	const char *policy_file = "policy.conf";
416cd6a6acSopenharmony_ci	if (p->name) {
426cd6a6acSopenharmony_ci		policy_file = p->name;
436cd6a6acSopenharmony_ci	}
446cd6a6acSopenharmony_ci	return policy_file;
456cd6a6acSopenharmony_ci}
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_cistatic void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule,
486cd6a6acSopenharmony_ci			   unsigned int stype, unsigned int ttype,
496cd6a6acSopenharmony_ci			   const class_perm_node_t *curperm, uint32_t perms)
506cd6a6acSopenharmony_ci{
516cd6a6acSopenharmony_ci	if (avrule->source_filename) {
526cd6a6acSopenharmony_ci		ERR(handle, "neverallow on line %lu of %s (or line %lu of %s) violated by allow %s %s:%s {%s };",
536cd6a6acSopenharmony_ci		    avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
546cd6a6acSopenharmony_ci		    p->p_type_val_to_name[stype],
556cd6a6acSopenharmony_ci		    p->p_type_val_to_name[ttype],
566cd6a6acSopenharmony_ci		    p->p_class_val_to_name[curperm->tclass - 1],
576cd6a6acSopenharmony_ci		    sepol_av_to_string(p, curperm->tclass, perms));
586cd6a6acSopenharmony_ci	} else if (avrule->line) {
596cd6a6acSopenharmony_ci		ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
606cd6a6acSopenharmony_ci		    avrule->line, p->p_type_val_to_name[stype],
616cd6a6acSopenharmony_ci		    p->p_type_val_to_name[ttype],
626cd6a6acSopenharmony_ci		    p->p_class_val_to_name[curperm->tclass - 1],
636cd6a6acSopenharmony_ci		    sepol_av_to_string(p, curperm->tclass, perms));
646cd6a6acSopenharmony_ci	} else {
656cd6a6acSopenharmony_ci		ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
666cd6a6acSopenharmony_ci		    p->p_type_val_to_name[stype],
676cd6a6acSopenharmony_ci		    p->p_type_val_to_name[ttype],
686cd6a6acSopenharmony_ci		    p->p_class_val_to_name[curperm->tclass - 1],
696cd6a6acSopenharmony_ci		    sepol_av_to_string(p, curperm->tclass, perms));
706cd6a6acSopenharmony_ci	}
716cd6a6acSopenharmony_ci}
726cd6a6acSopenharmony_ci
736cd6a6acSopenharmony_cistatic int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
746cd6a6acSopenharmony_ci{
756cd6a6acSopenharmony_ci	for (; cp; cp = cp->next) {
766cd6a6acSopenharmony_ci		if ((cp->tclass == class) && (cp->data & data))
776cd6a6acSopenharmony_ci			return 1;
786cd6a6acSopenharmony_ci	}
796cd6a6acSopenharmony_ci
806cd6a6acSopenharmony_ci	return 0;
816cd6a6acSopenharmony_ci}
826cd6a6acSopenharmony_ci
836cd6a6acSopenharmony_cistatic int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) {
846cd6a6acSopenharmony_ci	size_t i;
856cd6a6acSopenharmony_ci	for (i = 0; i < EXTENDED_PERMS_LEN; i++) {
866cd6a6acSopenharmony_ci		if (perms1[i] & perms2[i])
876cd6a6acSopenharmony_ci			return 1;
886cd6a6acSopenharmony_ci	}
896cd6a6acSopenharmony_ci
906cd6a6acSopenharmony_ci	return 0;
916cd6a6acSopenharmony_ci}
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_cistatic int check_extended_permissions(av_extended_perms_t *neverallow, avtab_extended_perms_t *allow)
946cd6a6acSopenharmony_ci{
956cd6a6acSopenharmony_ci	int rc = 0;
966cd6a6acSopenharmony_ci	if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
976cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
986cd6a6acSopenharmony_ci		if (neverallow->driver == allow->driver)
996cd6a6acSopenharmony_ci			rc = extended_permissions_and(neverallow->perms, allow->perms);
1006cd6a6acSopenharmony_ci	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
1016cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
1026cd6a6acSopenharmony_ci		rc = xperm_test(neverallow->driver, allow->perms);
1036cd6a6acSopenharmony_ci	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
1046cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
1056cd6a6acSopenharmony_ci		rc = xperm_test(allow->driver, neverallow->perms);
1066cd6a6acSopenharmony_ci	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
1076cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
1086cd6a6acSopenharmony_ci		rc = extended_permissions_and(neverallow->perms, allow->perms);
1096cd6a6acSopenharmony_ci	}
1106cd6a6acSopenharmony_ci
1116cd6a6acSopenharmony_ci	return rc;
1126cd6a6acSopenharmony_ci}
1136cd6a6acSopenharmony_ci
1146cd6a6acSopenharmony_ci/* Compute which allowed extended permissions violate the neverallow rule */
1156cd6a6acSopenharmony_cistatic void extended_permissions_violated(avtab_extended_perms_t *result,
1166cd6a6acSopenharmony_ci					av_extended_perms_t *neverallow,
1176cd6a6acSopenharmony_ci					avtab_extended_perms_t *allow)
1186cd6a6acSopenharmony_ci{
1196cd6a6acSopenharmony_ci	size_t i;
1206cd6a6acSopenharmony_ci	if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
1216cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
1226cd6a6acSopenharmony_ci		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
1236cd6a6acSopenharmony_ci		result->driver = allow->driver;
1246cd6a6acSopenharmony_ci		for (i = 0; i < EXTENDED_PERMS_LEN; i++)
1256cd6a6acSopenharmony_ci			result->perms[i] = neverallow->perms[i] & allow->perms[i];
1266cd6a6acSopenharmony_ci	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
1276cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
1286cd6a6acSopenharmony_ci		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
1296cd6a6acSopenharmony_ci		result->driver = neverallow->driver;
1306cd6a6acSopenharmony_ci		memcpy(result->perms, neverallow->perms, sizeof(result->perms));
1316cd6a6acSopenharmony_ci	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
1326cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
1336cd6a6acSopenharmony_ci		result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
1346cd6a6acSopenharmony_ci		result->driver = allow->driver;
1356cd6a6acSopenharmony_ci		memcpy(result->perms, allow->perms, sizeof(result->perms));
1366cd6a6acSopenharmony_ci	} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
1376cd6a6acSopenharmony_ci			&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
1386cd6a6acSopenharmony_ci		result->specified = AVTAB_XPERMS_IOCTLDRIVER;
1396cd6a6acSopenharmony_ci		for (i = 0; i < EXTENDED_PERMS_LEN; i++)
1406cd6a6acSopenharmony_ci			result->perms[i] = neverallow->perms[i] & allow->perms[i];
1416cd6a6acSopenharmony_ci	}
1426cd6a6acSopenharmony_ci}
1436cd6a6acSopenharmony_ci
1446cd6a6acSopenharmony_ci/* Same scenarios of interest as check_assertion_extended_permissions */
1456cd6a6acSopenharmony_cistatic int report_assertion_extended_permissions(sepol_handle_t *handle,
1466cd6a6acSopenharmony_ci				policydb_t *p, const avrule_t *avrule,
1476cd6a6acSopenharmony_ci				unsigned int stype, unsigned int ttype,
1486cd6a6acSopenharmony_ci				const class_perm_node_t *curperm, uint32_t perms,
1496cd6a6acSopenharmony_ci				avtab_key_t *k, avtab_t *avtab)
1506cd6a6acSopenharmony_ci{
1516cd6a6acSopenharmony_ci	avtab_ptr_t node;
1526cd6a6acSopenharmony_ci	avtab_key_t tmp_key;
1536cd6a6acSopenharmony_ci	avtab_extended_perms_t *xperms;
1546cd6a6acSopenharmony_ci	avtab_extended_perms_t error;
1556cd6a6acSopenharmony_ci	ebitmap_t *sattr = &p->type_attr_map[stype];
1566cd6a6acSopenharmony_ci	ebitmap_t *tattr = &p->type_attr_map[ttype];
1576cd6a6acSopenharmony_ci	ebitmap_node_t *snode, *tnode;
1586cd6a6acSopenharmony_ci	unsigned int i, j;
1596cd6a6acSopenharmony_ci	int rc;
1606cd6a6acSopenharmony_ci	int found_xperm = 0;
1616cd6a6acSopenharmony_ci	int errors = 0;
1626cd6a6acSopenharmony_ci
1636cd6a6acSopenharmony_ci	memcpy(&tmp_key, k, sizeof(avtab_key_t));
1646cd6a6acSopenharmony_ci	tmp_key.specified = AVTAB_XPERMS_ALLOWED;
1656cd6a6acSopenharmony_ci
1666cd6a6acSopenharmony_ci	ebitmap_for_each_positive_bit(sattr, snode, i) {
1676cd6a6acSopenharmony_ci		tmp_key.source_type = i + 1;
1686cd6a6acSopenharmony_ci		ebitmap_for_each_positive_bit(tattr, tnode, j) {
1696cd6a6acSopenharmony_ci			tmp_key.target_type = j + 1;
1706cd6a6acSopenharmony_ci			for (node = avtab_search_node(avtab, &tmp_key);
1716cd6a6acSopenharmony_ci			     node;
1726cd6a6acSopenharmony_ci			     node = avtab_search_node_next(node, tmp_key.specified)) {
1736cd6a6acSopenharmony_ci				xperms = node->datum.xperms;
1746cd6a6acSopenharmony_ci				if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
1756cd6a6acSopenharmony_ci						&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
1766cd6a6acSopenharmony_ci					continue;
1776cd6a6acSopenharmony_ci				found_xperm = 1;
1786cd6a6acSopenharmony_ci				rc = check_extended_permissions(avrule->xperms, xperms);
1796cd6a6acSopenharmony_ci				/* failure on the extended permission check_extended_permissions */
1806cd6a6acSopenharmony_ci				if (rc) {
1816cd6a6acSopenharmony_ci					extended_permissions_violated(&error, avrule->xperms, xperms);
1826cd6a6acSopenharmony_ci					ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n"
1836cd6a6acSopenharmony_ci							"allowxperm %s %s:%s %s;",
1846cd6a6acSopenharmony_ci							avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
1856cd6a6acSopenharmony_ci							p->p_type_val_to_name[i],
1866cd6a6acSopenharmony_ci							p->p_type_val_to_name[j],
1876cd6a6acSopenharmony_ci							p->p_class_val_to_name[curperm->tclass - 1],
1886cd6a6acSopenharmony_ci							sepol_extended_perms_to_string(&error));
1896cd6a6acSopenharmony_ci
1906cd6a6acSopenharmony_ci					errors++;
1916cd6a6acSopenharmony_ci				}
1926cd6a6acSopenharmony_ci			}
1936cd6a6acSopenharmony_ci		}
1946cd6a6acSopenharmony_ci	}
1956cd6a6acSopenharmony_ci
1966cd6a6acSopenharmony_ci	/* failure on the regular permissions */
1976cd6a6acSopenharmony_ci	if (!found_xperm) {
1986cd6a6acSopenharmony_ci		ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n"
1996cd6a6acSopenharmony_ci				"allow %s %s:%s {%s };",
2006cd6a6acSopenharmony_ci				avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
2016cd6a6acSopenharmony_ci				p->p_type_val_to_name[stype],
2026cd6a6acSopenharmony_ci				p->p_type_val_to_name[ttype],
2036cd6a6acSopenharmony_ci				p->p_class_val_to_name[curperm->tclass - 1],
2046cd6a6acSopenharmony_ci				sepol_av_to_string(p, curperm->tclass, perms));
2056cd6a6acSopenharmony_ci		errors++;
2066cd6a6acSopenharmony_ci
2076cd6a6acSopenharmony_ci	}
2086cd6a6acSopenharmony_ci
2096cd6a6acSopenharmony_ci	return errors;
2106cd6a6acSopenharmony_ci}
2116cd6a6acSopenharmony_ci
2126cd6a6acSopenharmony_cistatic int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
2136cd6a6acSopenharmony_ci{
2146cd6a6acSopenharmony_ci	int rc = 0;
2156cd6a6acSopenharmony_ci	struct avtab_match_args *a = (struct avtab_match_args *)args;
2166cd6a6acSopenharmony_ci	sepol_handle_t *handle = a->handle;
2176cd6a6acSopenharmony_ci	policydb_t *p = a->p;
2186cd6a6acSopenharmony_ci	avtab_t *avtab = a->avtab;
2196cd6a6acSopenharmony_ci	avrule_t *avrule = a->avrule;
2206cd6a6acSopenharmony_ci	class_perm_node_t *cp;
2216cd6a6acSopenharmony_ci	uint32_t perms;
2226cd6a6acSopenharmony_ci	ebitmap_t src_matches, tgt_matches, self_matches;
2236cd6a6acSopenharmony_ci	ebitmap_node_t *snode, *tnode;
2246cd6a6acSopenharmony_ci	unsigned int i, j;
2256cd6a6acSopenharmony_ci	const int is_avrule_self = (avrule->flags & RULE_SELF) != 0;
2266cd6a6acSopenharmony_ci
2276cd6a6acSopenharmony_ci	if ((k->specified & AVTAB_ALLOWED) == 0)
2286cd6a6acSopenharmony_ci		return 0;
2296cd6a6acSopenharmony_ci
2306cd6a6acSopenharmony_ci	if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
2316cd6a6acSopenharmony_ci		return 0;
2326cd6a6acSopenharmony_ci
2336cd6a6acSopenharmony_ci	ebitmap_init(&src_matches);
2346cd6a6acSopenharmony_ci	ebitmap_init(&tgt_matches);
2356cd6a6acSopenharmony_ci	ebitmap_init(&self_matches);
2366cd6a6acSopenharmony_ci
2376cd6a6acSopenharmony_ci	rc = ebitmap_and(&src_matches, &avrule->stypes.types,
2386cd6a6acSopenharmony_ci			 &p->attr_type_map[k->source_type - 1]);
2396cd6a6acSopenharmony_ci	if (rc < 0)
2406cd6a6acSopenharmony_ci		goto oom;
2416cd6a6acSopenharmony_ci
2426cd6a6acSopenharmony_ci	if (ebitmap_is_empty(&src_matches))
2436cd6a6acSopenharmony_ci		goto exit;
2446cd6a6acSopenharmony_ci
2456cd6a6acSopenharmony_ci	rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
2466cd6a6acSopenharmony_ci	if (rc < 0)
2476cd6a6acSopenharmony_ci		goto oom;
2486cd6a6acSopenharmony_ci
2496cd6a6acSopenharmony_ci	if (is_avrule_self) {
2506cd6a6acSopenharmony_ci		rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]);
2516cd6a6acSopenharmony_ci		if (rc < 0)
2526cd6a6acSopenharmony_ci			goto oom;
2536cd6a6acSopenharmony_ci
2546cd6a6acSopenharmony_ci		if (!ebitmap_is_empty(&self_matches)) {
2556cd6a6acSopenharmony_ci			rc = ebitmap_union(&tgt_matches, &self_matches);
2566cd6a6acSopenharmony_ci			if (rc < 0)
2576cd6a6acSopenharmony_ci				goto oom;
2586cd6a6acSopenharmony_ci		}
2596cd6a6acSopenharmony_ci	}
2606cd6a6acSopenharmony_ci
2616cd6a6acSopenharmony_ci	if (ebitmap_is_empty(&tgt_matches))
2626cd6a6acSopenharmony_ci		goto exit;
2636cd6a6acSopenharmony_ci
2646cd6a6acSopenharmony_ci	for (cp = avrule->perms; cp; cp = cp->next) {
2656cd6a6acSopenharmony_ci
2666cd6a6acSopenharmony_ci		perms = cp->data & d->data;
2676cd6a6acSopenharmony_ci		if ((cp->tclass != k->target_class) || !perms) {
2686cd6a6acSopenharmony_ci			continue;
2696cd6a6acSopenharmony_ci		}
2706cd6a6acSopenharmony_ci
2716cd6a6acSopenharmony_ci		ebitmap_for_each_positive_bit(&src_matches, snode, i) {
2726cd6a6acSopenharmony_ci			ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) {
2736cd6a6acSopenharmony_ci				if (is_avrule_self && i != j)
2746cd6a6acSopenharmony_ci					continue;
2756cd6a6acSopenharmony_ci				if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
2766cd6a6acSopenharmony_ci					a->errors += report_assertion_extended_permissions(handle,p, avrule,
2776cd6a6acSopenharmony_ci											i, j, cp, perms, k, avtab);
2786cd6a6acSopenharmony_ci				} else {
2796cd6a6acSopenharmony_ci					a->errors++;
2806cd6a6acSopenharmony_ci					report_failure(handle, p, avrule, i, j, cp, perms);
2816cd6a6acSopenharmony_ci				}
2826cd6a6acSopenharmony_ci			}
2836cd6a6acSopenharmony_ci		}
2846cd6a6acSopenharmony_ci	}
2856cd6a6acSopenharmony_ci
2866cd6a6acSopenharmony_cioom:
2876cd6a6acSopenharmony_ciexit:
2886cd6a6acSopenharmony_ci	ebitmap_destroy(&src_matches);
2896cd6a6acSopenharmony_ci	ebitmap_destroy(&tgt_matches);
2906cd6a6acSopenharmony_ci	ebitmap_destroy(&self_matches);
2916cd6a6acSopenharmony_ci	return rc;
2926cd6a6acSopenharmony_ci}
2936cd6a6acSopenharmony_ci
2946cd6a6acSopenharmony_cistatic int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
2956cd6a6acSopenharmony_ci{
2966cd6a6acSopenharmony_ci	int rc;
2976cd6a6acSopenharmony_ci	struct avtab_match_args args;
2986cd6a6acSopenharmony_ci
2996cd6a6acSopenharmony_ci	args.handle = handle;
3006cd6a6acSopenharmony_ci	args.p = p;
3016cd6a6acSopenharmony_ci	args.avrule = avrule;
3026cd6a6acSopenharmony_ci	args.errors = 0;
3036cd6a6acSopenharmony_ci
3046cd6a6acSopenharmony_ci	args.avtab =  &p->te_avtab;
3056cd6a6acSopenharmony_ci	rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args);
3066cd6a6acSopenharmony_ci	if (rc < 0)
3076cd6a6acSopenharmony_ci		goto oom;
3086cd6a6acSopenharmony_ci
3096cd6a6acSopenharmony_ci	args.avtab =  &p->te_cond_avtab;
3106cd6a6acSopenharmony_ci	rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args);
3116cd6a6acSopenharmony_ci	if (rc < 0)
3126cd6a6acSopenharmony_ci		goto oom;
3136cd6a6acSopenharmony_ci
3146cd6a6acSopenharmony_ci	return args.errors;
3156cd6a6acSopenharmony_ci
3166cd6a6acSopenharmony_cioom:
3176cd6a6acSopenharmony_ci	return rc;
3186cd6a6acSopenharmony_ci}
3196cd6a6acSopenharmony_ci
3206cd6a6acSopenharmony_ci/*
3216cd6a6acSopenharmony_ci * Look up the extended permissions in avtab and verify that neverallowed
3226cd6a6acSopenharmony_ci * permissions are not granted.
3236cd6a6acSopenharmony_ci */
3246cd6a6acSopenharmony_cistatic int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t *avtab,
3256cd6a6acSopenharmony_ci						unsigned int stype, unsigned int ttype,
3266cd6a6acSopenharmony_ci						avtab_key_t *k, policydb_t *p)
3276cd6a6acSopenharmony_ci{
3286cd6a6acSopenharmony_ci	avtab_ptr_t node;
3296cd6a6acSopenharmony_ci	avtab_key_t tmp_key;
3306cd6a6acSopenharmony_ci	avtab_extended_perms_t *xperms;
3316cd6a6acSopenharmony_ci	av_extended_perms_t *neverallow_xperms = avrule->xperms;
3326cd6a6acSopenharmony_ci	ebitmap_t *sattr = &p->type_attr_map[stype];
3336cd6a6acSopenharmony_ci	ebitmap_t *tattr = &p->type_attr_map[ttype];
3346cd6a6acSopenharmony_ci	ebitmap_node_t *snode, *tnode;
3356cd6a6acSopenharmony_ci	unsigned int i, j;
3366cd6a6acSopenharmony_ci	int rc = 1;
3376cd6a6acSopenharmony_ci
3386cd6a6acSopenharmony_ci	memcpy(&tmp_key, k, sizeof(avtab_key_t));
3396cd6a6acSopenharmony_ci	tmp_key.specified = AVTAB_XPERMS_ALLOWED;
3406cd6a6acSopenharmony_ci
3416cd6a6acSopenharmony_ci	ebitmap_for_each_positive_bit(sattr, snode, i) {
3426cd6a6acSopenharmony_ci		tmp_key.source_type = i + 1;
3436cd6a6acSopenharmony_ci		ebitmap_for_each_positive_bit(tattr, tnode, j) {
3446cd6a6acSopenharmony_ci			tmp_key.target_type = j + 1;
3456cd6a6acSopenharmony_ci			for (node = avtab_search_node(avtab, &tmp_key);
3466cd6a6acSopenharmony_ci			     node;
3476cd6a6acSopenharmony_ci			     node = avtab_search_node_next(node, tmp_key.specified)) {
3486cd6a6acSopenharmony_ci				xperms = node->datum.xperms;
3496cd6a6acSopenharmony_ci
3506cd6a6acSopenharmony_ci				if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
3516cd6a6acSopenharmony_ci						&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
3526cd6a6acSopenharmony_ci					continue;
3536cd6a6acSopenharmony_ci				rc = check_extended_permissions(neverallow_xperms, xperms);
3546cd6a6acSopenharmony_ci				if (rc)
3556cd6a6acSopenharmony_ci					return rc;
3566cd6a6acSopenharmony_ci			}
3576cd6a6acSopenharmony_ci		}
3586cd6a6acSopenharmony_ci	}
3596cd6a6acSopenharmony_ci
3606cd6a6acSopenharmony_ci	return rc;
3616cd6a6acSopenharmony_ci}
3626cd6a6acSopenharmony_ci
3636cd6a6acSopenharmony_ci/*
3646cd6a6acSopenharmony_ci * When the ioctl permission is granted on an avtab entry that matches an
3656cd6a6acSopenharmony_ci * avrule neverallowxperm entry, enumerate over the matching
3666cd6a6acSopenharmony_ci * source/target/class sets to determine if the extended permissions exist
3676cd6a6acSopenharmony_ci * and if the neverallowed ioctls are granted.
3686cd6a6acSopenharmony_ci *
3696cd6a6acSopenharmony_ci * Four scenarios of interest:
3706cd6a6acSopenharmony_ci * 1. PASS - the ioctl permission is not granted for this source/target/class
3716cd6a6acSopenharmony_ci *    This case is handled in check_assertion_avtab_match
3726cd6a6acSopenharmony_ci * 2. PASS - The ioctl permission is granted AND the extended permission
3736cd6a6acSopenharmony_ci *    is NOT granted
3746cd6a6acSopenharmony_ci * 3. FAIL - The ioctl permission is granted AND no extended permissions
3756cd6a6acSopenharmony_ci *    exist
3766cd6a6acSopenharmony_ci * 4. FAIL - The ioctl permission is granted AND the extended permission is
3776cd6a6acSopenharmony_ci *    granted
3786cd6a6acSopenharmony_ci */
3796cd6a6acSopenharmony_cistatic int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab,
3806cd6a6acSopenharmony_ci						avtab_key_t *k, policydb_t *p)
3816cd6a6acSopenharmony_ci{
3826cd6a6acSopenharmony_ci	ebitmap_t src_matches, tgt_matches, self_matches;
3836cd6a6acSopenharmony_ci	unsigned int i, j;
3846cd6a6acSopenharmony_ci	ebitmap_node_t *snode, *tnode;
3856cd6a6acSopenharmony_ci	const int is_avrule_self = (avrule->flags & RULE_SELF) != 0;
3866cd6a6acSopenharmony_ci	int rc;
3876cd6a6acSopenharmony_ci
3886cd6a6acSopenharmony_ci	ebitmap_init(&src_matches);
3896cd6a6acSopenharmony_ci	ebitmap_init(&tgt_matches);
3906cd6a6acSopenharmony_ci	ebitmap_init(&self_matches);
3916cd6a6acSopenharmony_ci
3926cd6a6acSopenharmony_ci	rc = ebitmap_and(&src_matches, &avrule->stypes.types,
3936cd6a6acSopenharmony_ci			 &p->attr_type_map[k->source_type - 1]);
3946cd6a6acSopenharmony_ci	if (rc < 0)
3956cd6a6acSopenharmony_ci		goto oom;
3966cd6a6acSopenharmony_ci
3976cd6a6acSopenharmony_ci	if (ebitmap_is_empty(&src_matches)) {
3986cd6a6acSopenharmony_ci		rc = 0;
3996cd6a6acSopenharmony_ci		goto exit;
4006cd6a6acSopenharmony_ci	}
4016cd6a6acSopenharmony_ci
4026cd6a6acSopenharmony_ci	rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types,
4036cd6a6acSopenharmony_ci			 &p->attr_type_map[k->target_type -1]);
4046cd6a6acSopenharmony_ci	if (rc < 0)
4056cd6a6acSopenharmony_ci		goto oom;
4066cd6a6acSopenharmony_ci
4076cd6a6acSopenharmony_ci	if (is_avrule_self) {
4086cd6a6acSopenharmony_ci		rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]);
4096cd6a6acSopenharmony_ci		if (rc < 0)
4106cd6a6acSopenharmony_ci			goto oom;
4116cd6a6acSopenharmony_ci
4126cd6a6acSopenharmony_ci		if (!ebitmap_is_empty(&self_matches)) {
4136cd6a6acSopenharmony_ci			rc = ebitmap_union(&tgt_matches, &self_matches);
4146cd6a6acSopenharmony_ci			if (rc < 0)
4156cd6a6acSopenharmony_ci				goto oom;
4166cd6a6acSopenharmony_ci		}
4176cd6a6acSopenharmony_ci	}
4186cd6a6acSopenharmony_ci
4196cd6a6acSopenharmony_ci	if (ebitmap_is_empty(&tgt_matches)) {
4206cd6a6acSopenharmony_ci		rc = 0;
4216cd6a6acSopenharmony_ci		goto exit;
4226cd6a6acSopenharmony_ci	}
4236cd6a6acSopenharmony_ci
4246cd6a6acSopenharmony_ci	ebitmap_for_each_positive_bit(&src_matches, snode, i) {
4256cd6a6acSopenharmony_ci		ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) {
4266cd6a6acSopenharmony_ci			if (is_avrule_self && i != j)
4276cd6a6acSopenharmony_ci				continue;
4286cd6a6acSopenharmony_ci			if (check_assertion_extended_permissions_avtab(avrule, avtab, i, j, k, p)) {
4296cd6a6acSopenharmony_ci				rc = 1;
4306cd6a6acSopenharmony_ci				goto exit;
4316cd6a6acSopenharmony_ci			}
4326cd6a6acSopenharmony_ci		}
4336cd6a6acSopenharmony_ci	}
4346cd6a6acSopenharmony_ci
4356cd6a6acSopenharmony_ci	rc = 0;
4366cd6a6acSopenharmony_ci
4376cd6a6acSopenharmony_cioom:
4386cd6a6acSopenharmony_ciexit:
4396cd6a6acSopenharmony_ci	ebitmap_destroy(&src_matches);
4406cd6a6acSopenharmony_ci	ebitmap_destroy(&tgt_matches);
4416cd6a6acSopenharmony_ci	ebitmap_destroy(&self_matches);
4426cd6a6acSopenharmony_ci	return rc;
4436cd6a6acSopenharmony_ci}
4446cd6a6acSopenharmony_ci
4456cd6a6acSopenharmony_cistatic int check_assertion_self_match(avtab_key_t *k, avrule_t *avrule, policydb_t *p)
4466cd6a6acSopenharmony_ci{
4476cd6a6acSopenharmony_ci	ebitmap_t src_matches;
4486cd6a6acSopenharmony_ci	int rc;
4496cd6a6acSopenharmony_ci
4506cd6a6acSopenharmony_ci	/* The key's target must match something in the matches of the avrule's source
4516cd6a6acSopenharmony_ci	 * and the key's source.
4526cd6a6acSopenharmony_ci	 */
4536cd6a6acSopenharmony_ci
4546cd6a6acSopenharmony_ci	rc = ebitmap_and(&src_matches, &avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
4556cd6a6acSopenharmony_ci	if (rc < 0)
4566cd6a6acSopenharmony_ci		goto oom;
4576cd6a6acSopenharmony_ci
4586cd6a6acSopenharmony_ci	if (!ebitmap_match_any(&src_matches, &p->attr_type_map[k->target_type - 1])) {
4596cd6a6acSopenharmony_ci		rc = 0;
4606cd6a6acSopenharmony_ci		goto nomatch;
4616cd6a6acSopenharmony_ci	}
4626cd6a6acSopenharmony_ci
4636cd6a6acSopenharmony_ci	rc = 1;
4646cd6a6acSopenharmony_ci
4656cd6a6acSopenharmony_cioom:
4666cd6a6acSopenharmony_cinomatch:
4676cd6a6acSopenharmony_ci	ebitmap_destroy(&src_matches);
4686cd6a6acSopenharmony_ci	return rc;
4696cd6a6acSopenharmony_ci}
4706cd6a6acSopenharmony_ci
4716cd6a6acSopenharmony_cistatic int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
4726cd6a6acSopenharmony_ci{
4736cd6a6acSopenharmony_ci	int rc;
4746cd6a6acSopenharmony_ci	struct avtab_match_args *a = (struct avtab_match_args *)args;
4756cd6a6acSopenharmony_ci	policydb_t *p = a->p;
4766cd6a6acSopenharmony_ci	avrule_t *avrule = a->avrule;
4776cd6a6acSopenharmony_ci	avtab_t *avtab = a->avtab;
4786cd6a6acSopenharmony_ci
4796cd6a6acSopenharmony_ci	if ((k->specified & AVTAB_ALLOWED) == 0)
4806cd6a6acSopenharmony_ci		goto nomatch;
4816cd6a6acSopenharmony_ci
4826cd6a6acSopenharmony_ci	if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
4836cd6a6acSopenharmony_ci		goto nomatch;
4846cd6a6acSopenharmony_ci
4856cd6a6acSopenharmony_ci	if (!ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]))
4866cd6a6acSopenharmony_ci		goto nomatch;
4876cd6a6acSopenharmony_ci
4886cd6a6acSopenharmony_ci	/* neverallow may have tgts even if it uses SELF */
4896cd6a6acSopenharmony_ci	if (!ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1])) {
4906cd6a6acSopenharmony_ci		if (avrule->flags == RULE_SELF) {
4916cd6a6acSopenharmony_ci			rc = check_assertion_self_match(k, avrule, p);
4926cd6a6acSopenharmony_ci			if (rc < 0)
4936cd6a6acSopenharmony_ci				goto oom;
4946cd6a6acSopenharmony_ci			if (rc == 0)
4956cd6a6acSopenharmony_ci				goto nomatch;
4966cd6a6acSopenharmony_ci		} else {
4976cd6a6acSopenharmony_ci			goto nomatch;
4986cd6a6acSopenharmony_ci		}
4996cd6a6acSopenharmony_ci	}
5006cd6a6acSopenharmony_ci
5016cd6a6acSopenharmony_ci	if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
5026cd6a6acSopenharmony_ci		rc = check_assertion_extended_permissions(avrule, avtab, k, p);
5036cd6a6acSopenharmony_ci		if (rc < 0)
5046cd6a6acSopenharmony_ci			goto oom;
5056cd6a6acSopenharmony_ci		if (rc == 0)
5066cd6a6acSopenharmony_ci			goto nomatch;
5076cd6a6acSopenharmony_ci	}
5086cd6a6acSopenharmony_ci	return 1;
5096cd6a6acSopenharmony_ci
5106cd6a6acSopenharmony_cinomatch:
5116cd6a6acSopenharmony_ci	return 0;
5126cd6a6acSopenharmony_ci
5136cd6a6acSopenharmony_cioom:
5146cd6a6acSopenharmony_ci	return rc;
5156cd6a6acSopenharmony_ci}
5166cd6a6acSopenharmony_ci
5176cd6a6acSopenharmony_ciint check_assertion(policydb_t *p, avrule_t *avrule)
5186cd6a6acSopenharmony_ci{
5196cd6a6acSopenharmony_ci	int rc;
5206cd6a6acSopenharmony_ci	struct avtab_match_args args;
5216cd6a6acSopenharmony_ci
5226cd6a6acSopenharmony_ci	args.handle = NULL;
5236cd6a6acSopenharmony_ci	args.p = p;
5246cd6a6acSopenharmony_ci	args.avrule = avrule;
5256cd6a6acSopenharmony_ci	args.errors = 0;
5266cd6a6acSopenharmony_ci	args.avtab = &p->te_avtab;
5276cd6a6acSopenharmony_ci
5286cd6a6acSopenharmony_ci	rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args);
5296cd6a6acSopenharmony_ci
5306cd6a6acSopenharmony_ci	if (rc == 0) {
5316cd6a6acSopenharmony_ci		args.avtab = &p->te_cond_avtab;
5326cd6a6acSopenharmony_ci		rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args);
5336cd6a6acSopenharmony_ci	}
5346cd6a6acSopenharmony_ci
5356cd6a6acSopenharmony_ci	return rc;
5366cd6a6acSopenharmony_ci}
5376cd6a6acSopenharmony_ci
5386cd6a6acSopenharmony_ciint check_assertions(sepol_handle_t * handle, policydb_t * p,
5396cd6a6acSopenharmony_ci		     avrule_t * avrules)
5406cd6a6acSopenharmony_ci{
5416cd6a6acSopenharmony_ci	int rc;
5426cd6a6acSopenharmony_ci	avrule_t *a;
5436cd6a6acSopenharmony_ci	unsigned long errors = 0;
5446cd6a6acSopenharmony_ci
5456cd6a6acSopenharmony_ci	if (!avrules) {
5466cd6a6acSopenharmony_ci		/* Since assertions are stored in avrules, if it is NULL
5476cd6a6acSopenharmony_ci		   there won't be any to check. This also prevents an invalid
5486cd6a6acSopenharmony_ci		   free if the avtabs are never initialized */
5496cd6a6acSopenharmony_ci		return 0;
5506cd6a6acSopenharmony_ci	}
5516cd6a6acSopenharmony_ci
5526cd6a6acSopenharmony_ci	for (a = avrules; a != NULL; a = a->next) {
5536cd6a6acSopenharmony_ci		if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
5546cd6a6acSopenharmony_ci			continue;
5556cd6a6acSopenharmony_ci		rc = check_assertion(p, a);
5566cd6a6acSopenharmony_ci		if (rc < 0) {
5576cd6a6acSopenharmony_ci			ERR(handle, "Error occurred while checking neverallows");
5586cd6a6acSopenharmony_ci			return -1;
5596cd6a6acSopenharmony_ci		}
5606cd6a6acSopenharmony_ci		if (rc) {
5616cd6a6acSopenharmony_ci			rc = report_assertion_failures(handle, p, a);
5626cd6a6acSopenharmony_ci			if (rc < 0) {
5636cd6a6acSopenharmony_ci				ERR(handle, "Error occurred while checking neverallows");
5646cd6a6acSopenharmony_ci				return -1;
5656cd6a6acSopenharmony_ci			}
5666cd6a6acSopenharmony_ci			errors += rc;
5676cd6a6acSopenharmony_ci		}
5686cd6a6acSopenharmony_ci	}
5696cd6a6acSopenharmony_ci
5706cd6a6acSopenharmony_ci	if (errors)
5716cd6a6acSopenharmony_ci		ERR(handle, "%lu neverallow failures occurred", errors);
5726cd6a6acSopenharmony_ci
5736cd6a6acSopenharmony_ci	return errors ? -1 : 0;
5746cd6a6acSopenharmony_ci}
575