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 */
15struct version_datum {
16	struct cil_db *db;
17	struct cil_tree_node *ast_node;
18	char *orig_name;
19};
20
21struct version_args {
22	struct cil_db *db;
23	hashtab_t vers_map;
24	const char *num;
25};
26
27enum plat_flavor {
28	PLAT_NONE = 0,
29	PLAT_TYPE,
30	PLAT_ATTRIB
31};
32
33static 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
50static 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 */
61static 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
68static void ver_map_destroy(hashtab_t h)
69{
70	hashtab_map(h, ver_map_entry_destroy, NULL);
71	hashtab_destroy(h);
72}
73
74static 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;
131exit:
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 */
142int 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;
156exit:
157	return rc;
158}
159
160static 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 */
187static 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 and replace existing type node.
204 */
205static 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	char *new_key;
211
212	cil_typeattribute_init(&typeattr);
213
214	new_key = __cil_attrib_get_versname(type->datum.name, args->num);
215
216	cil_symtab_datum_remove_node(&type->datum, node);
217	cil_destroy_type(type);
218
219	rc = cil_gen_node(args->db, node, (struct cil_symtab_datum *) typeattr,
220			  new_key, CIL_SYM_TYPES, CIL_TYPEATTRIBUTE);
221	if (rc != SEPOL_OK) {
222		goto exit;
223	}
224
225	return SEPOL_OK;
226exit:
227	return rc;
228}
229
230/*
231 * Update datum - create new key, remove entry under old key,
232 * update entry, and insert under new key
233 */
234static int __cil_attrib_swap_symtab_key(struct cil_tree_node *node, char *old_key,
235					const char *num)
236{
237	int rc = SEPOL_ERR;
238	char *new_key;
239	symtab_t *symtab;
240	struct cil_symtab_datum *datum = (struct cil_symtab_datum *) node->data;
241
242	new_key = __cil_attrib_get_versname(old_key, num);
243
244	symtab = datum->symtab;
245
246	/* TODO: remove, but what happens to other nodes on this datum ?*/
247	cil_list_remove(datum->nodes, CIL_NODE, node, 0);
248	cil_symtab_remove_datum(datum);
249
250	rc = cil_symtab_insert(symtab, new_key, datum, node);
251
252	if (rc != SEPOL_OK) {
253		goto exit;
254	}
255
256	return SEPOL_OK;
257exit:
258	return rc;
259}
260
261/*
262 * expressions may contains strings which are not in the type-attribute
263 * namespace, so this is not a general cil_expr attributizer.
264 * TODO: add support for other types of expressions which may contain types.
265 */
266static int cil_attrib_type_expr(struct cil_list *expr_str, struct version_args *args)
267{
268	int rc = SEPOL_ERR;
269	struct cil_list_item *curr = NULL;
270	char *new;
271	hashtab_key_t key;
272
273	/* iterate through cil_list, replacing types */
274	cil_list_for_each(curr, expr_str) {
275		switch(curr->flavor) {
276		case CIL_LIST:
277			rc = cil_attrib_type_expr((struct cil_list *)curr->data, args);
278			if (rc != SEPOL_OK)
279				goto exit;
280			break;
281		case CIL_STRING:
282			key = (hashtab_key_t) curr->data;
283			enum plat_flavor pf = __cil_get_plat_flavor(args->vers_map, key);
284			if (!strncmp(curr->data, "base_typeattr_", 14) || pf == PLAT_TYPE) {
285				new = __cil_attrib_get_versname((char *) curr->data, args->num);
286				curr->data = (void *) new;
287			}
288			break;
289		case CIL_DATUM:
290			cil_log(CIL_ERR, "AST already resolved. Not yet supported.\n");
291			rc = SEPOL_ERR;
292			goto exit;
293			break;
294		default:
295			break;
296		}
297	}
298
299	return SEPOL_OK;
300exit:
301	return rc;
302}
303
304static int cil_attrib_check_context(struct cil_context *ctxt, struct version_args *args)
305{
306	int rc = SEPOL_ERR;
307	hashtab_key_t key;
308
309	if (ctxt->type != NULL) {
310		cil_log(CIL_ERR, "AST already resolved. Not yet supported.\n");
311		goto exit;
312	}
313
314	key = (hashtab_key_t) ctxt->type_str;
315	if (__cil_get_plat_flavor(args->vers_map, key) != PLAT_NONE) {
316        /* TODO: reinstate check, but leave out for now
317		cil_log(CIL_ERR, "AST contains context with platform public type: %s\n",
318			ctxt->type_str);
319		rc = SEPOL_ERR;
320		goto exit; */
321	}
322
323	return SEPOL_OK;
324exit:
325	return rc;
326}
327
328static int cil_attrib_sidcontext(struct cil_tree_node *node, struct version_args *args)
329{
330	int rc = SEPOL_ERR;
331	struct cil_sidcontext *sidcon = (struct cil_sidcontext *)node->data;
332
333	if (sidcon->context_str == NULL) {
334		/* sidcon contains an anon context, which needs to have type checked */
335		rc = cil_attrib_check_context(sidcon->context, args);
336		if (rc != SEPOL_OK) {
337			goto exit;
338		}
339	}
340
341	return SEPOL_OK;
342exit:
343	return rc;
344}
345
346static int cil_attrib_context(struct cil_tree_node *node, struct version_args *args)
347{
348	struct cil_context *ctxt = (struct cil_context *)node->data;
349
350	return cil_attrib_check_context(ctxt, args);
351}
352
353static int cil_attrib_roletype(struct cil_tree_node *node,
354			       __attribute__((unused)) struct version_args *args)
355{
356	int rc = SEPOL_ERR;
357	char *key;
358	struct cil_roletype *roletype = (struct cil_roletype *)node->data;
359
360	if (roletype->role) {
361		cil_log(CIL_ERR, "AST already resolved.  !!! Not yet supported.\n");
362		goto exit;
363	}
364	key = roletype->type_str;
365	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
366		roletype->type_str = __cil_attrib_get_versname(key, args->num);
367	}
368
369	return SEPOL_OK;
370exit:
371	return rc;
372}
373
374static int cil_attrib_type(struct cil_tree_node *node, struct version_args *args)
375{
376	int rc = SEPOL_ERR;
377	struct cil_type *type = (struct cil_type *)node->data;
378	char *key = type->datum.name;
379
380	if (type->value) {
381		cil_log(CIL_ERR, "AST already resolved.  !!! Not yet supported.\n");
382		goto exit;
383	}
384	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
385		rc = __cil_attrib_convert_type(node, args);
386		if (rc != SEPOL_OK) {
387			goto exit;
388		}
389	}
390
391	return SEPOL_OK;
392exit:
393	return rc;
394}
395
396static int cil_attrib_typepermissive(struct cil_tree_node *node,
397				     struct version_args *args __attribute__ ((unused)))
398{
399	struct cil_typepermissive *typeperm = (struct cil_typepermissive *)node->data;
400
401	if (typeperm->type != NULL) {
402		cil_log(CIL_ERR, "AST already resolved.  ### Not yet supported.\n");
403		return SEPOL_ERR;
404	}
405
406	return SEPOL_OK;
407}
408
409static int cil_attrib_typeattribute(struct cil_tree_node *node, struct version_args *args)
410{
411	int rc = SEPOL_ERR;
412	struct cil_typeattribute *typeattr = (struct cil_typeattribute *)node->data;
413	char *key = typeattr->datum.name;
414
415	if (typeattr->types) {
416		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
417			node->line);
418		goto exit;
419	}
420	if (!strncmp(key, "base_typeattr_", 14)) {
421		rc = __cil_attrib_swap_symtab_key(node, key, args->num);
422		if (rc != SEPOL_OK) {
423			goto exit;
424		}
425	} else if (__cil_get_plat_flavor(args->vers_map, key) == PLAT_ATTRIB) {
426		// platform attribute declaration to be provided by platform policy
427		cil_symtab_datum_remove_node(&typeattr->datum, node);
428		cil_destroy_typeattribute(typeattr);
429		node->flavor = CIL_NONE; // traversal relies on this node sticking around, empty it.
430	}
431
432	return SEPOL_OK;
433exit:
434	return rc;
435}
436
437static int cil_attrib_typeattributeset(struct cil_tree_node *node, struct version_args *args)
438{
439	int rc = SEPOL_ERR;
440	char *key;
441	struct cil_typeattributeset *typeattrset = (struct cil_typeattributeset *) node->data;
442
443	if (typeattrset->datum_expr != NULL) {
444		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
445			node->line);
446		goto exit;
447	}
448
449	key = typeattrset->attr_str;
450	/* first check to see if the attribute to which this set belongs is versioned */
451	if (!strncmp(key, "base_typeattr_", 14)) {
452		typeattrset->attr_str = __cil_attrib_get_versname(key, args->num);
453	}
454
455	rc = cil_attrib_type_expr(typeattrset->str_expr, args);
456	if (rc != SEPOL_OK) {
457		goto exit;
458	}
459
460	return SEPOL_OK;
461exit:
462	return rc;
463}
464
465static int cil_attrib_typealiasactual(struct cil_tree_node *node, struct version_args *args)
466{
467	int rc = SEPOL_ERR;
468	char *key;
469	struct cil_aliasactual *aliasact = (struct cil_aliasactual *)node->data;
470
471	key = aliasact->actual_str;
472	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) != PLAT_NONE) {
473		cil_log(CIL_ERR, "%s with platform public type not allowed (line %d)\n",
474		    CIL_KEY_TYPEALIASACTUAL, node->line);
475		goto exit;
476	}
477
478	return SEPOL_OK;
479exit:
480	return rc;
481}
482
483static int cil_attrib_nametypetransition(struct cil_tree_node *node, struct version_args *args)
484{
485	int rc = SEPOL_ERR;
486	char *key;
487	struct cil_nametypetransition *namettrans = (struct cil_nametypetransition *)node->data;
488
489	if (namettrans->src != NULL) {
490		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
491			node->line);
492		goto exit;
493	}
494	key = namettrans->src_str;
495	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
496		namettrans->src_str = __cil_attrib_get_versname(key, args->num);
497	}
498
499	key = namettrans->tgt_str;
500	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
501		namettrans->tgt_str = __cil_attrib_get_versname(key, args->num);
502	}
503
504	return SEPOL_OK;
505exit:
506	return rc;
507}
508
509/*
510 * This is exactly the same as cil_attrib_nametypetransition, but the struct
511 * layouts differ, so we can't reuse it.
512 */
513static int cil_attrib_type_rule(struct cil_tree_node *node, struct version_args *args)
514{
515	int rc = SEPOL_ERR;
516	char *key;
517	struct cil_type_rule *type_rule = (struct cil_type_rule *)node->data;
518
519	if (type_rule->src != NULL) {
520		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
521			node->line);
522		goto exit;
523	}
524	key = type_rule->src_str;
525	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
526		type_rule->src_str = __cil_attrib_get_versname(key, args->num);
527	}
528
529	key = type_rule->tgt_str;
530	if (__cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
531		type_rule->tgt_str = __cil_attrib_get_versname(key, args->num);
532	}
533
534	return SEPOL_OK;
535exit:
536	return rc;
537}
538
539static int cil_attrib_avrule(struct cil_tree_node *node, struct version_args *args)
540{
541	int rc = SEPOL_ERR;
542	char *key;
543	struct cil_avrule *avrule = (struct cil_avrule *)node->data;
544
545	if (avrule->src != NULL) {
546		cil_log(CIL_ERR, "AST already resolved. Not yet supported (line %d).\n",
547			node->line);
548		goto exit;
549	}
550
551	key = avrule->src_str;
552	if (!strncmp(key, "base_typeattr_", 14) ||
553	    __cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
554		avrule->src_str = __cil_attrib_get_versname(key, args->num);
555	}
556
557	key = avrule->tgt_str;
558	if (!strncmp(key, "base_typeattr_", 14) ||
559	    __cil_get_plat_flavor(args->vers_map, (hashtab_key_t) key) == PLAT_TYPE) {
560		avrule->tgt_str = __cil_attrib_get_versname(key, args->num);
561	}
562
563	return SEPOL_OK;
564exit:
565	return rc;
566}
567
568static int cil_attrib_genfscon(struct cil_tree_node *node, struct version_args *args)
569{
570	int rc = SEPOL_ERR;
571
572	struct cil_genfscon *genfscon = (struct cil_genfscon *)node->data;
573
574	if (genfscon->context_str == NULL) {
575		/* genfscon contains an anon context, which needs to have type checked */
576		rc = cil_attrib_check_context(genfscon->context, args);
577		if (rc != SEPOL_OK) {
578			goto exit;
579		}
580	}
581
582	return SEPOL_OK;
583exit:
584	return rc;
585}
586
587static int cil_attrib_fsuse(struct cil_tree_node *node, struct version_args *args)
588{
589	int rc = SEPOL_ERR;
590	struct cil_fsuse *fsuse = (struct cil_fsuse *)node->data;
591
592	if (fsuse->context_str == NULL) {
593		/* fsuse contains an anon context, which needs to have type checked */
594		rc = cil_attrib_check_context(fsuse->context, args);
595		if (rc != SEPOL_OK) {
596			goto exit;
597		}
598	}
599
600	return SEPOL_OK;
601exit:
602	return rc;
603}
604
605static int __attributize_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
606{
607	int rc = SEPOL_ERR;
608	struct version_args *args = (struct version_args *) extra_args;
609
610	if (node == NULL || finished == NULL || extra_args == NULL) {
611		goto exit;
612	}
613
614	switch (node->flavor) {
615	case CIL_SIDCONTEXT:
616		/* contains type, but shouldn't involve an attributized type, maybe add
617		   a check on type and error if it conflicts */
618		rc = cil_attrib_sidcontext(node, args);
619		if (rc != SEPOL_OK) {
620			goto exit;
621		}
622		break;
623	case CIL_ROLE:
624		cil_log(CIL_ERR, "%s declaration illegal non-platform policy (line %d)\n",
625			CIL_KEY_ROLE, node->line);
626		rc = SEPOL_ERR;
627		break;
628	case CIL_ROLETYPE:
629		/* Yes, this is needed if we support roletype in non-platform policy.
630		   type_id can be type, typealias or typeattr */
631		rc = cil_attrib_roletype(node, args);
632		if (rc != SEPOL_OK) {
633			goto exit;
634		}
635		break;
636	case CIL_ROLEATTRIBUTE:
637		/* don't think this is needed, only used for cil_gen_req, and we aren't
638		   yet supporting roles in non-platform policy. */
639		break;
640	case CIL_TYPE:
641		/* conver to attribute if in policy */
642		rc = cil_attrib_type(node, args);
643		if (rc != SEPOL_OK) {
644			goto exit;
645		}
646		break;
647	case CIL_TYPEPERMISSIVE:
648		rc = cil_attrib_typepermissive(node, args);
649		if (rc != SEPOL_OK) {
650			goto exit;
651		}
652		break;
653	case CIL_TYPEATTRIBUTE:
654		rc = cil_attrib_typeattribute(node, args);
655		if (rc != SEPOL_OK) {
656			goto exit;
657		}
658		break;
659	case CIL_TYPEATTRIBUTESET:
660		rc = cil_attrib_typeattributeset(node, args);
661		if (rc != SEPOL_OK) {
662			goto exit;
663		}
664		break;
665	case CIL_TYPEALIASACTUAL:
666		/* this will break on an attributized type - identify it and throw error */
667		rc = cil_attrib_typealiasactual(node, args);
668		if (rc != SEPOL_OK) {
669			goto exit;
670		}
671		break;
672	case CIL_NAMETYPETRANSITION:
673		/* not allowed in plat-policy. Types present, throw error if attributee */
674		rc = cil_attrib_nametypetransition(node, args);
675		if (rc != SEPOL_OK) {
676			goto exit;
677		}
678		break;
679	case CIL_TYPE_RULE:
680		/* not allowed in plat-policy. Types present, throw error if attributee */
681		rc = cil_attrib_type_rule(node, args);
682		if (rc != SEPOL_OK) {
683			goto exit;
684		}
685		break;
686	case CIL_AVRULE:
687	case CIL_AVRULEX:
688		rc = cil_attrib_avrule(node, args);
689		if (rc != SEPOL_OK) {
690			goto exit;
691		}
692		break;
693	case CIL_CONTEXT:
694		/* not currently found in AOSP policy, but if found would need to be
695		   checked to not be attributee */
696		rc = cil_attrib_context(node, args);
697		if (rc != SEPOL_OK) {
698			goto exit;
699		}
700		break;
701	case CIL_GENFSCON:
702		/* not allowed in plat-policy, but types present, throw error if attributee */
703		rc = cil_attrib_genfscon(node, args);
704		if (rc != SEPOL_OK) {
705			goto exit;
706		}
707		break;
708	case CIL_FILECON:
709	case CIL_NODECON:
710	case CIL_PORTCON:
711	case CIL_PIRQCON:
712	case CIL_IOMEMCON:
713	case CIL_IOPORTCON:
714	case CIL_PCIDEVICECON:
715	case CIL_DEVICETREECON:
716	case CIL_VALIDATETRANS:
717	case CIL_MLSVALIDATETRANS:
718	case CIL_CALL:
719	case CIL_MACRO:
720	case CIL_OPTIONAL:
721		/* Not currently found in AOSP and not yet properly handled.  Return err until support added. */
722		cil_log(CIL_ERR, "unsupported policy statement (line %d)\n", node->line);
723		rc = SEPOL_ERR;
724		goto exit;
725	case CIL_FSUSE:
726		/* not allowed in plat-policy, but types present, throw error if attributee */
727		cil_attrib_fsuse(node, args);
728		if (rc != SEPOL_OK) {
729			goto exit;
730		}
731		break;
732	case CIL_CONSTRAIN:
733	case CIL_MLSCONSTRAIN:
734		/* there is type info here, but not sure if we'll allow non-platform code
735		   to have this, or whether or not it's in platform policy.  Currently
736		   assuming that mlsconstrain is private-platform only, and that normal
737		   constrain is verboten. */
738		cil_log(CIL_ERR, "unsupported policy statement (line %d)\n", node->line);
739		rc = SEPOL_ERR;
740		goto exit;
741	default:
742		break;
743	}
744
745	return SEPOL_OK;
746exit:
747	return rc;
748}
749
750/*
751 * walk ast, replacing previously identified types and attributes with the
752 * attributized version. Also replace previous references to the attributees
753 * with the versioned type.
754 */
755static int cil_attributize(struct cil_db *db, hashtab_t vers_map, const char *num)
756{
757	int rc = SEPOL_ERR;
758	struct version_args extra_args;
759	extra_args.db = db;
760	extra_args.vers_map = vers_map;
761	extra_args.num = num;
762
763	rc = cil_tree_walk(db->ast->root, __attributize_helper, NULL, NULL, &extra_args);
764	if (rc != SEPOL_OK) {
765		goto exit;
766	}
767
768	return SEPOL_OK;
769exit:
770	return rc;
771}
772
773/*
774 * Create typeattributeset mappings from the attributes generated from the
775 * original types/attributes to the original values.  This mapping will provide
776 * the basis for the platform policy's mapping to this public version.
777 *
778 * Add these new typeattributeset nodes to the given cil_db.
779 */
780static int cil_build_mappings_tree(hashtab_key_t k, hashtab_datum_t d, void *args)
781{
782	struct cil_typeattributeset *attrset = 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
790	if (vers_datum->ast_node->flavor == CIL_TYPEATTRIBUTE) {
791		// platform attributes are not versioned
792		return SEPOL_OK;
793	}
794	/* create typeattributeset datum */
795	cil_typeattributeset_init(&attrset);
796	cil_list_init(&attrset->str_expr, CIL_TYPE);
797	attrset->attr_str = __cil_attrib_get_versname(orig_type, verargs->num);
798	cil_list_append(attrset->str_expr, CIL_STRING, orig_type);
799
800	/* create containing tree node */
801	cil_tree_node_init(&ast_node);
802	ast_node->data = attrset;
803	ast_node->flavor = CIL_TYPEATTRIBUTESET;
804
805	/* add to tree */
806	ast_node->parent = ast_parent;
807	if (ast_parent->cl_head == NULL)
808		ast_parent->cl_head = ast_node;
809	else
810		ast_parent->cl_tail->next = ast_node;
811	ast_parent->cl_tail = ast_node;
812
813	/* create expandtypeattribute datum */
814	cil_expandtypeattribute_init(&expandattr);
815	cil_list_init(&expandattr->attr_strs, CIL_TYPE);
816	cil_list_append(expandattr->attr_strs, CIL_STRING, __cil_attrib_get_versname(orig_type, verargs->num));
817	expandattr->expand = CIL_TRUE;
818
819	/* create containing tree node */
820	cil_tree_node_init(&ast_node);
821	ast_node->data = expandattr;
822	ast_node->flavor = CIL_EXPANDTYPEATTRIBUTE;
823	/* add to tree */
824	ast_node->parent = ast_parent;
825	ast_parent->cl_tail->next = ast_node;
826	ast_parent->cl_tail = ast_node;
827
828	return SEPOL_OK;
829}
830
831/*
832 * Initializes the given db and uses the version mapping generated by
833 * cil_extract_attributees() to fill it with the glue policy required to
834 * connect the attributized policy created by cil_attributize() to the policy
835 * declaring the concrete types.
836 */
837static int cil_attrib_mapping(struct cil_db **db, hashtab_t vers_map, const char *num)
838{
839	int rc = SEPOL_ERR;
840	struct version_args extra_args;
841
842	cil_db_init(db);
843
844	/* foreach entry in vers_map, create typeattributeset node and attach to tree */
845	extra_args.db = *db;
846	extra_args.vers_map = NULL;
847	extra_args.num = num;
848	rc = hashtab_map(vers_map, cil_build_mappings_tree, &extra_args);
849	if (rc != SEPOL_OK) {
850		goto exit;
851	}
852
853	return SEPOL_OK;
854exit:
855	return rc;
856}
857
858int cil_android_attrib_mapping(struct cil_db **mdb, struct cil_db *srcdb, const char *num)
859{
860	int rc = SEPOL_ERR;
861	hashtab_t ver_map_tab = NULL;
862
863	ver_map_tab = hashtab_create(ver_map_hash_val, ver_map_key_cmp, VER_MAP_SZ);
864	if (!ver_map_tab) {
865		cil_log(CIL_ERR, "Unable to create version mapping table.\n");
866		goto exit;
867	}
868	rc = cil_build_ast(srcdb, srcdb->parse->root, srcdb->ast->root);
869	if (rc != SEPOL_OK) {
870		cil_log(CIL_ERR, "Unable to build source db AST.\n");
871		goto exit;
872	}
873	rc = cil_extract_attributees(srcdb, ver_map_tab);
874	if (rc != SEPOL_OK) {
875		cil_log(CIL_ERR, "Unable to extract attributizable elements from source db.\n");
876		goto exit;
877	}
878	rc = cil_attrib_mapping(mdb, ver_map_tab, num);
879	if (rc != SEPOL_OK) {
880		cil_log(CIL_ERR, "Unable to create mapping db from source db.\n");
881		goto exit;
882	}
883exit:
884	ver_map_destroy(ver_map_tab);
885	return rc;
886}
887
888int cil_android_attributize(struct cil_db *tgtdb, struct cil_db *srcdb, const char *num)
889{
890	int rc = SEPOL_ERR;
891	hashtab_t ver_map_tab = NULL;
892
893	ver_map_tab = hashtab_create(ver_map_hash_val, ver_map_key_cmp, VER_MAP_SZ);
894	if (!ver_map_tab) {
895		cil_log(CIL_ERR, "Unable to create version mapping table.\n");
896		goto exit;
897	}
898	rc = cil_build_ast(srcdb, srcdb->parse->root, srcdb->ast->root);
899	if (rc != SEPOL_OK) {
900		cil_log(CIL_ERR, "Unable to build source db AST.\n");
901		goto exit;
902	}
903	rc = cil_extract_attributees(srcdb, ver_map_tab);
904	if (rc != SEPOL_OK) {
905		cil_log(CIL_ERR, "Unable to extract attributizable elements from source db.\n");
906		goto exit;
907	}
908	rc = cil_build_ast(tgtdb, tgtdb->parse->root, tgtdb->ast->root);
909	if (rc != SEPOL_OK) {
910		cil_log(CIL_ERR, "Unable to build target db AST.\n");
911		goto exit;
912	}
913	rc = cil_attributize(tgtdb, ver_map_tab, num);
914	if (rc != SEPOL_OK) {
915		cil_log(CIL_ERR, "Unable to attributize target db.\n");
916		goto exit;
917	}
918exit:
919	ver_map_destroy(ver_map_tab);
920	return rc;
921}
922