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 		} else {
    104 			rc = hashtab_insert(args->vers_map, (hashtab_key_t) key, (hashtab_datum_t) datum);
    105 			if (rc != SEPOL_OK) {
    106 				goto exit;
    107 			}
    108 		}
    109 		break;
    110 	case CIL_TYPEALIAS:
    111 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
    112 			CIL_KEY_TYPEALIAS, node->line);
    113 		goto exit;
    114 		break;
    115 	case CIL_TYPEPERMISSIVE:
    116 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
    117 			CIL_KEY_TYPEPERMISSIVE, node->line);
    118 		goto exit;
    119 		break;
    120 	case CIL_NAMETYPETRANSITION:
    121 	case CIL_TYPE_RULE:
    122 		cil_log(CIL_ERR, "%s unsupported statement in attributee policy (line %d)\n",
    123 			CIL_KEY_TYPETRANSITION, node->line);
    124 		goto exit;
    125 		break;
    126 	default:
    127 		break;
    128 	}
    129 	return SEPOL_OK;
    130 exit:
    131 	return rc;
    132 }
    133 
    134 /*
    135  * For the given db, with an already-built AST, fill the vers_map hash table
    136  * with every encountered type and attribute.  This could eventually be expanded
    137  * to include other language constructs, such as users and roles, in which case
    138  * multiple hash tables would be needed.  These tables can then be used by
    139  * attributize() to change all references to these types.
    140  */
    141 int cil_extract_attributees(struct cil_db *db, hashtab_t vers_map)
    142 {
    143 	/* walk ast. */
    144 	int rc = SEPOL_ERR;
    145 	struct version_args extra_args;
    146 	extra_args.db = db;
    147 	extra_args.vers_map = vers_map;
    148 	extra_args.num = NULL;
    149 	rc = cil_tree_walk(db->ast->root, __extract_attributees_helper, NULL, NULL, &extra_args);
    150 	if (rc != SEPOL_OK) {
    151 		goto exit;
    152 	}
    153 
    154 	return SEPOL_OK;
    155 exit:
    156 	return rc;
    157 }
    158 
    159 static enum plat_flavor __cil_get_plat_flavor(hashtab_t vers_map, hashtab_key_t key)
    160 {
    161 	enum plat_flavor rc;
    162 	struct version_datum *vers_datum;
    163 
    164 	vers_datum = (struct version_datum *)hashtab_search(vers_map, key);
    165 	if (vers_datum == NULL) {
    166 		return PLAT_NONE;
    167 	}
    168 	switch (vers_datum->ast_node->flavor) {
    169 	case CIL_TYPE:
    170 		rc = PLAT_TYPE;
    171 		break;
    172 	case CIL_TYPEATTRIBUTE:
    173 		rc = PLAT_ATTRIB;
    174 		break;
    175 	default:
    176 		rc = PLAT_NONE;
    177 		break;
    178 	}
    179 	return rc;
    180 }
    181 
    182 /*
    183  * Takes the old name and version string and creates a new strpool entry by
    184  * combining them.
    185  */
    186 static char *__cil_attrib_get_versname(char *old, const char *vers)
    187 {
    188 	size_t len = 0;
    189 	char *tmp_new = NULL;
    190 	char *final;
    191 
    192 	len += strlen(old) + strlen(vers) + 2;
    193 	tmp_new = cil_malloc(len);
    194 	snprintf(tmp_new, len, "%s_%s", old, vers);
    195 	final = cil_strpool_add(tmp_new);
    196 	free(tmp_new);
    197 	return final;
    198 }
    199 
    200 /*
    201  * Change type to attribute - create new versioned name based on old, create
    202  * typeattribute node and replace existing type node.
    203  */
    204 static int __cil_attrib_convert_type(struct cil_tree_node *node, struct version_args *args)
    205 {
    206 	int rc = SEPOL_ERR;
    207 	struct cil_type *type = (struct cil_type *)node->data;
    208 	struct cil_typeattribute *typeattr = NULL;
    209 	char *new_key;
    210 
    211 	cil_typeattribute_init(&typeattr);
    212 
    213 	new_key = __cil_attrib_get_versname(type->datum.name, args->num);
    214 
    215 	cil_symtab_datum_remove_node(&type->datum, node);
    216 	cil_destroy_type(type);
    217 
    218 	rc = cil_gen_node(args->db, node, (struct cil_symtab_datum *) typeattr,
    219 			  new_key, CIL_SYM_TYPES, CIL_TYPEATTRIBUTE);
    220 	if (rc != SEPOL_OK) {
    221 		goto exit;
    222 	}
    223 
    224 	return SEPOL_OK;
    225 exit:
    226 	return rc;
    227 }
    228 
    229 /*
    230  * Update datum - create new key, remove entry under old key,
    231  * update entry, and insert under new key
    232  */
    233 static int __cil_attrib_swap_symtab_key(struct cil_tree_node *node, char *old_key,
    234 					const char *num)
    235 {
    236 	int rc = SEPOL_ERR;
    237 	char *new_key;
    238 	symtab_t *symtab;
    239 	struct cil_symtab_datum *datum = (struct cil_symtab_datum *) node->data;
    240 
    241 	new_key = __cil_attrib_get_versname(old_key, num);
    242 
    243 	symtab = datum->symtab;
    244 
    245 	/* TODO: remove, but what happens to other nodes on this datum ?*/
    246 	cil_list_remove(datum->nodes, CIL_NODE, node, 0);
    247 	cil_symtab_remove_datum(datum);
    248 
    249 	rc = cil_symtab_insert(symtab, new_key, datum, node);
    250 
    251 	if (rc != SEPOL_OK) {
    252 		goto exit;
    253 	}
    254 
    255 	return SEPOL_OK;
    256 exit:
    257 	return rc;
    258 }
    259 
    260 /*
    261  * expressions may contains strings which are not in the type-attribute
    262  * namespace, so this is not a general cil_expr attributizer.
    263  * TODO: add support for other types of expressions which may contain types.
    264  */
    265 static int cil_attrib_type_expr(struct cil_list *expr_str, struct version_args *args)
    266 {
    267 	int rc = SEPOL_ERR;
    268 	struct cil_list_item *curr = NULL;
    269 	char *new;
    270 	hashtab_key_t key;
    271 
    272 	/* iterate through cil_list, replacing types */
    273 	cil_list_for_each(curr, expr_str) {
    274 		switch(curr->flavor) {
    275 		case CIL_LIST:
    276 			rc = cil_attrib_type_expr((struct cil_list *)curr->data, args);
    277 			if (rc != SEPOL_OK)
    278 				goto exit;
    279 			break;
    280 		case CIL_STRING:
    281 			key = (hashtab_key_t) curr->data;
    282 			enum plat_flavor pf = __cil_get_plat_flavor(args->vers_map, key);
    283 			if (!strncmp(curr->data, "base_typeattr_", 14) || pf == PLAT_TYPE) {
    284 				new = __cil_attrib_get_versname((char *) curr->data, args->num);
    285 				curr->data = (void *) new;
    286 			}
    287 			break;
    288 		case CIL_DATUM:
    289 			cil_log(CIL_ERR, "AST already resolved. Not yet supported.\n");
    290 			rc = SEPOL_ERR;
    291 			goto exit;
    292 			break;
    293 		default:
    294 			break;
    295 		}
    296 	}
    297 
    298 	return SEPOL_OK;
    299 exit:
    300 	return rc;
    301 }
    302 
    303 static int cil_attrib_check_context(struct cil_context *ctxt, struct version_args *args)
    304 {
    305 	int rc = SEPOL_ERR;
    306 	hashtab_key_t key;
    307 
    308 	if (ctxt->type != NULL) {
    309 		cil_log(CIL_ERR, "AST already resolved. Not yet supported.\n");
    310 		goto exit;
    311 	}
    312 
    313 	key = (hashtab_key_t) ctxt->type_str;
    314 	if (__cil_get_plat_flavor(args->vers_map, key) != PLAT_NONE) {
    315         /* TODO: reinstate check, but leave out for now
    316 		cil_log(CIL_ERR, "AST contains context with platform public type: %s\n",
    317 			ctxt->type_str);
    318 		rc = SEPOL_ERR;
    319 		goto exit; */
    320 	}
    321 
    322 	return SEPOL_OK;
    323 exit:
    324 	return rc;
    325 }
    326 
    327 static int cil_attrib_sidcontext(struct cil_tree_node *node, struct version_args *args)
    328 {
    329 	int rc = SEPOL_ERR;
    330 	struct cil_sidcontext *sidcon = (struct cil_sidcontext *)node->data;
    331 
    332 	if (sidcon->context_str == NULL) {
    333 		/* sidcon contains an anon context, which needs to have type checked */
    334 		rc = cil_attrib_check_context(sidcon->context, args);
    335 		if (rc != SEPOL_OK) {
    336 			goto exit;
    337 		}
    338 	}
    339 
    340 	return SEPOL_OK;
    341 exit:
    342 	return rc;
    343 }
    344 
    345 static int cil_attrib_context(struct cil_tree_node *node, struct version_args *args)
    346 {
    347 	struct cil_context *ctxt = (struct cil_context *)node->data;
    348 
    349 	return cil_attrib_check_context(ctxt, args);
    350 }
    351 
    352 static int cil_attrib_roletype(struct cil_tree_node *node,
    353 			       __attribute__((unused)) struct version_args *args)
    354 {
    355 	int rc = SEPOL_ERR;
    356 	char *key;
    357 	struct cil_roletype *roletype = (struct cil_roletype *)node->data;
    358 
    359 	if (roletype->role) {
    360 		cil_log(CIL_ERR, "AST already resolved.  !!! Not yet supported.\n");
    361 		goto exit;
    362 	}
    363 	key = roletype->type_str;
    364 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    365 		roletype->type_str = __cil_attrib_get_versname(key, args->num);
    366 	}
    367 
    368 	return SEPOL_OK;
    369 exit:
    370 	return rc;
    371 }
    372 
    373 static int cil_attrib_type(struct cil_tree_node *node, struct version_args *args)
    374 {
    375 	int rc = SEPOL_ERR;
    376 	struct cil_type *type = (struct cil_type *)node->data;
    377 	char *key = type->datum.name;
    378 
    379 	if (type->value) {
    380 		cil_log(CIL_ERR, "AST already resolved.  !!! Not yet supported.\n");
    381 		goto exit;
    382 	}
    383 	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
    384 		rc = __cil_attrib_convert_type(node, args);
    385 		if (rc != SEPOL_OK) {
    386 			goto exit;
    387 		}
    388 	}
    389 
    390 	return SEPOL_OK;
    391 exit:
    392 	return rc;
    393 }
    394 
    395 static int cil_attrib_typepermissive(struct cil_tree_node *node,
    396 				     struct version_args *args __attribute__ ((unused)))
    397 {
    398 	struct cil_typepermissive *typeperm = (struct cil_typepermissive *)node->data;
    399 
    400 	if (typeperm->type != NULL) {
    401 		cil_log(CIL_ERR, "AST already resolved.  ### Not yet supported.\n");
    402 		return SEPOL_ERR;
    403 	}
    404 
    405 	return SEPOL_OK;
    406 }
    407 
    408 static int cil_attrib_typeattribute(struct cil_tree_node *node, struct version_args *args)
    409 {
    410 	int rc = SEPOL_ERR;
    411 	struct cil_typeattribute *typeattr = (struct cil_typeattribute *)node->data;
    412 	char *key = typeattr->datum.name;
    413 
    414 	if (typeattr->types) {
    415 		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
    416 			node->line);
    417 		goto exit;
    418 	}
    419 	if (!strncmp(key, "base_typeattr_", 14)) {
    420 		rc = __cil_attrib_swap_symtab_key(node, key, args->num);
    421 		if (rc != SEPOL_OK) {
    422 			goto exit;
    423 		}
    424 	} else if (__cil_get_plat_flavor(args->vers_map, key) == PLAT_ATTRIB) {
    425 		// platform attribute declaration to be provided by platform policy
    426 		cil_symtab_datum_remove_node(&typeattr->datum, node);
    427 		cil_destroy_typeattribute(typeattr);
    428 		node->flavor = CIL_NONE; // traversal relies on this node sticking around, empty it.
    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_tree_node *ast_node = NULL;
    783 	struct version_args *verargs = (struct version_args *)args;
    784 	struct cil_tree_node *ast_parent = verargs->db->ast->root;
    785 	char *orig_type = (char *) k;
    786 	struct version_datum *vers_datum = (struct version_datum *) d;
    787 
    788 	if (vers_datum->ast_node->flavor == CIL_TYPEATTRIBUTE) {
    789 		// platform attributes are not versioned
    790 		return SEPOL_OK;
    791 	}
    792 	/* create typeattributeset datum */
    793 	cil_typeattributeset_init(&attrset);
    794 	cil_list_init(&attrset->str_expr, CIL_TYPE);
    795 	attrset->attr_str = __cil_attrib_get_versname(orig_type, verargs->num);
    796 	cil_list_append(attrset->str_expr, CIL_STRING, orig_type);
    797 
    798 	/* create containing tree node */
    799 	cil_tree_node_init(&ast_node);
    800 	ast_node->data = attrset;
    801 	ast_node->flavor = CIL_TYPEATTRIBUTESET;
    802 
    803 	/* add to tree */
    804 	ast_node->parent = ast_parent;
    805 	if (ast_parent->cl_head == NULL)
    806 		ast_parent->cl_head = ast_node;
    807 	else
    808 		ast_parent->cl_tail->next = ast_node;
    809 	ast_parent->cl_tail = ast_node;
    810 	return SEPOL_OK;
    811 }
    812 
    813 /*
    814  * Initializes the given db and uses the version mapping generated by
    815  * cil_extract_attributees() to fill it with the glue policy required to
    816  * connect the attributized policy created by cil_attributize() to the policy
    817  * declaring the concrete types.
    818  */
    819 static int cil_attrib_mapping(struct cil_db **db, hashtab_t vers_map, const char *num)
    820 {
    821 	int rc = SEPOL_ERR;
    822 	struct version_args extra_args;
    823 
    824 	cil_db_init(db);
    825 
    826 	/* foreach entry in vers_map, create typeattributeset node and attach to tree */
    827 	extra_args.db = *db;
    828 	extra_args.vers_map = NULL;
    829 	extra_args.num = num;
    830 	rc = hashtab_map(vers_map, cil_build_mappings_tree, &extra_args);
    831 	if (rc != SEPOL_OK) {
    832 		goto exit;
    833 	}
    834 
    835 	return SEPOL_OK;
    836 exit:
    837 	return rc;
    838 }
    839 
    840 int cil_android_attrib_mapping(struct cil_db **mdb, struct cil_db *srcdb, const char *num)
    841 {
    842 	int rc = SEPOL_ERR;
    843 	hashtab_t ver_map_tab = NULL;
    844 
    845 	ver_map_tab = hashtab_create(ver_map_hash_val, ver_map_key_cmp, VER_MAP_SZ);
    846 	if (!ver_map_tab) {
    847 		cil_log(CIL_ERR, "Unable to create version mapping table.\n");
    848 		goto exit;
    849 	}
    850 	rc = cil_build_ast(srcdb, srcdb->parse->root, srcdb->ast->root);
    851 	if (rc != SEPOL_OK) {
    852 		cil_log(CIL_ERR, "Unable to build source db AST.\n");
    853 		goto exit;
    854 	}
    855 	rc = cil_extract_attributees(srcdb, ver_map_tab);
    856 	if (rc != SEPOL_OK) {
    857 		cil_log(CIL_ERR, "Unable to extract attributizable elements from source db.\n");
    858 		goto exit;
    859 	}
    860 	rc = cil_attrib_mapping(mdb, ver_map_tab, num);
    861 	if (rc != SEPOL_OK) {
    862 		cil_log(CIL_ERR, "Unable to create mapping db from source db.\n");
    863 		goto exit;
    864 	}
    865 exit:
    866 	ver_map_destroy(ver_map_tab);
    867 	return rc;
    868 }
    869 
    870 int cil_android_attributize(struct cil_db *tgtdb, struct cil_db *srcdb, const char *num)
    871 {
    872 	int rc = SEPOL_ERR;
    873 	hashtab_t ver_map_tab = NULL;
    874 
    875 	ver_map_tab = hashtab_create(ver_map_hash_val, ver_map_key_cmp, VER_MAP_SZ);
    876 	if (!ver_map_tab) {
    877 		cil_log(CIL_ERR, "Unable to create version mapping table.\n");
    878 		goto exit;
    879 	}
    880 	rc = cil_build_ast(srcdb, srcdb->parse->root, srcdb->ast->root);
    881 	if (rc != SEPOL_OK) {
    882 		cil_log(CIL_ERR, "Unable to build source db AST.\n");
    883 		goto exit;
    884 	}
    885 	rc = cil_extract_attributees(srcdb, ver_map_tab);
    886 	if (rc != SEPOL_OK) {
    887 		cil_log(CIL_ERR, "Unable to extract attributizable elements from source db.\n");
    888 		goto exit;
    889 	}
    890 	rc = cil_build_ast(tgtdb, tgtdb->parse->root, tgtdb->ast->root);
    891 	if (rc != SEPOL_OK) {
    892 		cil_log(CIL_ERR, "Unable to build target db AST.\n");
    893 		goto exit;
    894 	}
    895 	rc = cil_attributize(tgtdb, ver_map_tab, num);
    896 	if (rc != SEPOL_OK) {
    897 		cil_log(CIL_ERR, "Unable to attributize target db.\n");
    898 		goto exit;
    899 	}
    900 exit:
    901 	ver_map_destroy(ver_map_tab);
    902 	return rc;
    903 }
    904