16cd6a6acSopenharmony_ci/*
26cd6a6acSopenharmony_ci * Class and permission mappings.
36cd6a6acSopenharmony_ci */
46cd6a6acSopenharmony_ci
56cd6a6acSopenharmony_ci#include <errno.h>
66cd6a6acSopenharmony_ci#include <stdio.h>
76cd6a6acSopenharmony_ci#include <stdlib.h>
86cd6a6acSopenharmony_ci#include <stdarg.h>
96cd6a6acSopenharmony_ci#include <stdbool.h>
106cd6a6acSopenharmony_ci#include <selinux/selinux.h>
116cd6a6acSopenharmony_ci#include <selinux/avc.h>
126cd6a6acSopenharmony_ci#include "callbacks.h"
136cd6a6acSopenharmony_ci#include "mapping.h"
146cd6a6acSopenharmony_ci#include "selinux_internal.h"
156cd6a6acSopenharmony_ci
166cd6a6acSopenharmony_ci/*
176cd6a6acSopenharmony_ci * Class and permission mappings
186cd6a6acSopenharmony_ci */
196cd6a6acSopenharmony_ci
206cd6a6acSopenharmony_cistruct selinux_mapping {
216cd6a6acSopenharmony_ci	security_class_t value; /* real, kernel value */
226cd6a6acSopenharmony_ci	unsigned num_perms;
236cd6a6acSopenharmony_ci	access_vector_t perms[sizeof(access_vector_t) * 8];
246cd6a6acSopenharmony_ci};
256cd6a6acSopenharmony_ci
266cd6a6acSopenharmony_cistatic struct selinux_mapping *current_mapping = NULL;
276cd6a6acSopenharmony_cistatic security_class_t current_mapping_size = 0;
286cd6a6acSopenharmony_ci
296cd6a6acSopenharmony_ci/*
306cd6a6acSopenharmony_ci * Mapping setting function
316cd6a6acSopenharmony_ci */
326cd6a6acSopenharmony_ci
336cd6a6acSopenharmony_ciint
346cd6a6acSopenharmony_ciselinux_set_mapping(struct security_class_mapping *map)
356cd6a6acSopenharmony_ci{
366cd6a6acSopenharmony_ci	size_t size = sizeof(struct selinux_mapping);
376cd6a6acSopenharmony_ci	security_class_t i, j;
386cd6a6acSopenharmony_ci	unsigned k;
396cd6a6acSopenharmony_ci	bool print_unknown_handle = false;
406cd6a6acSopenharmony_ci	bool reject = (security_reject_unknown() == 1);
416cd6a6acSopenharmony_ci	bool deny = (security_deny_unknown() == 1);
426cd6a6acSopenharmony_ci
436cd6a6acSopenharmony_ci	free(current_mapping);
446cd6a6acSopenharmony_ci	current_mapping = NULL;
456cd6a6acSopenharmony_ci	current_mapping_size = 0;
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_ci	if (avc_reset() < 0)
486cd6a6acSopenharmony_ci		goto err;
496cd6a6acSopenharmony_ci
506cd6a6acSopenharmony_ci	/* Find number of classes in the input mapping */
516cd6a6acSopenharmony_ci	if (!map) {
526cd6a6acSopenharmony_ci		errno = EINVAL;
536cd6a6acSopenharmony_ci		goto err;
546cd6a6acSopenharmony_ci	}
556cd6a6acSopenharmony_ci	i = 0;
566cd6a6acSopenharmony_ci	while (map[i].name)
576cd6a6acSopenharmony_ci		i++;
586cd6a6acSopenharmony_ci
596cd6a6acSopenharmony_ci	/* Allocate space for the class records, plus one for class zero */
606cd6a6acSopenharmony_ci	current_mapping = (struct selinux_mapping *)calloc(++i, size);
616cd6a6acSopenharmony_ci	if (!current_mapping)
626cd6a6acSopenharmony_ci		goto err;
636cd6a6acSopenharmony_ci
646cd6a6acSopenharmony_ci	/* Store the raw class and permission values */
656cd6a6acSopenharmony_ci	j = 0;
666cd6a6acSopenharmony_ci	while (map[j].name) {
676cd6a6acSopenharmony_ci		struct security_class_mapping *p_in = map + (j++);
686cd6a6acSopenharmony_ci		struct selinux_mapping *p_out = current_mapping + j;
696cd6a6acSopenharmony_ci
706cd6a6acSopenharmony_ci		p_out->value = string_to_security_class(p_in->name);
716cd6a6acSopenharmony_ci		if (!p_out->value) {
726cd6a6acSopenharmony_ci			selinux_log(SELINUX_INFO,
736cd6a6acSopenharmony_ci				    "SELinux: Class %s not defined in policy.\n",
746cd6a6acSopenharmony_ci				    p_in->name);
756cd6a6acSopenharmony_ci			if (reject)
766cd6a6acSopenharmony_ci				goto err2;
776cd6a6acSopenharmony_ci			p_out->num_perms = 0;
786cd6a6acSopenharmony_ci			print_unknown_handle = true;
796cd6a6acSopenharmony_ci			continue;
806cd6a6acSopenharmony_ci		}
816cd6a6acSopenharmony_ci
826cd6a6acSopenharmony_ci		k = 0;
836cd6a6acSopenharmony_ci		while (p_in->perms[k]) {
846cd6a6acSopenharmony_ci			/* An empty permission string skips ahead */
856cd6a6acSopenharmony_ci			if (!*p_in->perms[k]) {
866cd6a6acSopenharmony_ci				k++;
876cd6a6acSopenharmony_ci				continue;
886cd6a6acSopenharmony_ci			}
896cd6a6acSopenharmony_ci			p_out->perms[k] = string_to_av_perm(p_out->value,
906cd6a6acSopenharmony_ci							    p_in->perms[k]);
916cd6a6acSopenharmony_ci			if (!p_out->perms[k]) {
926cd6a6acSopenharmony_ci				selinux_log(SELINUX_INFO,
936cd6a6acSopenharmony_ci					    "SELinux:  Permission %s in class %s not defined in policy.\n",
946cd6a6acSopenharmony_ci					    p_in->perms[k], p_in->name);
956cd6a6acSopenharmony_ci				if (reject)
966cd6a6acSopenharmony_ci					goto err2;
976cd6a6acSopenharmony_ci				print_unknown_handle = true;
986cd6a6acSopenharmony_ci			}
996cd6a6acSopenharmony_ci			k++;
1006cd6a6acSopenharmony_ci		}
1016cd6a6acSopenharmony_ci		p_out->num_perms = k;
1026cd6a6acSopenharmony_ci	}
1036cd6a6acSopenharmony_ci
1046cd6a6acSopenharmony_ci	if (print_unknown_handle)
1056cd6a6acSopenharmony_ci		selinux_log(SELINUX_INFO,
1066cd6a6acSopenharmony_ci			    "SELinux: the above unknown classes and permissions will be %s\n",
1076cd6a6acSopenharmony_ci			    deny ? "denied" : "allowed");
1086cd6a6acSopenharmony_ci
1096cd6a6acSopenharmony_ci	/* Set the mapping size here so the above lookups are "raw" */
1106cd6a6acSopenharmony_ci	current_mapping_size = i;
1116cd6a6acSopenharmony_ci	return 0;
1126cd6a6acSopenharmony_cierr2:
1136cd6a6acSopenharmony_ci	free(current_mapping);
1146cd6a6acSopenharmony_ci	current_mapping = NULL;
1156cd6a6acSopenharmony_ci	current_mapping_size = 0;
1166cd6a6acSopenharmony_cierr:
1176cd6a6acSopenharmony_ci	return -1;
1186cd6a6acSopenharmony_ci}
1196cd6a6acSopenharmony_ci
1206cd6a6acSopenharmony_ci/*
1216cd6a6acSopenharmony_ci * Get real, kernel values from mapped values
1226cd6a6acSopenharmony_ci */
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_cisecurity_class_t
1256cd6a6acSopenharmony_ciunmap_class(security_class_t tclass)
1266cd6a6acSopenharmony_ci{
1276cd6a6acSopenharmony_ci	if (tclass < current_mapping_size)
1286cd6a6acSopenharmony_ci		return current_mapping[tclass].value;
1296cd6a6acSopenharmony_ci
1306cd6a6acSopenharmony_ci	/* If here no mapping set or the class requested is not valid. */
1316cd6a6acSopenharmony_ci	if (current_mapping_size != 0) {
1326cd6a6acSopenharmony_ci		errno = EINVAL;
1336cd6a6acSopenharmony_ci		return 0;
1346cd6a6acSopenharmony_ci	}
1356cd6a6acSopenharmony_ci	else
1366cd6a6acSopenharmony_ci		return tclass;
1376cd6a6acSopenharmony_ci}
1386cd6a6acSopenharmony_ci
1396cd6a6acSopenharmony_ciaccess_vector_t
1406cd6a6acSopenharmony_ciunmap_perm(security_class_t tclass, access_vector_t tperm)
1416cd6a6acSopenharmony_ci{
1426cd6a6acSopenharmony_ci	if (tclass < current_mapping_size) {
1436cd6a6acSopenharmony_ci		unsigned i;
1446cd6a6acSopenharmony_ci		access_vector_t kperm = 0;
1456cd6a6acSopenharmony_ci
1466cd6a6acSopenharmony_ci		for (i = 0; i < current_mapping[tclass].num_perms; i++)
1476cd6a6acSopenharmony_ci			if (tperm & (UINT32_C(1)<<i)) {
1486cd6a6acSopenharmony_ci				kperm |= current_mapping[tclass].perms[i];
1496cd6a6acSopenharmony_ci				tperm &= ~(UINT32_C(1)<<i);
1506cd6a6acSopenharmony_ci			}
1516cd6a6acSopenharmony_ci		return kperm;
1526cd6a6acSopenharmony_ci	}
1536cd6a6acSopenharmony_ci
1546cd6a6acSopenharmony_ci	/* If here no mapping set or the perm requested is not valid. */
1556cd6a6acSopenharmony_ci	if (current_mapping_size != 0) {
1566cd6a6acSopenharmony_ci		errno = EINVAL;
1576cd6a6acSopenharmony_ci		return 0;
1586cd6a6acSopenharmony_ci	}
1596cd6a6acSopenharmony_ci	else
1606cd6a6acSopenharmony_ci		return tperm;
1616cd6a6acSopenharmony_ci}
1626cd6a6acSopenharmony_ci
1636cd6a6acSopenharmony_ci/*
1646cd6a6acSopenharmony_ci * Get mapped values from real, kernel values
1656cd6a6acSopenharmony_ci */
1666cd6a6acSopenharmony_ci
1676cd6a6acSopenharmony_cisecurity_class_t
1686cd6a6acSopenharmony_cimap_class(security_class_t kclass)
1696cd6a6acSopenharmony_ci{
1706cd6a6acSopenharmony_ci	security_class_t i;
1716cd6a6acSopenharmony_ci
1726cd6a6acSopenharmony_ci	for (i = 0; i < current_mapping_size; i++)
1736cd6a6acSopenharmony_ci		if (current_mapping[i].value == kclass)
1746cd6a6acSopenharmony_ci			return i;
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci/* If here no mapping set or the class requested is not valid. */
1776cd6a6acSopenharmony_ci	if (current_mapping_size != 0) {
1786cd6a6acSopenharmony_ci		errno = EINVAL;
1796cd6a6acSopenharmony_ci		return 0;
1806cd6a6acSopenharmony_ci	}
1816cd6a6acSopenharmony_ci	else
1826cd6a6acSopenharmony_ci		return kclass;
1836cd6a6acSopenharmony_ci}
1846cd6a6acSopenharmony_ci
1856cd6a6acSopenharmony_ciaccess_vector_t
1866cd6a6acSopenharmony_cimap_perm(security_class_t tclass, access_vector_t kperm)
1876cd6a6acSopenharmony_ci{
1886cd6a6acSopenharmony_ci	if (tclass < current_mapping_size) {
1896cd6a6acSopenharmony_ci		unsigned i;
1906cd6a6acSopenharmony_ci		access_vector_t tperm = 0;
1916cd6a6acSopenharmony_ci
1926cd6a6acSopenharmony_ci		for (i = 0; i < current_mapping[tclass].num_perms; i++)
1936cd6a6acSopenharmony_ci			if (kperm & current_mapping[tclass].perms[i]) {
1946cd6a6acSopenharmony_ci				tperm |= UINT32_C(1)<<i;
1956cd6a6acSopenharmony_ci				kperm &= ~current_mapping[tclass].perms[i];
1966cd6a6acSopenharmony_ci			}
1976cd6a6acSopenharmony_ci
1986cd6a6acSopenharmony_ci		if (tperm == 0) {
1996cd6a6acSopenharmony_ci			errno = EINVAL;
2006cd6a6acSopenharmony_ci			return 0;
2016cd6a6acSopenharmony_ci		}
2026cd6a6acSopenharmony_ci		else
2036cd6a6acSopenharmony_ci			return tperm;
2046cd6a6acSopenharmony_ci	}
2056cd6a6acSopenharmony_ci	return kperm;
2066cd6a6acSopenharmony_ci}
2076cd6a6acSopenharmony_ci
2086cd6a6acSopenharmony_civoid
2096cd6a6acSopenharmony_cimap_decision(security_class_t tclass, struct av_decision *avd)
2106cd6a6acSopenharmony_ci{
2116cd6a6acSopenharmony_ci	if (tclass < current_mapping_size) {
2126cd6a6acSopenharmony_ci		bool allow_unknown = (security_deny_unknown() == 0);
2136cd6a6acSopenharmony_ci		struct selinux_mapping *mapping = &current_mapping[tclass];
2146cd6a6acSopenharmony_ci		unsigned int i, n = mapping->num_perms;
2156cd6a6acSopenharmony_ci		access_vector_t result;
2166cd6a6acSopenharmony_ci
2176cd6a6acSopenharmony_ci		for (i = 0, result = 0; i < n; i++) {
2186cd6a6acSopenharmony_ci			if (avd->allowed & mapping->perms[i])
2196cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2206cd6a6acSopenharmony_ci			else if (allow_unknown && !mapping->perms[i])
2216cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2226cd6a6acSopenharmony_ci		}
2236cd6a6acSopenharmony_ci		avd->allowed = result;
2246cd6a6acSopenharmony_ci
2256cd6a6acSopenharmony_ci		for (i = 0, result = 0; i < n; i++) {
2266cd6a6acSopenharmony_ci			if (avd->decided & mapping->perms[i])
2276cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2286cd6a6acSopenharmony_ci			else if (allow_unknown && !mapping->perms[i])
2296cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2306cd6a6acSopenharmony_ci		}
2316cd6a6acSopenharmony_ci		avd->decided = result;
2326cd6a6acSopenharmony_ci
2336cd6a6acSopenharmony_ci		for (i = 0, result = 0; i < n; i++)
2346cd6a6acSopenharmony_ci			if (avd->auditallow & mapping->perms[i])
2356cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2366cd6a6acSopenharmony_ci		avd->auditallow = result;
2376cd6a6acSopenharmony_ci
2386cd6a6acSopenharmony_ci		for (i = 0, result = 0; i < n; i++) {
2396cd6a6acSopenharmony_ci			if (avd->auditdeny & mapping->perms[i])
2406cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2416cd6a6acSopenharmony_ci			else if (!allow_unknown && !mapping->perms[i])
2426cd6a6acSopenharmony_ci				result |= UINT32_C(1)<<i;
2436cd6a6acSopenharmony_ci		}
2446cd6a6acSopenharmony_ci
2456cd6a6acSopenharmony_ci		/*
2466cd6a6acSopenharmony_ci		 * Make sure we audit denials for any permission check
2476cd6a6acSopenharmony_ci		 * beyond the mapping->num_perms since this indicates
2486cd6a6acSopenharmony_ci		 * a bug in the object manager.
2496cd6a6acSopenharmony_ci		 */
2506cd6a6acSopenharmony_ci		for (; i < (sizeof(result)*8); i++)
2516cd6a6acSopenharmony_ci			result |= UINT32_C(1)<<i;
2526cd6a6acSopenharmony_ci		avd->auditdeny = result;
2536cd6a6acSopenharmony_ci	}
2546cd6a6acSopenharmony_ci}
255