Home | History | Annotate | Download | only in src
      1 #include <cil/android.h>
      2 #include <sepol/policydb/hashtab.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 
      6 #include "cil_build_ast.h"
      7 #include "cil_internal.h"
      8 #include "cil_strpool.h"
      9 #include "cil_symtab.h"
     10 #include "cil_tree.h"
     11 
     12 #define VER_MAP_SZ (1 << 12)
     13 
     14 /* added to hashmap - currently unused as hashmap is used as a set */
     15 struct version_datum {
     16 	struct cil_db *db;
     17 	struct cil_tree_node *ast_node;
     18 	char *orig_name;
     19 };
     20 
     21 struct version_args {
     22 	struct cil_db *db;
     23 	hashtab_t vers_map;
     24 	const char *num;
     25 };
     26 
     27 enum plat_flavor {
     28 	PLAT_NONE = 0,
     29 	PLAT_TYPE,
     30 	PLAT_ATTRIB
     31 };
     32 
     33 static unsigned int ver_map_hash_val(hashtab_t h, const_hashtab_key_t key)
     34 {
     35 	/* from cil_stpool.c */
     36 	char *p, *keyp;
     37 	size_t size;
     38 	unsigned int val;
     39 
     40 	val = 0;
     41 	keyp = (char*)key;
     42 	size = strlen(keyp);
     43 	for (p = keyp; ((size_t) (p - keyp)) < size; p++)
     44 		val =
     45 			(val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
     46 	return val & (h->size - 1);
     47 }
     48 
     49 
     50 static int ver_map_key_cmp(hashtab_t h __attribute__ ((unused)),
     51 			   const_hashtab_key_t key1, const_hashtab_key_t key2)
     52 {
     53 	/* hashtab_key_t is just a const char* underneath */
     54 	return strcmp(key1, key2);
     55 }
     56 
     57 /*
     58  * version_datum  pointers all refer to memory owned elsewhere, so just free the
     59  * datum itself.
     60  */
     61 static int ver_map_entry_destroy(__attribute__ ((unused))hashtab_key_t k,
     62 				 hashtab_datum_t d, __attribute__ ((unused))void *args)
     63 {
     64 	free(d);
     65 	return 0;
     66 }
     67 
     68 static void ver_map_destroy(hashtab_t h)
     69 {
     70 	hashtab_map(h, ver_map_entry_destroy, NULL);
     71 	hashtab_destroy(h);
     72 }
     73 
     74 static int __extract_attributees_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
     75 {
     76 	int rc = SEPOL_ERR;
     77 	struct version_args *args = (struct version_args *) extra_args;
     78 	char *key;
     79 	struct version_datum *datum;
     80 
     81 	if (node == NULL || finished == NULL || extra_args == NULL) {
     82 		goto exit;
     83 	}
     84 
     85 	switch (node->flavor) {
     86 	case CIL_ROLE:
     87 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
     88 			CIL_KEY_ROLE, node->line);
     89 		rc = SEPOL_ERR;
     90 		break;
     91 	case CIL_TYPE:
     92 	case CIL_TYPEATTRIBUTE:
     93 		datum = cil_malloc(sizeof(*datum));
     94 		datum->db = args->db;
     95 		datum->ast_node = node;
     96 		datum->orig_name = DATUM(node->data)->name;
     97 		key = datum->orig_name;
     98 		if (!strncmp(key, "base_typeattr_", 14)) {
     99 			/* checkpolicy creates base attributes which are just typeattributesets,
    100 			   of the existing types and attributes.  These may be differnt in
    101 			   every checkpolicy output, ignore them here, they'll be dealt with
    102 			   as a special case when attributizing. */
    103 			free(datum);
    104 		} else {
    105 			rc = hashtab_insert(args->vers_map, (hashtab_key_t) key, (hashtab_datum_t) datum);
    106 			if (rc != SEPOL_OK) {
    107 				goto exit;
    108 			}
    109 		}
    110 		break;
    111 	case CIL_TYPEALIAS:
    112 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
    113 			CIL_KEY_TYPEALIAS, node->line);
    114 		goto exit;
    115 		break;
    116 	case CIL_TYPEPERMISSIVE:
    117 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
    118 			CIL_KEY_TYPEPERMISSIVE, node->line);
    119 		goto exit;
    120 		break;
    121 	case CIL_NAMETYPETRANSITION:
    122 	case CIL_TYPE_RULE:
    123 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
    124 			CIL_KEY_TYPETRANSITION, node->line);
    125 		goto exit;
    126 		break;
    127 	default:
    128 		break;
    129 	}
    130 	return SEPOL_OK;
    131 exit:
    132 	return rc;
    133 }
    134 
    135 /*
    136  * For the given db, with an already-built AST, fill the vers_map hash table
    137  * with every encountered type and attribute.  This could eventually be expanded
    138  * to include other language constructs, such as users and roles, in which case
    139  * multiple hash tables would be needed.  These tables can then be used by
    140  * attributize() to change all references to these types.
    141  */
    142 int cil_extract_attributees(struct cil_db *db, hashtab_t vers_map)
    143 {
    144 	/* walk ast. */
    145 	int rc = SEPOL_ERR;
    146 	struct version_args extra_args;
    147 	extra_args.db = db;
    148 	extra_args.vers_map = vers_map;
    149 	extra_args.num = NULL;
    150 	rc = cil_tree_walk(db->ast->root, __extract_attributees_helper, NULL, NULL, &extra_args);
    151 	if (rc != SEPOL_OK) {
    152 		goto exit;
    153 	}
    154 
    155 	return SEPOL_OK;
    156 exit:
    157 	return rc;
    158 }
    159 
    160 static enum plat_flavor __cil_get_plat_flavor(hashtab_t vers_map, hashtab_key_t key)
    161 {
    162 	enum plat_flavor rc;
    163 	struct version_datum *vers_datum;
    164 
    165 	vers_datum = (struct version_datum *)hashtab_search(vers_map, key);
    166 	if (vers_datum == NULL) {
    167 		return PLAT_NONE;
    168 	}
    169 	switch (vers_datum->ast_node->flavor) {
    170 	case CIL_TYPE:
    171 		rc = PLAT_TYPE;
    172 		break;
    173 	case CIL_TYPEATTRIBUTE:
    174 		rc = PLAT_ATTRIB;
    175 		break;
    176 	default:
    177 		rc = PLAT_NONE;
    178 		break;
    179 	}
    180 	return rc;
    181 }
    182 
    183 /*
    184  * Takes the old name and version string and creates a new strpool entry by
    185  * combining them.
    186  */
    187 static char *__cil_attrib_get_versname(char *old, const char *vers)
    188 {
    189 	size_t len = 0;
    190 	char *tmp_new = NULL;
    191 	char *final;
    192 
    193 	len += strlen(old) + strlen(vers) + 2;
    194 	tmp_new = cil_malloc(len);
    195 	snprintf(tmp_new, len, "%s_%s", old, vers);
    196 	final = cil_strpool_add(tmp_new);
    197 	free(tmp_new);
    198 	return final;
    199 }
    200 
    201 /*
    202  * Change type to attribute - create new versioned name based on old, create
    203  * typeattribute node add to the existing type node.
    204  */
    205 static int __cil_attrib_convert_type(struct cil_tree_node *node, struct version_args *args)
    206 {
    207 	int rc = SEPOL_ERR;
    208 	struct cil_type *type = (struct cil_type *)node->data;
    209 	struct cil_typeattribute *typeattr = NULL;
    210 	struct cil_tree_node *new_ast_node = NULL;
    211 	char *new_key;
    212 
    213 	cil_typeattribute_init(&typeattr);
    214 
    215 	new_key = __cil_attrib_get_versname(type->datum.name, args->num);
    216 
    217 	/* create new tree node to contain typeattribute and add to tree */
    218 	cil_tree_node_init(&new_ast_node);
    219 	new_ast_node->parent = node->parent;
    220 	new_ast_node->next = node->next;
    221 	node->next = new_ast_node;
    222 
    223 	rc = cil_gen_node(args->db, new_ast_node, (struct cil_symtab_datum *) typeattr,
    224 			  new_key, CIL_SYM_TYPES, CIL_TYPEATTRIBUTE);
    225 	if (rc != SEPOL_OK) {
    226 		goto exit;
    227 	}
    228 
    229 	return SEPOL_OK;
    230 exit:
    231 	return rc;
    232 }
    233 
    234 /*
    235  * Update datum - create new key, remove entry under old key,
    236  * update entry, and insert under new key
    237  */
    238 static int __cil_attrib_swap_symtab_key(struct cil_tree_node *node, char *old_key,
    239 					const char *num)
    240 {
    241 	int rc = SEPOL_ERR;
    242 	char *new_key;
    243 	symtab_t *symtab;
    244 	struct cil_symtab_datum *datum = (struct cil_symtab_datum *) node->data;
    245 
    246 	new_key = __cil_attrib_get_versname(old_key, num);
    247 
    248 	symtab = datum->symtab;
    249 
    250 	/* TODO: remove, but what happens to other nodes on this datum ?*/
    251 	cil_list_remove(datum->nodes, CIL_NODE, node, 0);
    252 	cil_symtab_remove_datum(datum);
    253 
    254 	rc = cil_symtab_insert(symtab, new_key, datum, node);
    255 
    256 	if (rc != SEPOL_OK) {
    257 		goto exit;
    258 	}
    259 
    260 	return SEPOL_OK;
    261 exit:
    262 	return rc;
    263 }
    264 
    265 /*
    266  * expressions may contains strings which are not in the type-attribute
    267  * namespace, so this is not a general cil_expr attributizer.
    268  * TODO: add support for other types of expressions which may contain types.
    269  */
    270 static int cil_attrib_type_expr(struct cil_list *expr_str, struct version_args *args)
    271 {
    272 	int rc = SEPOL_ERR;
    273 	struct cil_list_item *curr = NULL;
    274 	char *new;
    275 	hashtab_key_t key;
    276 
    277 	/* iterate through cil_list, replacing types */
    278 	cil_list_for_each(curr, expr_str) {
    279 		switch(curr->flavor) {
    280 		case CIL_LIST:
    281 			rc = cil_attrib_type_expr((struct cil_list *)curr->data, args);
    282 			if (rc != SEPOL_OK)
    283 				goto exit;
    284 			break;
    285 		case CIL_STRING:
    286 			key = (hashtab_key_t) curr->data;
    287 			enum plat_flavor pf = __cil_get_plat_flavor(args->vers_map, key);
    288 			if (!strncmp(curr->data, "base_typeattr_", 14) || pf == PLAT_TYPE) {
    289 				new = __cil_attrib_get_versname((char *) curr->data, args->num);
    290 				curr->data = (void *) new;
    291 			}
    292 			break;
    293 		case CIL_DATUM:
    294 			cil_log(CIL_ERR, "AST already resolved. Not yet supported.\n");
    295 			rc = SEPOL_ERR;
    296 			goto exit;
    297 			break;
    298 		default:
    299 			break;
    300 		}
    301 	}
    302 
    303 	return SEPOL_OK;
    304 exit:
    305 	return rc;
    306 }
    307 
    308 static int cil_attrib_check_context(struct cil_context *ctxt, struct version_args *args)
    309 {
    310 	int rc = SEPOL_ERR;
    311 	hashtab_key_t key;
    312 
    313 	if (ctxt->type != NULL) {
    314 		cil_log(CIL_ERR, "AST already resolved. Not yet supported.\n");
    315 		goto exit;
    316 	}
    317 
    318 	key = (hashtab_key_t) ctxt->type_str;
    319 	if (__cil_get_plat_flavor(args->vers_map, key) != PLAT_NONE) {
    320         /* TODO: reinstate check, but leave out for now
    321 		cil_log(CIL_ERR, "AST contains context with platform public type: %s\n",
    322 			ctxt->type_str);
    323 		rc = SEPOL_ERR;
    324 		goto exit; */
    325 	}
    326 
    327 	return SEPOL_OK;
    328 exit:
    329 	return rc;
    330 }
    331 
    332 static int cil_attrib_sidcontext(struct cil_tree_node *node, struct version_args *args)
    333 {
    334 	int rc = SEPOL_ERR;
    335 	struct cil_sidcontext *sidcon = (struct cil_sidcontext *)node->data;
    336 
    337 	if (sidcon->context_str == NULL) {
    338 		/* sidcon contains an anon context, which needs to have type checked */
    339 		rc = cil_attrib_check_context(sidcon->context, args);
    340 		if (rc != SEPOL_OK) {
    341 			goto exit;
    342 		}
    343 	}
    344 
    345 	return SEPOL_OK;
    346 exit:
    347 	return rc;
    348 }
    349 
    350 static int cil_attrib_context(struct cil_tree_node *node, struct version_args *args)
    351 {
    352 	struct cil_context *ctxt = (struct cil_context *)node->data;
    353 
    354 	return cil_attrib_check_context(ctxt, args);
    355 }
    356 
    357 static int cil_attrib_roletype(struct cil_tree_node *node,
    358 			       __attribute__((unused)) struct version_args *args)
    359 {
    360 	int rc = SEPOL_ERR;
    361 	char *key;
    362 	struct cil_roletype *roletype = (struct cil_roletype *)node->data;
    363 
    364 	if (roletype->role) {
    365 		cil_log(CIL_ERR, "AST already resolved.  !!! Not yet supported.\n");
    366 		goto exit;
    367 	}
    368 	key = roletype->type_str;
    369 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    370 		roletype->type_str = __cil_attrib_get_versname(key, args->num);
    371 	}
    372 
    373 	return SEPOL_OK;
    374 exit:
    375 	return rc;
    376 }
    377 
    378 static int cil_attrib_type(struct cil_tree_node *node, struct version_args *args)
    379 {
    380 	int rc = SEPOL_ERR;
    381 	struct cil_type *type = (struct cil_type *)node->data;
    382 	char *key = type->datum.name;
    383 
    384 	if (type->value) {
    385 		cil_log(CIL_ERR, "AST already resolved.  !!! Not yet supported.\n");
    386 		goto exit;
    387 	}
    388 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    389 		rc = __cil_attrib_convert_type(node, args);
    390 		if (rc != SEPOL_OK) {
    391 			goto exit;
    392 		}
    393 	}
    394 
    395 	return SEPOL_OK;
    396 exit:
    397 	return rc;
    398 }
    399 
    400 static int cil_attrib_typepermissive(struct cil_tree_node *node,
    401 				     struct version_args *args __attribute__ ((unused)))
    402 {
    403 	struct cil_typepermissive *typeperm = (struct cil_typepermissive *)node->data;
    404 
    405 	if (typeperm->type != NULL) {
    406 		cil_log(CIL_ERR, "AST already resolved.  ### Not yet supported.\n");
    407 		return SEPOL_ERR;
    408 	}
    409 
    410 	return SEPOL_OK;
    411 }
    412 
    413 static int cil_attrib_typeattribute(struct cil_tree_node *node, struct version_args *args)
    414 {
    415 	int rc = SEPOL_ERR;
    416 	struct cil_typeattribute *typeattr = (struct cil_typeattribute *)node->data;
    417 	char *key = typeattr->datum.name;
    418 
    419 	if (typeattr->types) {
    420 		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
    421 			node->line);
    422 		goto exit;
    423 	}
    424 	if (!strncmp(key, "base_typeattr_", 14)) {
    425 		rc = __cil_attrib_swap_symtab_key(node, key, args->num);
    426 		if (rc != SEPOL_OK) {
    427 			goto exit;
    428 		}
    429 	}
    430 
    431 	return SEPOL_OK;
    432 exit:
    433 	return rc;
    434 }
    435 
    436 static int cil_attrib_typeattributeset(struct cil_tree_node *node, struct version_args *args)
    437 {
    438 	int rc = SEPOL_ERR;
    439 	char *key;
    440 	struct cil_typeattributeset *typeattrset = (struct cil_typeattributeset *) node->data;
    441 
    442 	if (typeattrset->datum_expr != NULL) {
    443 		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
    444 			node->line);
    445 		goto exit;
    446 	}
    447 
    448 	key = typeattrset->attr_str;
    449 	/* first check to see if the attribute to which this set belongs is versioned */
    450 	if (!strncmp(key, "base_typeattr_", 14)) {
    451 		typeattrset->attr_str = __cil_attrib_get_versname(key, args->num);
    452 	}
    453 
    454 	rc = cil_attrib_type_expr(typeattrset->str_expr, args);
    455 	if (rc != SEPOL_OK) {
    456 		goto exit;
    457 	}
    458 
    459 	return SEPOL_OK;
    460 exit:
    461 	return rc;
    462 }
    463 
    464 static int cil_attrib_typealiasactual(struct cil_tree_node *node, struct version_args *args)
    465 {
    466 	int rc = SEPOL_ERR;
    467 	char *key;
    468 	struct cil_aliasactual *aliasact = (struct cil_aliasactual *)node->data;
    469 
    470 	key = aliasact->actual_str;
    471 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) != PLAT_NONE) {
    472 		cil_log(CIL_ERR, "%s with platform public type not allowed (line %d)\n",
    473 		    CIL_KEY_TYPEALIASACTUAL, node->line);
    474 		goto exit;
    475 	}
    476 
    477 	return SEPOL_OK;
    478 exit:
    479 	return rc;
    480 }
    481 
    482 static int cil_attrib_nametypetransition(struct cil_tree_node *node, struct version_args *args)
    483 {
    484 	int rc = SEPOL_ERR;
    485 	char *key;
    486 	struct cil_nametypetransition *namettrans = (struct cil_nametypetransition *)node->data;
    487 
    488 	if (namettrans->src != NULL) {
    489 		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
    490 			node->line);
    491 		goto exit;
    492 	}
    493 	key = namettrans->src_str;
    494 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    495 		namettrans->src_str = __cil_attrib_get_versname(key, args->num);
    496 	}
    497 
    498 	key = namettrans->tgt_str;
    499 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    500 		namettrans->tgt_str = __cil_attrib_get_versname(key, args->num);
    501 	}
    502 
    503 	return SEPOL_OK;
    504 exit:
    505 	return rc;
    506 }
    507 
    508 /*
    509  * This is exactly the same as cil_attrib_nametypetransition, but the struct
    510  * layouts differ, so we can't reuse it.
    511  */
    512 static int cil_attrib_type_rule(struct cil_tree_node *node, struct version_args *args)
    513 {
    514 	int rc = SEPOL_ERR;
    515 	char *key;
    516 	struct cil_type_rule *type_rule = (struct cil_type_rule *)node->data;
    517 
    518 	if (type_rule->src != NULL) {
    519 		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
    520 			node->line);
    521 		goto exit;
    522 	}
    523 	key = type_rule->src_str;
    524 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    525 		type_rule->src_str = __cil_attrib_get_versname(key, args->num);
    526 	}
    527 
    528 	key = type_rule->tgt_str;
    529 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    530 		type_rule->tgt_str = __cil_attrib_get_versname(key, args->num);
    531 	}
    532 
    533 	return SEPOL_OK;
    534 exit:
    535 	return rc;
    536 }
    537 
    538 static int cil_attrib_avrule(struct cil_tree_node *node, struct version_args *args)
    539 {
    540 	int rc = SEPOL_ERR;
    541 	char *key;
    542 	struct cil_avrule *avrule = (struct cil_avrule *)node->data;
    543 
    544 	if (avrule->src != NULL) {
    545 		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
    546 			node->line);
    547 		goto exit;
    548 	}
    549 
    550 	key = avrule->src_str;
    551 	if (!strncmp(key, "base_typeattr_", 14) ||
    552 	    __cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    553 		avrule->src_str = __cil_attrib_get_versname(key, args->num);
    554 	}
    555 
    556 	key = avrule->tgt_str;
    557 	if (!strncmp(key, "base_typeattr_", 14) ||
    558 	    __cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    559 		avrule->tgt_str = __cil_attrib_get_versname(key, args->num);
    560 	}
    561 
    562 	return SEPOL_OK;
    563 exit:
    564 	return rc;
    565 }
    566 
    567 static int cil_attrib_genfscon(struct cil_tree_node *node, struct version_args *args)
    568 {
    569 	int rc = SEPOL_ERR;
    570 
    571 	struct cil_genfscon *genfscon = (struct cil_genfscon *)node->data;
    572 
    573 	if (genfscon->context_str == NULL) {
    574 		/* genfscon contains an anon context, which needs to have type checked */
    575 		rc = cil_attrib_check_context(genfscon->context, args);
    576 		if (rc != SEPOL_OK) {
    577 			goto exit;
    578 		}
    579 	}
    580 
    581 	return SEPOL_OK;
    582 exit:
    583 	return rc;
    584 }
    585 
    586 static int cil_attrib_fsuse(struct cil_tree_node *node, struct version_args *args)
    587 {
    588 	int rc = SEPOL_ERR;
    589 	struct cil_fsuse *fsuse = (struct cil_fsuse *)node->data;
    590 
    591 	if (fsuse->context_str == NULL) {
    592 		/* fsuse contains an anon context, which needs to have type checked */
    593 		rc = cil_attrib_check_context(fsuse->context, args);
    594 		if (rc != SEPOL_OK) {
    595 			goto exit;
    596 		}
    597 	}
    598 
    599 	return SEPOL_OK;
    600 exit:
    601 	return rc;
    602 }
    603 
    604 static int __attributize_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
    605 {
    606 	int rc = SEPOL_ERR;
    607 	struct version_args *args = (struct version_args *) extra_args;
    608 
    609 	if (node == NULL || finished == NULL || extra_args == NULL) {
    610 		goto exit;
    611 	}
    612 
    613 	switch (node->flavor) {
    614 	case CIL_SIDCONTEXT:
    615 		/* contains type, but shouldn't involve an attributized type, maybe add
    616 		   a check on type and error if it conflicts */
    617 		rc = cil_attrib_sidcontext(node, args);
    618 		if (rc != SEPOL_OK) {
    619 			goto exit;
    620 		}
    621 		break;
    622 	case CIL_ROLE:
    623 		cil_log(CIL_ERR, "%s declaration illegal non-platform policy (line %d)\n",
    624 			CIL_KEY_ROLE, node->line);
    625 		rc = SEPOL_ERR;
    626 		break;
    627 	case CIL_ROLETYPE:
    628 		/* Yes, this is needed if we support roletype in non-platform policy.
    629 		   type_id can be type, typealias or typeattr */
    630 		rc = cil_attrib_roletype(node, args);
    631 		if (rc != SEPOL_OK) {
    632 			goto exit;
    633 		}
    634 		break;
    635 	case CIL_ROLEATTRIBUTE:
    636 		/* don't think this is needed, only used for cil_gen_req, and we aren't
    637 		   yet supporting roles in non-platform policy. */
    638 		break;
    639 	case CIL_TYPE:
    640 		/* conver to attribute if in policy */
    641 		rc = cil_attrib_type(node, args);
    642 		if (rc != SEPOL_OK) {
    643 			goto exit;
    644 		}
    645 		break;
    646 	case CIL_TYPEPERMISSIVE:
    647 		rc = cil_attrib_typepermissive(node, args);
    648 		if (rc != SEPOL_OK) {
    649 			goto exit;
    650 		}
    651 		break;
    652 	case CIL_TYPEATTRIBUTE:
    653 		rc = cil_attrib_typeattribute(node, args);
    654 		if (rc != SEPOL_OK) {
    655 			goto exit;
    656 		}
    657 		break;
    658 	case CIL_TYPEATTRIBUTESET:
    659 		rc = cil_attrib_typeattributeset(node, args);
    660 		if (rc != SEPOL_OK) {
    661 			goto exit;
    662 		}
    663 		break;
    664 	case CIL_TYPEALIASACTUAL:
    665 		/* this will break on an attributized type - identify it and throw error */
    666 		rc = cil_attrib_typealiasactual(node, args);
    667 		if (rc != SEPOL_OK) {
    668 			goto exit;
    669 		}
    670 		break;
    671 	case CIL_NAMETYPETRANSITION:
    672 		/* not allowed in plat-policy. Types present, throw error if attributee */
    673 		rc = cil_attrib_nametypetransition(node, args);
    674 		if (rc != SEPOL_OK) {
    675 			goto exit;
    676 		}
    677 		break;
    678 	case CIL_TYPE_RULE:
    679 		/* not allowed in plat-policy. Types present, throw error if attributee */
    680 		rc = cil_attrib_type_rule(node, args);
    681 		if (rc != SEPOL_OK) {
    682 			goto exit;
    683 		}
    684 		break;
    685 	case CIL_AVRULE:
    686 	case CIL_AVRULEX:
    687 		rc = cil_attrib_avrule(node, args);
    688 		if (rc != SEPOL_OK) {
    689 			goto exit;
    690 		}
    691 		break;
    692 	case CIL_CONTEXT:
    693 		/* not currently found in AOSP policy, but if found would need to be
    694 		   checked to not be attributee */
    695 		rc = cil_attrib_context(node, args);
    696 		if (rc != SEPOL_OK) {
    697 			goto exit;
    698 		}
    699 		break;
    700 	case CIL_GENFSCON:
    701 		/* not allowed in plat-policy, but types present, throw error if attributee */
    702 		rc = cil_attrib_genfscon(node, args);
    703 		if (rc != SEPOL_OK) {
    704 			goto exit;
    705 		}
    706 		break;
    707 	case CIL_FILECON:
    708 	case CIL_NODECON:
    709 	case CIL_PORTCON:
    710 	case CIL_PIRQCON:
    711 	case CIL_IOMEMCON:
    712 	case CIL_IOPORTCON:
    713 	case CIL_PCIDEVICECON:
    714 	case CIL_DEVICETREECON:
    715 	case CIL_VALIDATETRANS:
    716 	case CIL_MLSVALIDATETRANS:
    717 	case CIL_CALL:
    718 	case CIL_MACRO:
    719 	case CIL_OPTIONAL:
    720 		/* Not currently found in AOSP and not yet properly handled.  Return err until support added. */
    721 		cil_log(CIL_ERR, "unsupported policy statement (line %d)\n", node->line);
    722 		rc = SEPOL_ERR;
    723 		goto exit;
    724 	case CIL_FSUSE:
    725 		/* not allowed in plat-policy, but types present, throw error if attributee */
    726 		cil_attrib_fsuse(node, args);
    727 		if (rc != SEPOL_OK) {
    728 			goto exit;
    729 		}
    730 		break;
    731 	case CIL_CONSTRAIN:
    732 	case CIL_MLSCONSTRAIN:
    733 		/* there is type info here, but not sure if we'll allow non-platform code
    734 		   to have this, or whether or not it's in platform policy.  Currently
    735 		   assuming that mlsconstrain is private-platform only, and that normal
    736 		   constrain is verboten. */
    737 		cil_log(CIL_ERR, "unsupported policy statement (line %d)\n", node->line);
    738 		rc = SEPOL_ERR;
    739 		goto exit;
    740 	default:
    741 		break;
    742 	}
    743 
    744 	return SEPOL_OK;
    745 exit:
    746 	return rc;
    747 }
    748 
    749 /*
    750  * walk ast, replacing previously identified types and attributes with the
    751  * attributized version. Also replace previous references to the attributees
    752  * with the versioned type.
    753  */
    754 static int cil_attributize(struct cil_db *db, hashtab_t vers_map, const char *num)
    755 {
    756 	int rc = SEPOL_ERR;
    757 	struct version_args extra_args;
    758 	extra_args.db = db;
    759 	extra_args.vers_map = vers_map;
    760 	extra_args.num = num;
    761 
    762 	rc = cil_tree_walk(db->ast->root, __attributize_helper, NULL, NULL, &extra_args);
    763 	if (rc != SEPOL_OK) {
    764 		goto exit;
    765 	}
    766 
    767 	return SEPOL_OK;
    768 exit:
    769 	return rc;
    770 }
    771 
    772 /*
    773  * Create typeattributeset mappings from the attributes generated from the
    774  * original types/attributes to the original values.  This mapping will provide
    775  * the basis for the platform policy's mapping to this public version.
    776  *
    777  * Add these new typeattributeset nodes to the given cil_db.
    778  */
    779 static int cil_build_mappings_tree(hashtab_key_t k, hashtab_datum_t d, void *args)
    780 {
    781 	struct cil_typeattributeset *attrset = NULL;
    782 	struct cil_typeattribute *typeattr = NULL;
    783 	struct cil_expandtypeattribute *expandattr = NULL;
    784 	struct cil_tree_node *ast_node = NULL;
    785 	struct version_args *verargs = (struct version_args *)args;
    786 	struct cil_tree_node *ast_parent = verargs->db->ast->root;
    787 	char *orig_type = (char *) k;
    788 	struct version_datum *vers_datum = (struct version_datum *) d;
    789 	char *new_key = __cil_attrib_get_versname(orig_type, verargs->num);
    790 
    791 	if (vers_datum->ast_node->flavor == CIL_TYPEATTRIBUTE) {
    792 		// platform attributes are not versioned
    793 		return SEPOL_OK;
    794 	}
    795 	/* create typeattributeset datum */
    796 	cil_typeattributeset_init(&attrset);
    797 	cil_list_init(&attrset->str_expr, CIL_TYPE);
    798 	attrset->attr_str = new_key;
    799 	cil_list_append(attrset->str_expr, CIL_STRING, orig_type);
    800 
    801 	/* create containing tree node */
    802 	cil_tree_node_init(&ast_node);
    803 	ast_node->data = attrset;
    804 	ast_node->flavor = CIL_TYPEATTRIBUTESET;
    805 
    806 	/* add to tree */
    807 	ast_node->parent = ast_parent;
    808 	if (ast_parent->cl_head == NULL)
    809 		ast_parent->cl_head = ast_node;
    810 	else
    811 		ast_parent->cl_tail->next = ast_node;
    812 	ast_parent->cl_tail = ast_node;
    813 
    814 	/* create expandtypeattribute datum */
    815 	cil_expandtypeattribute_init(&expandattr);
    816 	cil_list_init(&expandattr->attr_strs, CIL_TYPE);
    817 	cil_list_append(expandattr->attr_strs, CIL_STRING, new_key);
    818 	expandattr->expand = CIL_TRUE;
    819 
    820 	/* create containing tree node */
    821 	cil_tree_node_init(&ast_node);
    822 	ast_node->data = expandattr;
    823 	ast_node->flavor = CIL_EXPANDTYPEATTRIBUTE;
    824 	/* add to tree */
    825 	ast_node->parent = ast_parent;
    826 	ast_parent->cl_tail->next = ast_node;
    827 	ast_parent->cl_tail = ast_node;
    828 
    829 	/* re)declare typeattribute. */
    830 	cil_typeattribute_init(&typeattr);
    831 	typeattr->datum.name = new_key;
    832 	cil_tree_node_init(&ast_node);
    833 	ast_node->data = typeattr;
    834 	ast_node->flavor = CIL_TYPEATTRIBUTE;
    835 	ast_node->parent = ast_parent;
    836 	ast_parent->cl_tail->next = ast_node;
    837 	ast_parent->cl_tail = ast_node;
    838 
    839 	return SEPOL_OK;
    840 }
    841 
    842 /*
    843  * Initializes the given db and uses the version mapping generated by
    844  * cil_extract_attributees() to fill it with the glue policy required to
    845  * connect the attributized policy created by cil_attributize() to the policy
    846  * declaring the concrete types.
    847  */
    848 static int cil_attrib_mapping(struct cil_db **db, hashtab_t vers_map, const char *num)
    849 {
    850 	int rc = SEPOL_ERR;
    851 	struct version_args extra_args;
    852 
    853 	cil_db_init(db);
    854 
    855 	/* foreach entry in vers_map, create typeattributeset node and attach to tree */
    856 	extra_args.db = *db;
    857 	extra_args.vers_map = NULL;
    858 	extra_args.num = num;
    859 	rc = hashtab_map(vers_map, cil_build_mappings_tree, &extra_args);
    860 	if (rc != SEPOL_OK) {
    861 		goto exit;
    862 	}
    863 
    864 	return SEPOL_OK;
    865 exit:
    866 	return rc;
    867 }
    868 
    869 int cil_android_attrib_mapping(struct cil_db **mdb, struct cil_db *srcdb, const char *num)
    870 {
    871 	int rc = SEPOL_ERR;
    872 	hashtab_t ver_map_tab = NULL;
    873 
    874 	ver_map_tab = hashtab_create(ver_map_hash_val, ver_map_key_cmp, VER_MAP_SZ);
    875 	if (!ver_map_tab) {
    876 		cil_log(CIL_ERR, "Unable to create version mapping table.\n");
    877 		goto exit;
    878 	}
    879 	rc = cil_build_ast(srcdb, srcdb->parse->root, srcdb->ast->root);
    880 	if (rc != SEPOL_OK) {
    881 		cil_log(CIL_ERR, "Unable to build source db AST.\n");
    882 		goto exit;
    883 	}
    884 	rc = cil_extract_attributees(srcdb, ver_map_tab);
    885 	if (rc != SEPOL_OK) {
    886 		cil_log(CIL_ERR, "Unable to extract attributizable elements from source db.\n");
    887 		goto exit;
    888 	}
    889 	rc = cil_attrib_mapping(mdb, ver_map_tab, num);
    890 	if (rc != SEPOL_OK) {
    891 		cil_log(CIL_ERR, "Unable to create mapping db from source db.\n");
    892 		goto exit;
    893 	}
    894 exit:
    895 	ver_map_destroy(ver_map_tab);
    896 	return rc;
    897 }
    898 
    899 int cil_android_attributize(struct cil_db *tgtdb, struct cil_db *srcdb, const char *num)
    900 {
    901 	int rc = SEPOL_ERR;
    902 	hashtab_t ver_map_tab = NULL;
    903 
    904 	ver_map_tab = hashtab_create(ver_map_hash_val, ver_map_key_cmp, VER_MAP_SZ);
    905 	if (!ver_map_tab) {
    906 		cil_log(CIL_ERR, "Unable to create version mapping table.\n");
    907 		goto exit;
    908 	}
    909 	rc = cil_build_ast(srcdb, srcdb->parse->root, srcdb->ast->root);
    910 	if (rc != SEPOL_OK) {
    911 		cil_log(CIL_ERR, "Unable to build source db AST.\n");
    912 		goto exit;
    913 	}
    914 	rc = cil_extract_attributees(srcdb, ver_map_tab);
    915 	if (rc != SEPOL_OK) {
    916 		cil_log(CIL_ERR, "Unable to extract attributizable elements from source db.\n");
    917 		goto exit;
    918 	}
    919 	rc = cil_build_ast(tgtdb, tgtdb->parse->root, tgtdb->ast->root);
    920 	if (rc != SEPOL_OK) {
    921 		cil_log(CIL_ERR, "Unable to build target db AST.\n");
    922 		goto exit;
    923 	}
    924 	rc = cil_attributize(tgtdb, ver_map_tab, num);
    925 	if (rc != SEPOL_OK) {
    926 		cil_log(CIL_ERR, "Unable to attributize target db.\n");
    927 		goto exit;
    928 	}
    929 exit:
    930 	ver_map_destroy(ver_map_tab);
    931 	return rc;
    932 }
    933