1
2 /*
3 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
4 */
5 /*
6 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
7 *
8 * Support for enhanced MLS infrastructure.
9 *
10 * Updated: Frank Mayer <mayerf@tresys.com>
11 * and Karl MacMillan <kmacmillan@tresys.com>
12 *
13 * Added conditional policy language extensions
14 *
15 * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com>
16 *
17 * Fine-grained netlink support
18 * IPv6 support
19 * Code cleanup
20 *
21 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
22 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
23 * Copyright (C) 2003 - 2004 Red Hat, Inc.
24 *
25 * This library is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU Lesser General Public
27 * License as published by the Free Software Foundation; either
28 * version 2.1 of the License, or (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * Lesser General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public
36 * License along with this library; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 */
39
40 /* FLASK */
41
42 /*
43 * Implementation of the security services.
44 */
45
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51
52 #include <sepol/policydb/policydb.h>
53 #include <sepol/policydb/sidtab.h>
54 #include <sepol/policydb/services.h>
55 #include <sepol/policydb/conditional.h>
56 #include <sepol/policydb/flask.h>
57
58 #include "debug.h"
59 #include "private.h"
60 #include "context.h"
61 #include "av_permissions.h"
62 #include "dso.h"
63 #include "mls.h"
64
65 #define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
66 #define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
67
68 static int selinux_enforcing = 1;
69
70 static sidtab_t mysidtab, *sidtab = &mysidtab;
71 static policydb_t mypolicydb, *policydb = &mypolicydb;
72
sepol_set_sidtab(sidtab_t * s)73 int hidden sepol_set_sidtab(sidtab_t * s)
74 {
75 sidtab = s;
76 return 0;
77 }
78
sepol_set_policydb(policydb_t * p)79 int hidden sepol_set_policydb(policydb_t * p)
80 {
81 policydb = p;
82 return 0;
83 }
84
sepol_set_policydb_from_file(FILE * fp)85 int sepol_set_policydb_from_file(FILE * fp)
86 {
87 struct policy_file pf;
88
89 policy_file_init(&pf);
90 pf.fp = fp;
91 pf.type = PF_USE_STDIO;
92 if (mypolicydb.policy_type)
93 policydb_destroy(&mypolicydb);
94 if (policydb_init(&mypolicydb)) {
95 ERR(NULL, "Out of memory!");
96 return -1;
97 }
98 if (policydb_read(&mypolicydb, &pf, 0)) {
99 ERR(NULL, "can't read binary policy: %s", strerror(errno));
100 return -1;
101 }
102 policydb = &mypolicydb;
103 return sepol_sidtab_init(sidtab);
104 }
105
106 /*
107 * The largest sequence number that has been used when
108 * providing an access decision to the access vector cache.
109 * The sequence number only changes when a policy change
110 * occurs.
111 */
112 static uint32_t latest_granting = 0;
113
114 /*
115 * Return the boolean value of a constraint expression
116 * when it is applied to the specified source and target
117 * security contexts.
118 *
119 * xcontext is a special beast... It is used by the validatetrans rules
120 * only. For these rules, scontext is the context before the transition,
121 * tcontext is the context after the transition, and xcontext is the context
122 * of the process performing the transition. All other callers of
123 * constraint_expr_eval should pass in NULL for xcontext.
124 */
constraint_expr_eval(context_struct_t * scontext,context_struct_t * tcontext,context_struct_t * xcontext,constraint_expr_t * cexpr)125 static int constraint_expr_eval(context_struct_t * scontext,
126 context_struct_t * tcontext,
127 context_struct_t * xcontext,
128 constraint_expr_t * cexpr)
129 {
130 uint32_t val1, val2;
131 context_struct_t *c;
132 role_datum_t *r1, *r2;
133 mls_level_t *l1, *l2;
134 constraint_expr_t *e;
135 int s[CEXPR_MAXDEPTH];
136 int sp = -1;
137
138 for (e = cexpr; e; e = e->next) {
139 switch (e->expr_type) {
140 case CEXPR_NOT:
141 BUG_ON(sp < 0);
142 s[sp] = !s[sp];
143 break;
144 case CEXPR_AND:
145 BUG_ON(sp < 1);
146 sp--;
147 s[sp] &= s[sp + 1];
148 break;
149 case CEXPR_OR:
150 BUG_ON(sp < 1);
151 sp--;
152 s[sp] |= s[sp + 1];
153 break;
154 case CEXPR_ATTR:
155 if (sp == (CEXPR_MAXDEPTH - 1))
156 return 0;
157 switch (e->attr) {
158 case CEXPR_USER:
159 val1 = scontext->user;
160 val2 = tcontext->user;
161 break;
162 case CEXPR_TYPE:
163 val1 = scontext->type;
164 val2 = tcontext->type;
165 break;
166 case CEXPR_ROLE:
167 val1 = scontext->role;
168 val2 = tcontext->role;
169 r1 = policydb->role_val_to_struct[val1 - 1];
170 r2 = policydb->role_val_to_struct[val2 - 1];
171 switch (e->op) {
172 case CEXPR_DOM:
173 s[++sp] =
174 ebitmap_get_bit(&r1->dominates,
175 val2 - 1);
176 continue;
177 case CEXPR_DOMBY:
178 s[++sp] =
179 ebitmap_get_bit(&r2->dominates,
180 val1 - 1);
181 continue;
182 case CEXPR_INCOMP:
183 s[++sp] =
184 (!ebitmap_get_bit
185 (&r1->dominates, val2 - 1)
186 && !ebitmap_get_bit(&r2->dominates,
187 val1 - 1));
188 continue;
189 default:
190 break;
191 }
192 break;
193 case CEXPR_L1L2:
194 l1 = &(scontext->range.level[0]);
195 l2 = &(tcontext->range.level[0]);
196 goto mls_ops;
197 case CEXPR_L1H2:
198 l1 = &(scontext->range.level[0]);
199 l2 = &(tcontext->range.level[1]);
200 goto mls_ops;
201 case CEXPR_H1L2:
202 l1 = &(scontext->range.level[1]);
203 l2 = &(tcontext->range.level[0]);
204 goto mls_ops;
205 case CEXPR_H1H2:
206 l1 = &(scontext->range.level[1]);
207 l2 = &(tcontext->range.level[1]);
208 goto mls_ops;
209 case CEXPR_L1H1:
210 l1 = &(scontext->range.level[0]);
211 l2 = &(scontext->range.level[1]);
212 goto mls_ops;
213 case CEXPR_L2H2:
214 l1 = &(tcontext->range.level[0]);
215 l2 = &(tcontext->range.level[1]);
216 goto mls_ops;
217 mls_ops:
218 switch (e->op) {
219 case CEXPR_EQ:
220 s[++sp] = mls_level_eq(l1, l2);
221 continue;
222 case CEXPR_NEQ:
223 s[++sp] = !mls_level_eq(l1, l2);
224 continue;
225 case CEXPR_DOM:
226 s[++sp] = mls_level_dom(l1, l2);
227 continue;
228 case CEXPR_DOMBY:
229 s[++sp] = mls_level_dom(l2, l1);
230 continue;
231 case CEXPR_INCOMP:
232 s[++sp] = mls_level_incomp(l2, l1);
233 continue;
234 default:
235 BUG();
236 return 0;
237 }
238 break;
239 default:
240 BUG();
241 return 0;
242 }
243
244 switch (e->op) {
245 case CEXPR_EQ:
246 s[++sp] = (val1 == val2);
247 break;
248 case CEXPR_NEQ:
249 s[++sp] = (val1 != val2);
250 break;
251 default:
252 BUG();
253 return 0;
254 }
255 break;
256 case CEXPR_NAMES:
257 if (sp == (CEXPR_MAXDEPTH - 1))
258 return 0;
259 c = scontext;
260 if (e->attr & CEXPR_TARGET)
261 c = tcontext;
262 else if (e->attr & CEXPR_XTARGET) {
263 c = xcontext;
264 if (!c) {
265 BUG();
266 return 0;
267 }
268 }
269 if (e->attr & CEXPR_USER)
270 val1 = c->user;
271 else if (e->attr & CEXPR_ROLE)
272 val1 = c->role;
273 else if (e->attr & CEXPR_TYPE)
274 val1 = c->type;
275 else {
276 BUG();
277 return 0;
278 }
279
280 switch (e->op) {
281 case CEXPR_EQ:
282 s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
283 break;
284 case CEXPR_NEQ:
285 s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
286 break;
287 default:
288 BUG();
289 return 0;
290 }
291 break;
292 default:
293 BUG();
294 return 0;
295 }
296 }
297
298 BUG_ON(sp != 0);
299 return s[0];
300 }
301
302 /*
303 * Compute access vectors based on a context structure pair for
304 * the permissions in a particular class.
305 */
context_struct_compute_av(context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,sepol_access_vector_t requested,struct sepol_av_decision * avd,unsigned int * reason)306 static int context_struct_compute_av(context_struct_t * scontext,
307 context_struct_t * tcontext,
308 sepol_security_class_t tclass,
309 sepol_access_vector_t requested,
310 struct sepol_av_decision *avd,
311 unsigned int *reason)
312 {
313 constraint_node_t *constraint;
314 struct role_allow *ra;
315 avtab_key_t avkey;
316 class_datum_t *tclass_datum;
317 avtab_ptr_t node;
318 ebitmap_t *sattr, *tattr;
319 ebitmap_node_t *snode, *tnode;
320 unsigned int i, j;
321
322 if (!tclass || tclass > policydb->p_classes.nprim) {
323 ERR(NULL, "unrecognized class %d", tclass);
324 return -EINVAL;
325 }
326 tclass_datum = policydb->class_val_to_struct[tclass - 1];
327
328 /*
329 * Initialize the access vectors to the default values.
330 */
331 avd->allowed = 0;
332 avd->decided = 0xffffffff;
333 avd->auditallow = 0;
334 avd->auditdeny = 0xffffffff;
335 avd->seqno = latest_granting;
336 *reason = 0;
337
338 /*
339 * If a specific type enforcement rule was defined for
340 * this permission check, then use it.
341 */
342 avkey.target_class = tclass;
343 avkey.specified = AVTAB_AV;
344 sattr = &policydb->type_attr_map[scontext->type - 1];
345 tattr = &policydb->type_attr_map[tcontext->type - 1];
346 ebitmap_for_each_bit(sattr, snode, i) {
347 if (!ebitmap_node_get_bit(snode, i))
348 continue;
349 ebitmap_for_each_bit(tattr, tnode, j) {
350 if (!ebitmap_node_get_bit(tnode, j))
351 continue;
352 avkey.source_type = i + 1;
353 avkey.target_type = j + 1;
354 for (node =
355 avtab_search_node(&policydb->te_avtab, &avkey);
356 node != NULL;
357 node =
358 avtab_search_node_next(node, avkey.specified)) {
359 if (node->key.specified == AVTAB_ALLOWED)
360 avd->allowed |= node->datum.data;
361 else if (node->key.specified ==
362 AVTAB_AUDITALLOW)
363 avd->auditallow |= node->datum.data;
364 else if (node->key.specified == AVTAB_AUDITDENY)
365 avd->auditdeny &= node->datum.data;
366 }
367
368 /* Check conditional av table for additional permissions */
369 cond_compute_av(&policydb->te_cond_avtab, &avkey, avd);
370
371 }
372 }
373
374 if (requested & ~avd->allowed) {
375 *reason |= SEPOL_COMPUTEAV_TE;
376 requested &= avd->allowed;
377 }
378
379 /*
380 * Remove any permissions prohibited by a constraint (this includes
381 * the MLS policy).
382 */
383 constraint = tclass_datum->constraints;
384 while (constraint) {
385 if ((constraint->permissions & (avd->allowed)) &&
386 !constraint_expr_eval(scontext, tcontext, NULL,
387 constraint->expr)) {
388 avd->allowed =
389 (avd->allowed) & ~(constraint->permissions);
390 }
391 constraint = constraint->next;
392 }
393
394 if (requested & ~avd->allowed) {
395 *reason |= SEPOL_COMPUTEAV_CONS;
396 requested &= avd->allowed;
397 }
398
399 /*
400 * If checking process transition permission and the
401 * role is changing, then check the (current_role, new_role)
402 * pair.
403 */
404 if (tclass == SECCLASS_PROCESS &&
405 (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
406 scontext->role != tcontext->role) {
407 for (ra = policydb->role_allow; ra; ra = ra->next) {
408 if (scontext->role == ra->role &&
409 tcontext->role == ra->new_role)
410 break;
411 }
412 if (!ra)
413 avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
414 PROCESS__DYNTRANSITION);
415 }
416
417 if (requested & ~avd->allowed) {
418 *reason |= SEPOL_COMPUTEAV_RBAC;
419 requested &= avd->allowed;
420 }
421
422 return 0;
423 }
424
sepol_validate_transition(sepol_security_id_t oldsid,sepol_security_id_t newsid,sepol_security_id_t tasksid,sepol_security_class_t tclass)425 int hidden sepol_validate_transition(sepol_security_id_t oldsid,
426 sepol_security_id_t newsid,
427 sepol_security_id_t tasksid,
428 sepol_security_class_t tclass)
429 {
430 context_struct_t *ocontext;
431 context_struct_t *ncontext;
432 context_struct_t *tcontext;
433 class_datum_t *tclass_datum;
434 constraint_node_t *constraint;
435
436 if (!tclass || tclass > policydb->p_classes.nprim) {
437 ERR(NULL, "unrecognized class %d", tclass);
438 return -EINVAL;
439 }
440 tclass_datum = policydb->class_val_to_struct[tclass - 1];
441
442 ocontext = sepol_sidtab_search(sidtab, oldsid);
443 if (!ocontext) {
444 ERR(NULL, "unrecognized SID %d", oldsid);
445 return -EINVAL;
446 }
447
448 ncontext = sepol_sidtab_search(sidtab, newsid);
449 if (!ncontext) {
450 ERR(NULL, "unrecognized SID %d", newsid);
451 return -EINVAL;
452 }
453
454 tcontext = sepol_sidtab_search(sidtab, tasksid);
455 if (!tcontext) {
456 ERR(NULL, "unrecognized SID %d", tasksid);
457 return -EINVAL;
458 }
459
460 constraint = tclass_datum->validatetrans;
461 while (constraint) {
462 if (!constraint_expr_eval(ocontext, ncontext, tcontext,
463 constraint->expr)) {
464 return -EPERM;
465 }
466 constraint = constraint->next;
467 }
468
469 return 0;
470 }
471
sepol_compute_av_reason(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_access_vector_t requested,struct sepol_av_decision * avd,unsigned int * reason)472 int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
473 sepol_security_id_t tsid,
474 sepol_security_class_t tclass,
475 sepol_access_vector_t requested,
476 struct sepol_av_decision *avd,
477 unsigned int *reason)
478 {
479 context_struct_t *scontext = 0, *tcontext = 0;
480 int rc = 0;
481
482 scontext = sepol_sidtab_search(sidtab, ssid);
483 if (!scontext) {
484 ERR(NULL, "unrecognized SID %d", ssid);
485 rc = -EINVAL;
486 goto out;
487 }
488 tcontext = sepol_sidtab_search(sidtab, tsid);
489 if (!tcontext) {
490 ERR(NULL, "unrecognized SID %d", tsid);
491 rc = -EINVAL;
492 goto out;
493 }
494
495 rc = context_struct_compute_av(scontext, tcontext, tclass,
496 requested, avd, reason);
497 out:
498 return rc;
499 }
500
sepol_compute_av(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_access_vector_t requested,struct sepol_av_decision * avd)501 int hidden sepol_compute_av(sepol_security_id_t ssid,
502 sepol_security_id_t tsid,
503 sepol_security_class_t tclass,
504 sepol_access_vector_t requested,
505 struct sepol_av_decision *avd)
506 {
507 unsigned int reason = 0;
508 return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd,
509 &reason);
510 }
511
512 /*
513 * Write the security context string representation of
514 * the context associated with `sid' into a dynamically
515 * allocated string of the correct size. Set `*scontext'
516 * to point to this string and set `*scontext_len' to
517 * the length of the string.
518 */
sepol_sid_to_context(sepol_security_id_t sid,sepol_security_context_t * scontext,size_t * scontext_len)519 int hidden sepol_sid_to_context(sepol_security_id_t sid,
520 sepol_security_context_t * scontext,
521 size_t * scontext_len)
522 {
523 context_struct_t *context;
524 int rc = 0;
525
526 context = sepol_sidtab_search(sidtab, sid);
527 if (!context) {
528 ERR(NULL, "unrecognized SID %d", sid);
529 rc = -EINVAL;
530 goto out;
531 }
532 rc = context_to_string(NULL, policydb, context, scontext, scontext_len);
533 out:
534 return rc;
535
536 }
537
538 /*
539 * Return a SID associated with the security context that
540 * has the string representation specified by `scontext'.
541 */
sepol_context_to_sid(const sepol_security_context_t scontext,size_t scontext_len,sepol_security_id_t * sid)542 int hidden sepol_context_to_sid(const sepol_security_context_t scontext,
543 size_t scontext_len, sepol_security_id_t * sid)
544 {
545
546 context_struct_t *context = NULL;
547
548 /* First, create the context */
549 if (context_from_string(NULL, policydb, &context,
550 scontext, scontext_len) < 0)
551 goto err;
552
553 /* Obtain the new sid */
554 if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0))
555 goto err;
556
557 context_destroy(context);
558 free(context);
559 return STATUS_SUCCESS;
560
561 err:
562 if (context) {
563 context_destroy(context);
564 free(context);
565 }
566 ERR(NULL, "could not convert %s to sid", scontext);
567 return STATUS_ERR;
568 }
569
compute_sid_handle_invalid_context(context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,context_struct_t * newcontext)570 static inline int compute_sid_handle_invalid_context(context_struct_t *
571 scontext,
572 context_struct_t *
573 tcontext,
574 sepol_security_class_t
575 tclass,
576 context_struct_t *
577 newcontext)
578 {
579 if (selinux_enforcing) {
580 return -EACCES;
581 } else {
582 sepol_security_context_t s, t, n;
583 size_t slen, tlen, nlen;
584
585 context_to_string(NULL, policydb, scontext, &s, &slen);
586 context_to_string(NULL, policydb, tcontext, &t, &tlen);
587 context_to_string(NULL, policydb, newcontext, &n, &nlen);
588 ERR(NULL, "invalid context %s for "
589 "scontext=%s tcontext=%s tclass=%s",
590 n, s, t, policydb->p_class_val_to_name[tclass - 1]);
591 free(s);
592 free(t);
593 free(n);
594 return 0;
595 }
596 }
597
sepol_compute_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,uint32_t specified,sepol_security_id_t * out_sid)598 static int sepol_compute_sid(sepol_security_id_t ssid,
599 sepol_security_id_t tsid,
600 sepol_security_class_t tclass,
601 uint32_t specified, sepol_security_id_t * out_sid)
602 {
603 context_struct_t *scontext = 0, *tcontext = 0, newcontext;
604 struct role_trans *roletr = 0;
605 avtab_key_t avkey;
606 avtab_datum_t *avdatum;
607 avtab_ptr_t node;
608 int rc = 0;
609
610 scontext = sepol_sidtab_search(sidtab, ssid);
611 if (!scontext) {
612 ERR(NULL, "unrecognized SID %d", ssid);
613 rc = -EINVAL;
614 goto out;
615 }
616 tcontext = sepol_sidtab_search(sidtab, tsid);
617 if (!tcontext) {
618 ERR(NULL, "unrecognized SID %d", tsid);
619 rc = -EINVAL;
620 goto out;
621 }
622
623 context_init(&newcontext);
624
625 /* Set the user identity. */
626 switch (specified) {
627 case AVTAB_TRANSITION:
628 case AVTAB_CHANGE:
629 /* Use the process user identity. */
630 newcontext.user = scontext->user;
631 break;
632 case AVTAB_MEMBER:
633 /* Use the related object owner. */
634 newcontext.user = tcontext->user;
635 break;
636 }
637
638 /* Set the role and type to default values. */
639 switch (tclass) {
640 case SECCLASS_PROCESS:
641 /* Use the current role and type of process. */
642 newcontext.role = scontext->role;
643 newcontext.type = scontext->type;
644 break;
645 default:
646 /* Use the well-defined object role. */
647 newcontext.role = OBJECT_R_VAL;
648 /* Use the type of the related object. */
649 newcontext.type = tcontext->type;
650 }
651
652 /* Look for a type transition/member/change rule. */
653 avkey.source_type = scontext->type;
654 avkey.target_type = tcontext->type;
655 avkey.target_class = tclass;
656 avkey.specified = specified;
657 avdatum = avtab_search(&policydb->te_avtab, &avkey);
658
659 /* If no permanent rule, also check for enabled conditional rules */
660 if (!avdatum) {
661 node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
662 for (; node != NULL;
663 node = avtab_search_node_next(node, specified)) {
664 if (node->key.specified & AVTAB_ENABLED) {
665 avdatum = &node->datum;
666 break;
667 }
668 }
669 }
670
671 if (avdatum) {
672 /* Use the type from the type transition/member/change rule. */
673 newcontext.type = avdatum->data;
674 }
675
676 /* Check for class-specific changes. */
677 switch (tclass) {
678 case SECCLASS_PROCESS:
679 if (specified & AVTAB_TRANSITION) {
680 /* Look for a role transition rule. */
681 for (roletr = policydb->role_tr; roletr;
682 roletr = roletr->next) {
683 if (roletr->role == scontext->role &&
684 roletr->type == tcontext->type) {
685 /* Use the role transition rule. */
686 newcontext.role = roletr->new_role;
687 break;
688 }
689 }
690 }
691 break;
692 default:
693 break;
694 }
695
696 /* Set the MLS attributes.
697 This is done last because it may allocate memory. */
698 rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
699 &newcontext);
700 if (rc)
701 goto out;
702
703 /* Check the validity of the context. */
704 if (!policydb_context_isvalid(policydb, &newcontext)) {
705 rc = compute_sid_handle_invalid_context(scontext,
706 tcontext,
707 tclass, &newcontext);
708 if (rc)
709 goto out;
710 }
711 /* Obtain the sid for the context. */
712 rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid);
713 out:
714 context_destroy(&newcontext);
715 return rc;
716 }
717
718 /*
719 * Compute a SID to use for labeling a new object in the
720 * class `tclass' based on a SID pair.
721 */
sepol_transition_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)722 int hidden sepol_transition_sid(sepol_security_id_t ssid,
723 sepol_security_id_t tsid,
724 sepol_security_class_t tclass,
725 sepol_security_id_t * out_sid)
726 {
727 return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
728 }
729
730 /*
731 * Compute a SID to use when selecting a member of a
732 * polyinstantiated object of class `tclass' based on
733 * a SID pair.
734 */
sepol_member_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)735 int hidden sepol_member_sid(sepol_security_id_t ssid,
736 sepol_security_id_t tsid,
737 sepol_security_class_t tclass,
738 sepol_security_id_t * out_sid)
739 {
740 return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
741 }
742
743 /*
744 * Compute a SID to use for relabeling an object in the
745 * class `tclass' based on a SID pair.
746 */
sepol_change_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)747 int hidden sepol_change_sid(sepol_security_id_t ssid,
748 sepol_security_id_t tsid,
749 sepol_security_class_t tclass,
750 sepol_security_id_t * out_sid)
751 {
752 return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
753 }
754
755 /*
756 * Verify that each permission that is defined under the
757 * existing policy is still defined with the same value
758 * in the new policy.
759 */
validate_perm(hashtab_key_t key,hashtab_datum_t datum,void * p)760 static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
761 {
762 hashtab_t h;
763 perm_datum_t *perdatum, *perdatum2;
764
765 h = (hashtab_t) p;
766 perdatum = (perm_datum_t *) datum;
767
768 perdatum2 = (perm_datum_t *) hashtab_search(h, key);
769 if (!perdatum2) {
770 ERR(NULL, "permission %s disappeared", key);
771 return -1;
772 }
773 if (perdatum->s.value != perdatum2->s.value) {
774 ERR(NULL, "the value of permissions %s changed", key);
775 return -1;
776 }
777 return 0;
778 }
779
780 /*
781 * Verify that each class that is defined under the
782 * existing policy is still defined with the same
783 * attributes in the new policy.
784 */
validate_class(hashtab_key_t key,hashtab_datum_t datum,void * p)785 static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
786 {
787 policydb_t *newp;
788 class_datum_t *cladatum, *cladatum2;
789
790 newp = (policydb_t *) p;
791 cladatum = (class_datum_t *) datum;
792
793 cladatum2 =
794 (class_datum_t *) hashtab_search(newp->p_classes.table, key);
795 if (!cladatum2) {
796 ERR(NULL, "class %s disappeared", key);
797 return -1;
798 }
799 if (cladatum->s.value != cladatum2->s.value) {
800 ERR(NULL, "the value of class %s changed", key);
801 return -1;
802 }
803 if ((cladatum->comdatum && !cladatum2->comdatum) ||
804 (!cladatum->comdatum && cladatum2->comdatum)) {
805 ERR(NULL, "the inherits clause for the access "
806 "vector definition for class %s changed", key);
807 return -1;
808 }
809 if (cladatum->comdatum) {
810 if (hashtab_map
811 (cladatum->comdatum->permissions.table, validate_perm,
812 cladatum2->comdatum->permissions.table)) {
813 ERR(NULL,
814 " in the access vector definition "
815 "for class %s\n", key);
816 return -1;
817 }
818 }
819 if (hashtab_map(cladatum->permissions.table, validate_perm,
820 cladatum2->permissions.table)) {
821 ERR(NULL, " in access vector definition for class %s", key);
822 return -1;
823 }
824 return 0;
825 }
826
827 /* Clone the SID into the new SID table. */
clone_sid(sepol_security_id_t sid,context_struct_t * context,void * arg)828 static int clone_sid(sepol_security_id_t sid,
829 context_struct_t * context, void *arg)
830 {
831 sidtab_t *s = arg;
832
833 return sepol_sidtab_insert(s, sid, context);
834 }
835
convert_context_handle_invalid_context(context_struct_t * context)836 static inline int convert_context_handle_invalid_context(context_struct_t *
837 context)
838 {
839 if (selinux_enforcing) {
840 return -EINVAL;
841 } else {
842 sepol_security_context_t s;
843 size_t len;
844
845 context_to_string(NULL, policydb, context, &s, &len);
846 ERR(NULL, "context %s is invalid", s);
847 free(s);
848 return 0;
849 }
850 }
851
852 typedef struct {
853 policydb_t *oldp;
854 policydb_t *newp;
855 } convert_context_args_t;
856
857 /*
858 * Convert the values in the security context
859 * structure `c' from the values specified
860 * in the policy `p->oldp' to the values specified
861 * in the policy `p->newp'. Verify that the
862 * context is valid under the new policy.
863 */
convert_context(sepol_security_id_t key,context_struct_t * c,void * p)864 static int convert_context(sepol_security_id_t key __attribute__ ((unused)),
865 context_struct_t * c, void *p)
866 {
867 convert_context_args_t *args;
868 context_struct_t oldc;
869 role_datum_t *role;
870 type_datum_t *typdatum;
871 user_datum_t *usrdatum;
872 sepol_security_context_t s;
873 size_t len;
874 int rc = -EINVAL;
875
876 args = (convert_context_args_t *) p;
877
878 if (context_cpy(&oldc, c))
879 return -ENOMEM;
880
881 /* Convert the user. */
882 usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table,
883 args->oldp->
884 p_user_val_to_name[c->user -
885 1]);
886
887 if (!usrdatum) {
888 goto bad;
889 }
890 c->user = usrdatum->s.value;
891
892 /* Convert the role. */
893 role = (role_datum_t *) hashtab_search(args->newp->p_roles.table,
894 args->oldp->
895 p_role_val_to_name[c->role - 1]);
896 if (!role) {
897 goto bad;
898 }
899 c->role = role->s.value;
900
901 /* Convert the type. */
902 typdatum = (type_datum_t *)
903 hashtab_search(args->newp->p_types.table,
904 args->oldp->p_type_val_to_name[c->type - 1]);
905 if (!typdatum) {
906 goto bad;
907 }
908 c->type = typdatum->s.value;
909
910 rc = mls_convert_context(args->oldp, args->newp, c);
911 if (rc)
912 goto bad;
913
914 /* Check the validity of the new context. */
915 if (!policydb_context_isvalid(args->newp, c)) {
916 rc = convert_context_handle_invalid_context(&oldc);
917 if (rc)
918 goto bad;
919 }
920
921 context_destroy(&oldc);
922 return 0;
923
924 bad:
925 context_to_string(NULL, policydb, &oldc, &s, &len);
926 context_destroy(&oldc);
927 ERR(NULL, "invalidating context %s", s);
928 free(s);
929 return rc;
930 }
931
932 /* Reading from a policy "file". */
next_entry(void * buf,struct policy_file * fp,size_t bytes)933 int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes)
934 {
935 size_t nread;
936
937 switch (fp->type) {
938 case PF_USE_STDIO:
939 nread = fread(buf, bytes, 1, fp->fp);
940
941 if (nread != 1)
942 return -1;
943 break;
944 case PF_USE_MEMORY:
945 if (bytes > fp->len)
946 return -1;
947 memcpy(buf, fp->data, bytes);
948 fp->data += bytes;
949 fp->len -= bytes;
950 break;
951 default:
952 return -1;
953 }
954 return 0;
955 }
956
put_entry(const void * ptr,size_t size,size_t n,struct policy_file * fp)957 size_t hidden put_entry(const void *ptr, size_t size, size_t n,
958 struct policy_file *fp)
959 {
960 size_t bytes = size * n;
961
962 switch (fp->type) {
963 case PF_USE_STDIO:
964 return fwrite(ptr, size, n, fp->fp);
965 case PF_USE_MEMORY:
966 if (bytes > fp->len) {
967 errno = ENOSPC;
968 return 0;
969 }
970
971 memcpy(fp->data, ptr, bytes);
972 fp->data += bytes;
973 fp->len -= bytes;
974 return n;
975 case PF_LEN:
976 fp->len += bytes;
977 return n;
978 default:
979 return 0;
980 }
981 return 0;
982 }
983
984 /*
985 * Read a new set of configuration data from
986 * a policy database binary representation file.
987 *
988 * Verify that each class that is defined under the
989 * existing policy is still defined with the same
990 * attributes in the new policy.
991 *
992 * Convert the context structures in the SID table to the
993 * new representation and verify that all entries
994 * in the SID table are valid under the new policy.
995 *
996 * Change the active policy database to use the new
997 * configuration data.
998 *
999 * Reset the access vector cache.
1000 */
sepol_load_policy(void * data,size_t len)1001 int hidden sepol_load_policy(void *data, size_t len)
1002 {
1003 policydb_t oldpolicydb, newpolicydb;
1004 sidtab_t oldsidtab, newsidtab;
1005 convert_context_args_t args;
1006 int rc = 0;
1007 struct policy_file file, *fp;
1008
1009 policy_file_init(&file);
1010 file.type = PF_USE_MEMORY;
1011 file.data = data;
1012 file.len = len;
1013 fp = &file;
1014
1015 if (policydb_init(&newpolicydb))
1016 return -ENOMEM;
1017
1018 if (policydb_read(&newpolicydb, fp, 1)) {
1019 return -EINVAL;
1020 }
1021
1022 sepol_sidtab_init(&newsidtab);
1023
1024 /* Verify that the existing classes did not change. */
1025 if (hashtab_map
1026 (policydb->p_classes.table, validate_class, &newpolicydb)) {
1027 ERR(NULL, "the definition of an existing class changed");
1028 rc = -EINVAL;
1029 goto err;
1030 }
1031
1032 /* Clone the SID table. */
1033 sepol_sidtab_shutdown(sidtab);
1034 if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) {
1035 rc = -ENOMEM;
1036 goto err;
1037 }
1038
1039 /* Convert the internal representations of contexts
1040 in the new SID table and remove invalid SIDs. */
1041 args.oldp = policydb;
1042 args.newp = &newpolicydb;
1043 sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
1044
1045 /* Save the old policydb and SID table to free later. */
1046 memcpy(&oldpolicydb, policydb, sizeof *policydb);
1047 sepol_sidtab_set(&oldsidtab, sidtab);
1048
1049 /* Install the new policydb and SID table. */
1050 memcpy(policydb, &newpolicydb, sizeof *policydb);
1051 sepol_sidtab_set(sidtab, &newsidtab);
1052
1053 /* Free the old policydb and SID table. */
1054 policydb_destroy(&oldpolicydb);
1055 sepol_sidtab_destroy(&oldsidtab);
1056
1057 return 0;
1058
1059 err:
1060 sepol_sidtab_destroy(&newsidtab);
1061 policydb_destroy(&newpolicydb);
1062 return rc;
1063
1064 }
1065
1066 /*
1067 * Return the SIDs to use for an unlabeled file system
1068 * that is being mounted from the device with the
1069 * the kdevname `name'. The `fs_sid' SID is returned for
1070 * the file system and the `file_sid' SID is returned
1071 * for all files within that file system.
1072 */
sepol_fs_sid(char * name,sepol_security_id_t * fs_sid,sepol_security_id_t * file_sid)1073 int hidden sepol_fs_sid(char *name,
1074 sepol_security_id_t * fs_sid,
1075 sepol_security_id_t * file_sid)
1076 {
1077 int rc = 0;
1078 ocontext_t *c;
1079
1080 c = policydb->ocontexts[OCON_FS];
1081 while (c) {
1082 if (strcmp(c->u.name, name) == 0)
1083 break;
1084 c = c->next;
1085 }
1086
1087 if (c) {
1088 if (!c->sid[0] || !c->sid[1]) {
1089 rc = sepol_sidtab_context_to_sid(sidtab,
1090 &c->context[0],
1091 &c->sid[0]);
1092 if (rc)
1093 goto out;
1094 rc = sepol_sidtab_context_to_sid(sidtab,
1095 &c->context[1],
1096 &c->sid[1]);
1097 if (rc)
1098 goto out;
1099 }
1100 *fs_sid = c->sid[0];
1101 *file_sid = c->sid[1];
1102 } else {
1103 *fs_sid = SECINITSID_FS;
1104 *file_sid = SECINITSID_FILE;
1105 }
1106
1107 out:
1108 return rc;
1109 }
1110
1111 /*
1112 * Return the SID of the port specified by
1113 * `domain', `type', `protocol', and `port'.
1114 */
sepol_port_sid(uint16_t domain,uint16_t type,uint8_t protocol,uint16_t port,sepol_security_id_t * out_sid)1115 int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)),
1116 uint16_t type __attribute__ ((unused)),
1117 uint8_t protocol,
1118 uint16_t port, sepol_security_id_t * out_sid)
1119 {
1120 ocontext_t *c;
1121 int rc = 0;
1122
1123 c = policydb->ocontexts[OCON_PORT];
1124 while (c) {
1125 if (c->u.port.protocol == protocol &&
1126 c->u.port.low_port <= port && c->u.port.high_port >= port)
1127 break;
1128 c = c->next;
1129 }
1130
1131 if (c) {
1132 if (!c->sid[0]) {
1133 rc = sepol_sidtab_context_to_sid(sidtab,
1134 &c->context[0],
1135 &c->sid[0]);
1136 if (rc)
1137 goto out;
1138 }
1139 *out_sid = c->sid[0];
1140 } else {
1141 *out_sid = SECINITSID_PORT;
1142 }
1143
1144 out:
1145 return rc;
1146 }
1147
1148 /*
1149 * Return the SIDs to use for a network interface
1150 * with the name `name'. The `if_sid' SID is returned for
1151 * the interface and the `msg_sid' SID is returned as
1152 * the default SID for messages received on the
1153 * interface.
1154 */
sepol_netif_sid(char * name,sepol_security_id_t * if_sid,sepol_security_id_t * msg_sid)1155 int hidden sepol_netif_sid(char *name,
1156 sepol_security_id_t * if_sid,
1157 sepol_security_id_t * msg_sid)
1158 {
1159 int rc = 0;
1160 ocontext_t *c;
1161
1162 c = policydb->ocontexts[OCON_NETIF];
1163 while (c) {
1164 if (strcmp(name, c->u.name) == 0)
1165 break;
1166 c = c->next;
1167 }
1168
1169 if (c) {
1170 if (!c->sid[0] || !c->sid[1]) {
1171 rc = sepol_sidtab_context_to_sid(sidtab,
1172 &c->context[0],
1173 &c->sid[0]);
1174 if (rc)
1175 goto out;
1176 rc = sepol_sidtab_context_to_sid(sidtab,
1177 &c->context[1],
1178 &c->sid[1]);
1179 if (rc)
1180 goto out;
1181 }
1182 *if_sid = c->sid[0];
1183 *msg_sid = c->sid[1];
1184 } else {
1185 *if_sid = SECINITSID_NETIF;
1186 *msg_sid = SECINITSID_NETMSG;
1187 }
1188
1189 out:
1190 return rc;
1191 }
1192
match_ipv6_addrmask(uint32_t * input,uint32_t * addr,uint32_t * mask)1193 static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr,
1194 uint32_t * mask)
1195 {
1196 int i, fail = 0;
1197
1198 for (i = 0; i < 4; i++)
1199 if (addr[i] != (input[i] & mask[i])) {
1200 fail = 1;
1201 break;
1202 }
1203
1204 return !fail;
1205 }
1206
1207 /*
1208 * Return the SID of the node specified by the address
1209 * `addrp' where `addrlen' is the length of the address
1210 * in bytes and `domain' is the communications domain or
1211 * address family in which the address should be interpreted.
1212 */
sepol_node_sid(uint16_t domain,void * addrp,size_t addrlen,sepol_security_id_t * out_sid)1213 int hidden sepol_node_sid(uint16_t domain,
1214 void *addrp,
1215 size_t addrlen, sepol_security_id_t * out_sid)
1216 {
1217 int rc = 0;
1218 ocontext_t *c;
1219
1220 switch (domain) {
1221 case AF_INET:{
1222 uint32_t addr;
1223
1224 if (addrlen != sizeof(uint32_t)) {
1225 rc = -EINVAL;
1226 goto out;
1227 }
1228
1229 addr = *((uint32_t *) addrp);
1230
1231 c = policydb->ocontexts[OCON_NODE];
1232 while (c) {
1233 if (c->u.node.addr == (addr & c->u.node.mask))
1234 break;
1235 c = c->next;
1236 }
1237 break;
1238 }
1239
1240 case AF_INET6:
1241 if (addrlen != sizeof(uint64_t) * 2) {
1242 rc = -EINVAL;
1243 goto out;
1244 }
1245
1246 c = policydb->ocontexts[OCON_NODE6];
1247 while (c) {
1248 if (match_ipv6_addrmask(addrp, c->u.node6.addr,
1249 c->u.node6.mask))
1250 break;
1251 c = c->next;
1252 }
1253 break;
1254
1255 default:
1256 *out_sid = SECINITSID_NODE;
1257 goto out;
1258 }
1259
1260 if (c) {
1261 if (!c->sid[0]) {
1262 rc = sepol_sidtab_context_to_sid(sidtab,
1263 &c->context[0],
1264 &c->sid[0]);
1265 if (rc)
1266 goto out;
1267 }
1268 *out_sid = c->sid[0];
1269 } else {
1270 *out_sid = SECINITSID_NODE;
1271 }
1272
1273 out:
1274 return rc;
1275 }
1276
1277 /*
1278 * Generate the set of SIDs for legal security contexts
1279 * for a given user that can be reached by `fromsid'.
1280 * Set `*sids' to point to a dynamically allocated
1281 * array containing the set of SIDs. Set `*nel' to the
1282 * number of elements in the array.
1283 */
1284 #define SIDS_NEL 25
1285
sepol_get_user_sids(sepol_security_id_t fromsid,char * username,sepol_security_id_t ** sids,uint32_t * nel)1286 int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
1287 char *username,
1288 sepol_security_id_t ** sids, uint32_t * nel)
1289 {
1290 context_struct_t *fromcon, usercon;
1291 sepol_security_id_t *mysids, *mysids2, sid;
1292 uint32_t mynel = 0, maxnel = SIDS_NEL;
1293 user_datum_t *user;
1294 role_datum_t *role;
1295 struct sepol_av_decision avd;
1296 int rc = 0;
1297 unsigned int i, j, reason;
1298 ebitmap_node_t *rnode, *tnode;
1299
1300 fromcon = sepol_sidtab_search(sidtab, fromsid);
1301 if (!fromcon) {
1302 rc = -EINVAL;
1303 goto out;
1304 }
1305
1306 user = (user_datum_t *) hashtab_search(policydb->p_users.table,
1307 username);
1308 if (!user) {
1309 rc = -EINVAL;
1310 goto out;
1311 }
1312 usercon.user = user->s.value;
1313
1314 mysids = malloc(maxnel * sizeof(sepol_security_id_t));
1315 if (!mysids) {
1316 rc = -ENOMEM;
1317 goto out;
1318 }
1319 memset(mysids, 0, maxnel * sizeof(sepol_security_id_t));
1320
1321 ebitmap_for_each_bit(&user->roles.roles, rnode, i) {
1322 if (!ebitmap_node_get_bit(rnode, i))
1323 continue;
1324 role = policydb->role_val_to_struct[i];
1325 usercon.role = i + 1;
1326 ebitmap_for_each_bit(&role->types.types, tnode, j) {
1327 if (!ebitmap_node_get_bit(tnode, j))
1328 continue;
1329 usercon.type = j + 1;
1330 if (usercon.type == fromcon->type)
1331 continue;
1332
1333 if (mls_setup_user_range
1334 (fromcon, user, &usercon, policydb->mls))
1335 continue;
1336
1337 rc = context_struct_compute_av(fromcon, &usercon,
1338 SECCLASS_PROCESS,
1339 PROCESS__TRANSITION,
1340 &avd, &reason);
1341 if (rc || !(avd.allowed & PROCESS__TRANSITION))
1342 continue;
1343 rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
1344 &sid);
1345 if (rc) {
1346 free(mysids);
1347 goto out;
1348 }
1349 if (mynel < maxnel) {
1350 mysids[mynel++] = sid;
1351 } else {
1352 maxnel += SIDS_NEL;
1353 mysids2 =
1354 malloc(maxnel *
1355 sizeof(sepol_security_id_t));
1356
1357 if (!mysids2) {
1358 rc = -ENOMEM;
1359 free(mysids);
1360 goto out;
1361 }
1362 memset(mysids2, 0,
1363 maxnel * sizeof(sepol_security_id_t));
1364 memcpy(mysids2, mysids,
1365 mynel * sizeof(sepol_security_id_t));
1366 free(mysids);
1367 mysids = mysids2;
1368 mysids[mynel++] = sid;
1369 }
1370 }
1371 }
1372
1373 *sids = mysids;
1374 *nel = mynel;
1375
1376 out:
1377 return rc;
1378 }
1379
1380 /*
1381 * Return the SID to use for a file in a filesystem
1382 * that cannot support a persistent label mapping or use another
1383 * fixed labeling behavior like transition SIDs or task SIDs.
1384 */
sepol_genfs_sid(const char * fstype,char * path,sepol_security_class_t sclass,sepol_security_id_t * sid)1385 int hidden sepol_genfs_sid(const char *fstype,
1386 char *path,
1387 sepol_security_class_t sclass,
1388 sepol_security_id_t * sid)
1389 {
1390 size_t len;
1391 genfs_t *genfs;
1392 ocontext_t *c;
1393 int rc = 0, cmp = 0;
1394
1395 for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
1396 cmp = strcmp(fstype, genfs->fstype);
1397 if (cmp <= 0)
1398 break;
1399 }
1400
1401 if (!genfs || cmp) {
1402 *sid = SECINITSID_UNLABELED;
1403 rc = -ENOENT;
1404 goto out;
1405 }
1406
1407 for (c = genfs->head; c; c = c->next) {
1408 len = strlen(c->u.name);
1409 if ((!c->v.sclass || sclass == c->v.sclass) &&
1410 (strncmp(c->u.name, path, len) == 0))
1411 break;
1412 }
1413
1414 if (!c) {
1415 *sid = SECINITSID_UNLABELED;
1416 rc = -ENOENT;
1417 goto out;
1418 }
1419
1420 if (!c->sid[0]) {
1421 rc = sepol_sidtab_context_to_sid(sidtab,
1422 &c->context[0], &c->sid[0]);
1423 if (rc)
1424 goto out;
1425 }
1426
1427 *sid = c->sid[0];
1428 out:
1429 return rc;
1430 }
1431
sepol_fs_use(const char * fstype,unsigned int * behavior,sepol_security_id_t * sid)1432 int hidden sepol_fs_use(const char *fstype,
1433 unsigned int *behavior, sepol_security_id_t * sid)
1434 {
1435 int rc = 0;
1436 ocontext_t *c;
1437
1438 c = policydb->ocontexts[OCON_FSUSE];
1439 while (c) {
1440 if (strcmp(fstype, c->u.name) == 0)
1441 break;
1442 c = c->next;
1443 }
1444
1445 if (c) {
1446 *behavior = c->v.behavior;
1447 if (!c->sid[0]) {
1448 rc = sepol_sidtab_context_to_sid(sidtab,
1449 &c->context[0],
1450 &c->sid[0]);
1451 if (rc)
1452 goto out;
1453 }
1454 *sid = c->sid[0];
1455 } else {
1456 rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
1457 if (rc) {
1458 *behavior = SECURITY_FS_USE_NONE;
1459 rc = 0;
1460 } else {
1461 *behavior = SECURITY_FS_USE_GENFS;
1462 }
1463 }
1464
1465 out:
1466 return rc;
1467 }
1468
1469 /* FLASK */
1470