1/*
2 * Class and permission mappings.
3 */
4
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdarg.h>
9#include <stdbool.h>
10#include <selinux/selinux.h>
11#include <selinux/avc.h>
12#include "callbacks.h"
13#include "mapping.h"
14#include "selinux_internal.h"
15
16/*
17 * Class and permission mappings
18 */
19
20struct selinux_mapping {
21	security_class_t value; /* real, kernel value */
22	unsigned num_perms;
23	access_vector_t perms[sizeof(access_vector_t) * 8];
24};
25
26static struct selinux_mapping *current_mapping = NULL;
27static security_class_t current_mapping_size = 0;
28
29/*
30 * Mapping setting function
31 */
32
33int
34selinux_set_mapping(struct security_class_mapping *map)
35{
36	size_t size = sizeof(struct selinux_mapping);
37	security_class_t i, j;
38	unsigned k;
39	bool print_unknown_handle = false;
40	bool reject = (security_reject_unknown() == 1);
41	bool deny = (security_deny_unknown() == 1);
42
43	free(current_mapping);
44	current_mapping = NULL;
45	current_mapping_size = 0;
46
47	if (avc_reset() < 0)
48		goto err;
49
50	/* Find number of classes in the input mapping */
51	if (!map) {
52		errno = EINVAL;
53		goto err;
54	}
55	i = 0;
56	while (map[i].name)
57		i++;
58
59	/* Allocate space for the class records, plus one for class zero */
60	current_mapping = (struct selinux_mapping *)calloc(++i, size);
61	if (!current_mapping)
62		goto err;
63
64	/* Store the raw class and permission values */
65	j = 0;
66	while (map[j].name) {
67		struct security_class_mapping *p_in = map + (j++);
68		struct selinux_mapping *p_out = current_mapping + j;
69
70		p_out->value = string_to_security_class(p_in->name);
71		if (!p_out->value) {
72			selinux_log(SELINUX_INFO,
73				    "SELinux: Class %s not defined in policy.\n",
74				    p_in->name);
75			if (reject)
76				goto err2;
77			p_out->num_perms = 0;
78			print_unknown_handle = true;
79			continue;
80		}
81
82		k = 0;
83		while (p_in->perms[k]) {
84			/* An empty permission string skips ahead */
85			if (!*p_in->perms[k]) {
86				k++;
87				continue;
88			}
89			p_out->perms[k] = string_to_av_perm(p_out->value,
90							    p_in->perms[k]);
91			if (!p_out->perms[k]) {
92				selinux_log(SELINUX_INFO,
93					    "SELinux:  Permission %s in class %s not defined in policy.\n",
94					    p_in->perms[k], p_in->name);
95				if (reject)
96					goto err2;
97				print_unknown_handle = true;
98			}
99			k++;
100		}
101		p_out->num_perms = k;
102	}
103
104	if (print_unknown_handle)
105		selinux_log(SELINUX_INFO,
106			    "SELinux: the above unknown classes and permissions will be %s\n",
107			    deny ? "denied" : "allowed");
108
109	/* Set the mapping size here so the above lookups are "raw" */
110	current_mapping_size = i;
111	return 0;
112err2:
113	free(current_mapping);
114	current_mapping = NULL;
115	current_mapping_size = 0;
116err:
117	return -1;
118}
119
120/*
121 * Get real, kernel values from mapped values
122 */
123
124security_class_t
125unmap_class(security_class_t tclass)
126{
127	if (tclass < current_mapping_size)
128		return current_mapping[tclass].value;
129
130	/* If here no mapping set or the class requested is not valid. */
131	if (current_mapping_size != 0) {
132		errno = EINVAL;
133		return 0;
134	}
135	else
136		return tclass;
137}
138
139access_vector_t
140unmap_perm(security_class_t tclass, access_vector_t tperm)
141{
142	if (tclass < current_mapping_size) {
143		unsigned i;
144		access_vector_t kperm = 0;
145
146		for (i = 0; i < current_mapping[tclass].num_perms; i++)
147			if (tperm & (UINT32_C(1)<<i)) {
148				kperm |= current_mapping[tclass].perms[i];
149				tperm &= ~(UINT32_C(1)<<i);
150			}
151		return kperm;
152	}
153
154	/* If here no mapping set or the perm requested is not valid. */
155	if (current_mapping_size != 0) {
156		errno = EINVAL;
157		return 0;
158	}
159	else
160		return tperm;
161}
162
163/*
164 * Get mapped values from real, kernel values
165 */
166
167security_class_t
168map_class(security_class_t kclass)
169{
170	security_class_t i;
171
172	for (i = 0; i < current_mapping_size; i++)
173		if (current_mapping[i].value == kclass)
174			return i;
175
176/* If here no mapping set or the class requested is not valid. */
177	if (current_mapping_size != 0) {
178		errno = EINVAL;
179		return 0;
180	}
181	else
182		return kclass;
183}
184
185access_vector_t
186map_perm(security_class_t tclass, access_vector_t kperm)
187{
188	if (tclass < current_mapping_size) {
189		unsigned i;
190		access_vector_t tperm = 0;
191
192		for (i = 0; i < current_mapping[tclass].num_perms; i++)
193			if (kperm & current_mapping[tclass].perms[i]) {
194				tperm |= UINT32_C(1)<<i;
195				kperm &= ~current_mapping[tclass].perms[i];
196			}
197
198		if (tperm == 0) {
199			errno = EINVAL;
200			return 0;
201		}
202		else
203			return tperm;
204	}
205	return kperm;
206}
207
208void
209map_decision(security_class_t tclass, struct av_decision *avd)
210{
211	if (tclass < current_mapping_size) {
212		bool allow_unknown = (security_deny_unknown() == 0);
213		struct selinux_mapping *mapping = &current_mapping[tclass];
214		unsigned int i, n = mapping->num_perms;
215		access_vector_t result;
216
217		for (i = 0, result = 0; i < n; i++) {
218			if (avd->allowed & mapping->perms[i])
219				result |= UINT32_C(1)<<i;
220			else if (allow_unknown && !mapping->perms[i])
221				result |= UINT32_C(1)<<i;
222		}
223		avd->allowed = result;
224
225		for (i = 0, result = 0; i < n; i++) {
226			if (avd->decided & mapping->perms[i])
227				result |= UINT32_C(1)<<i;
228			else if (allow_unknown && !mapping->perms[i])
229				result |= UINT32_C(1)<<i;
230		}
231		avd->decided = result;
232
233		for (i = 0, result = 0; i < n; i++)
234			if (avd->auditallow & mapping->perms[i])
235				result |= UINT32_C(1)<<i;
236		avd->auditallow = result;
237
238		for (i = 0, result = 0; i < n; i++) {
239			if (avd->auditdeny & mapping->perms[i])
240				result |= UINT32_C(1)<<i;
241			else if (!allow_unknown && !mapping->perms[i])
242				result |= UINT32_C(1)<<i;
243		}
244
245		/*
246		 * Make sure we audit denials for any permission check
247		 * beyond the mapping->num_perms since this indicates
248		 * a bug in the object manager.
249		 */
250		for (; i < (sizeof(result)*8); i++)
251			result |= UINT32_C(1)<<i;
252		avd->auditdeny = result;
253	}
254}
255