Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright 2011 Tresys Technology, LLC. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  *
      7  *    1. Redistributions of source code must retain the above copyright notice,
      8  *       this list of conditions and the following disclaimer.
      9  *
     10  *    2. Redistributions in binary form must reproduce the above copyright notice,
     11  *       this list of conditions and the following disclaimer in the documentation
     12  *       and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
     15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     17  * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     22  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  *
     25  * The views and conclusions contained in the software and documentation are those
     26  * of the authors and should not be interpreted as representing official policies,
     27  * either expressed or implied, of Tresys Technology, LLC.
     28  */
     29 
     30 #include <sepol/policydb/ebitmap.h>
     31 
     32 #include "cil_internal.h"
     33 #include "cil_flavor.h"
     34 #include "cil_list.h"
     35 #include "cil_log.h"
     36 #include "cil_symtab.h"
     37 
     38 struct cil_args_find {
     39 	enum cil_flavor flavor;
     40 	void *target;
     41 	struct cil_list *matching;
     42 	int match_self;
     43 };
     44 
     45 static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
     46 {
     47 	enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
     48 	enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
     49 
     50 	if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
     51 		struct cil_type *t1 = (struct cil_type *)d1;
     52 		struct cil_type *t2 = (struct cil_type *)d2;
     53 		if (t1->value == t2->value) {
     54 			return CIL_TRUE;
     55 		}
     56 	} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
     57 		struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
     58 		struct cil_type *t = (struct cil_type *)d2;
     59 		if (ebitmap_get_bit(a->types, t->value)) {
     60 			return CIL_TRUE;
     61 		}
     62 	} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
     63 		struct cil_type *t = (struct cil_type *)d1;
     64 		struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
     65 		if (ebitmap_get_bit(a->types, t->value)) {
     66 			return CIL_TRUE;
     67 		}
     68 	} else {
     69 		/* Both are attributes */
     70 		struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
     71 		struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
     72 		if (d1 == d2) {
     73 			return CIL_TRUE;
     74 		} else if (ebitmap_match_any(a1->types, a2->types)) {
     75 			return CIL_TRUE;
     76 		}
     77 	}
     78 	return CIL_FALSE;
     79 }
     80 
     81 static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
     82 {
     83 	int rc = SEPOL_OK;
     84 	enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
     85 	enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
     86 
     87 	if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
     88 		struct cil_type *t1 = (struct cil_type *)d1;
     89 		struct cil_type *t2 = (struct cil_type *)d2;
     90 		if (t1->value == t2->value) {
     91 			ebitmap_set_bit(matches, t1->value, 1);
     92 		}
     93 	} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
     94 		struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
     95 		struct cil_type *t = (struct cil_type *)d2;
     96 		if (ebitmap_get_bit(a->types, t->value)) {
     97 			ebitmap_set_bit(matches, t->value, 1);
     98 		}
     99 	} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
    100 		struct cil_type *t = (struct cil_type *)d1;
    101 		struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
    102 		if (ebitmap_get_bit(a->types, t->value)) {
    103 			ebitmap_set_bit(matches, t->value, 1);
    104 		}
    105 	} else {
    106 		/* Both are attributes */
    107 		struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
    108 		struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
    109 		rc = ebitmap_and(matches, a1->types, a2->types);
    110 	}
    111 
    112 	return rc;
    113 }
    114 
    115 /* s1 is the src type that is matched with a self
    116  * s2, and t2 are the source and type of the other rule
    117  */
    118 static int cil_self_match_any(struct cil_symtab_datum *s1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2)
    119 {
    120 	int rc;
    121 	struct cil_tree_node *n1 = s1->nodes->head->data;
    122 	if (n1->flavor != CIL_TYPEATTRIBUTE) {
    123 		rc = cil_type_match_any(s1, t2);
    124 	} else {
    125 		struct cil_typeattribute *a = (struct cil_typeattribute *)s1;
    126 		ebitmap_t map;
    127 		ebitmap_init(&map);
    128 		rc = cil_type_matches(&map, s2, t2);
    129 		if (rc < 0) {
    130 			ebitmap_destroy(&map);
    131 			goto exit;
    132 		}
    133 		if (map.node == NULL) {
    134 			rc = CIL_FALSE;
    135 			goto exit;
    136 		}
    137 		rc = ebitmap_match_any(&map, a->types);
    138 		ebitmap_destroy(&map);
    139 	}
    140 
    141 exit:
    142 	return rc;
    143 }
    144 
    145 static int cil_classperms_match_any(struct cil_classperms *cp1, struct cil_classperms *cp2)
    146 {
    147 	struct cil_class *c1 = cp1->class;
    148 	struct cil_class *c2 = cp2->class;
    149 	struct cil_list_item *i1, *i2;
    150 
    151 	if (&c1->datum != &c2->datum) return CIL_FALSE;
    152 
    153 	cil_list_for_each(i1, cp1->perms) {
    154 		struct cil_perm *p1 = i1->data;
    155 		cil_list_for_each(i2, cp2->perms) {
    156 			struct cil_perm *p2 = i2->data;
    157 			if (&p1->datum == &p2->datum) return CIL_TRUE;
    158 		}
    159 	}
    160 	return CIL_FALSE;
    161 }
    162 
    163 static int __cil_classperms_list_match_any(struct cil_classperms *cp1, struct cil_list *cpl2)
    164 {
    165 	int rc;
    166 	struct cil_list_item *curr;
    167 
    168 	cil_list_for_each(curr, cpl2) {
    169 		if (curr->flavor == CIL_CLASSPERMS) {
    170 			struct cil_classperms *cp = curr->data;
    171 			if (FLAVOR(cp->class) == CIL_CLASS) {
    172 				rc = cil_classperms_match_any(cp1, cp);
    173 				if (rc == CIL_TRUE) return CIL_TRUE;
    174 			} else { /* MAP */
    175 				struct cil_list_item *i = NULL;
    176 				cil_list_for_each(i, cp->perms) {
    177 					struct cil_perm *cmp = i->data;
    178 					rc = __cil_classperms_list_match_any(cp1, cmp->classperms);
    179 					if (rc == CIL_TRUE) return CIL_TRUE;
    180 				}
    181 			}
    182 		} else { /* SET */
    183 			struct cil_classperms_set *cp_set = curr->data;
    184 			struct cil_classpermission *cp = cp_set->set;
    185 			rc = __cil_classperms_list_match_any(cp1, cp->classperms);
    186 			if (rc == CIL_TRUE) return CIL_TRUE;
    187 		}
    188 	}
    189 	return CIL_FALSE;
    190 }
    191 
    192 static int cil_classperms_list_match_any(struct cil_list *cpl1, struct cil_list *cpl2)
    193 {
    194 	int rc;
    195 	struct cil_list_item *curr;
    196 
    197 	cil_list_for_each(curr, cpl1) {
    198 		if (curr->flavor == CIL_CLASSPERMS) {
    199 			struct cil_classperms *cp = curr->data;
    200 			if (FLAVOR(cp->class) == CIL_CLASS) {
    201 				rc = __cil_classperms_list_match_any(cp, cpl2);
    202 				if (rc == CIL_TRUE) return CIL_TRUE;
    203 			} else { /* MAP */
    204 				struct cil_list_item *i = NULL;
    205 				cil_list_for_each(i, cp->perms) {
    206 					struct cil_perm *cmp = i->data;
    207 					rc = cil_classperms_list_match_any(cmp->classperms, cpl2);
    208 					if (rc == CIL_TRUE) return CIL_TRUE;
    209 				}
    210 			}
    211 		} else { /* SET */
    212 			struct cil_classperms_set *cp_set = curr->data;
    213 			struct cil_classpermission *cp = cp_set->set;
    214 			rc = cil_classperms_list_match_any(cp->classperms, cpl2);
    215 			if (rc == CIL_TRUE) return CIL_TRUE;
    216 		}
    217 	}
    218 	return CIL_FALSE;
    219 }
    220 
    221 static void __add_classes_from_classperms_list(struct cil_list *classperms, struct cil_list *class_list)
    222 {
    223 	struct cil_list_item *curr;
    224 
    225 	cil_list_for_each(curr, classperms) {
    226 		if (curr->flavor == CIL_CLASSPERMS) {
    227 			struct cil_classperms *cp = curr->data;
    228 			if (FLAVOR(cp->class) == CIL_CLASS) {
    229 				cil_list_append(class_list, CIL_CLASS, cp->class);
    230 			} else { /* MAP */
    231 				struct cil_list_item *i = NULL;
    232 				cil_list_for_each(i, cp->perms) {
    233 					struct cil_perm *cmp = i->data;
    234 					__add_classes_from_classperms_list(cmp->classperms, class_list);
    235 				}
    236 			}
    237 		} else { /* SET */
    238 			struct cil_classperms_set *cp_set = curr->data;
    239 			struct cil_classpermission *cp = cp_set->set;
    240 			__add_classes_from_classperms_list(cp->classperms, class_list);
    241 		}
    242 	}
    243 }
    244 
    245 static int __add_classes_from_map_perms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
    246 {
    247 	struct cil_list *class_list = args;
    248 	struct cil_perm *cmp = (struct cil_perm *)d;
    249 
    250 	__add_classes_from_classperms_list(cmp->classperms, class_list);
    251 
    252 	return SEPOL_OK;
    253 }
    254 
    255 struct cil_list *cil_expand_class(struct cil_class *class)
    256 {
    257 	struct cil_list *class_list;
    258 
    259 	cil_list_init(&class_list, CIL_CLASS);
    260 
    261 	if (FLAVOR(class) == CIL_CLASS) {
    262 		cil_list_append(class_list, CIL_CLASS, class);
    263 	} else { /* MAP */
    264 		cil_symtab_map(&class->perms, __add_classes_from_map_perms, class_list);
    265 	}
    266 
    267 	return class_list;
    268 }
    269 
    270 static int cil_permissionx_match_any(struct cil_permissionx *px1, struct cil_permissionx *px2)
    271 {
    272 	int rc = CIL_FALSE;
    273 	struct cil_list *cl1 = NULL;
    274 	struct cil_list *cl2 = NULL;
    275 
    276 	if (px1->kind != px2->kind) goto exit;
    277 
    278 	if (!ebitmap_match_any(px1->perms, px2->perms)) goto exit;
    279 
    280 	cl1 = cil_expand_class(px1->obj);
    281 	cl2 = cil_expand_class(px2->obj);
    282 
    283 	if (!cil_list_match_any(cl1, cl2)) goto exit;
    284 
    285 	rc = CIL_TRUE;
    286 
    287 exit:
    288 	cil_list_destroy(&cl1, CIL_FALSE);
    289 	cil_list_destroy(&cl2, CIL_FALSE);
    290 
    291 	return rc;
    292 }
    293 
    294 int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self)
    295 {
    296 	int rc = SEPOL_OK;
    297 	struct cil_symtab_datum *s1 = avrule->src;
    298 	struct cil_symtab_datum *t1 = avrule->tgt;
    299 	struct cil_symtab_datum *s2 = target->src;
    300 	struct cil_symtab_datum *t2 = target->tgt;
    301 
    302 	if (match_self != CIL_TRUE && avrule == target) goto exit;
    303 
    304 	if (avrule->rule_kind != target->rule_kind) goto exit;
    305 
    306 	if (avrule->is_extended != target->is_extended) goto exit;
    307 
    308 	if (!cil_type_match_any(s1, s2)) goto exit;
    309 
    310 	if (t1->fqn != CIL_KEY_SELF && t2->fqn != CIL_KEY_SELF) {
    311 		if (!cil_type_match_any(t1, t2)) goto exit;
    312 	} else {
    313 		if (t1->fqn == CIL_KEY_SELF && t2->fqn == CIL_KEY_SELF) {
    314 			/* The earlier check whether s1 and s2 matches is all that is needed */
    315 		} else if (t1->fqn == CIL_KEY_SELF) {
    316 			rc = cil_self_match_any(s1, s2, t2);
    317 			if (rc < 0) {
    318 				goto exit;
    319 			} else if (rc == CIL_FALSE) {
    320 				rc = SEPOL_OK;
    321 				goto exit;
    322 			}
    323 		} else if (t2->fqn == CIL_KEY_SELF) {
    324 			rc = cil_self_match_any(s2, s1, t1);
    325 			if (rc < 0) {
    326 				goto exit;
    327 			} else if (rc == CIL_FALSE) {
    328 				rc = SEPOL_OK;
    329 				goto exit;
    330 			}
    331 		}
    332 	}
    333 
    334 	if (!target->is_extended) {
    335 		if (cil_classperms_list_match_any(avrule->perms.classperms, target->perms.classperms)) {
    336 			cil_list_append(matching, CIL_NODE, node);
    337 		}
    338 	} else {
    339 		if (cil_permissionx_match_any(avrule->perms.x.permx, target->perms.x.permx)) {
    340 			cil_list_append(matching, CIL_NODE, node);
    341 		}
    342 	}
    343 
    344 	rc = SEPOL_OK;
    345 
    346 exit:
    347 	return rc;
    348 }
    349 
    350 static int __cil_find_matching_avrule_in_ast(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
    351 {
    352 	int rc = SEPOL_OK;
    353 	struct cil_args_find *args = extra_args;
    354 
    355 	if (node->flavor == CIL_BLOCK) {
    356 		struct cil_block *blk = node->data;
    357 		if (blk->is_abstract == CIL_TRUE) {
    358 			*finished = CIL_TREE_SKIP_HEAD;
    359 			goto exit;
    360 		}
    361 	} else if (node->flavor == CIL_MACRO) {
    362 		*finished = CIL_TREE_SKIP_HEAD;
    363 		goto exit;
    364 	} else if (node->flavor == CIL_AVRULE || node->flavor == CIL_AVRULEX) {
    365 		if (node->flavor == args->flavor) {
    366 			rc = cil_find_matching_avrule(node, node->data, args->target, args->matching, args->match_self);
    367 		}
    368 	}
    369 
    370 exit:
    371 	return rc;
    372 }
    373 
    374 int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self)
    375 {
    376 	int rc;
    377 	struct cil_args_find args;
    378 
    379 	args.flavor = flavor;
    380 	args.target = target;
    381 	args.matching = matching;
    382 	args.match_self = match_self;
    383 
    384 	rc = cil_tree_walk(current, __cil_find_matching_avrule_in_ast, NULL, NULL, &args);
    385 	if (rc) {
    386 		cil_log(CIL_ERR, "An error occurred while searching for avrule in AST\n");
    387 	}
    388 
    389 	return rc;
    390 }
    391