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