From: <mil...@us...> - 2008-03-05 14:45:22
|
Revision: 2841 http://selinux.svn.sourceforge.net/selinux/?rev=2841&view=rev Author: millertc Date: 2008-03-05 06:45:21 -0800 (Wed, 05 Mar 2008) Log Message: ----------- The changes are purely mechanical. Everything but the yacc rules has been moved from policy_parse.c into policy_define.c and policy_define.h. This allows us to retain strict error checking (-Werror) on the SELinux toolchain without our being tripped up by generated (yacc/bison) code. Signed-off-by: Todd C. Miller <tm...@tr...> Acked-by: Stephen Smalley <sd...@ty...> Modified Paths: -------------- trunk/checkpolicy/Makefile trunk/checkpolicy/policy_parse.y Added Paths: ----------- trunk/checkpolicy/policy_define.c trunk/checkpolicy/policy_define.h Modified: trunk/checkpolicy/Makefile =================================================================== --- trunk/checkpolicy/Makefile 2008-03-05 12:50:37 UTC (rev 2840) +++ trunk/checkpolicy/Makefile 2008-03-05 14:45:21 UTC (rev 2841) @@ -14,7 +14,8 @@ override CFLAGS += -I. -I${INCLUDEDIR} -CHECKOBJS = y.tab.o lex.yy.o queue.o module_compiler.o parse_util.o +CHECKOBJS = y.tab.o lex.yy.o queue.o module_compiler.o parse_util.o \ + policy_define.o CHECKPOLOBJS = $(CHECKOBJS) checkpolicy.o CHECKMODOBJS = $(CHECKOBJS) checkmodule.o Added: trunk/checkpolicy/policy_define.c =================================================================== --- trunk/checkpolicy/policy_define.c (rev 0) +++ trunk/checkpolicy/policy_define.c 2008-03-05 14:45:21 UTC (rev 2841) @@ -0,0 +1,3831 @@ +/* + * Author : Stephen Smalley, <sd...@ep...> + */ + +/* + * Updated: Trusted Computer Solutions, Inc. <dgo...@tr...> + * + * Support for enhanced MLS infrastructure. + * + * Updated: David Caplan, <da...@tr...> + * + * Added conditional policy language extensions + * + * Updated: Joshua Brindle <jbr...@tr...> + * Karl MacMillan <kma...@me...> + * Jason Tang <jt...@tr...> + * + * Added support for binary policy modules + * + * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. + * Copyright (C) 2003 - 2008 Tresys Technology, LLC + * Copyright (C) 2007 Red Hat Inc. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + */ + +/* FLASK */ + +#include <sys/types.h> +#include <assert.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> + +#include <sepol/policydb/expand.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/polcaps.h> +#include "queue.h" +#include "checkpolicy.h" +#include "module_compiler.h" +#include "policy_define.h" + +policydb_t *policydbp; +queue_t id_queue = 0; +unsigned int pass; +char *curfile = 0; +int mlspol = 0; + +extern unsigned long policydb_lineno; +extern unsigned long source_lineno; +extern unsigned int policydb_errors; + +extern int yywarn(char *msg); +extern int yyerror(char *msg); + +#define ERRORMSG_LEN 255 +static char errormsg[ERRORMSG_LEN + 1] = {0}; + +static int id_has_dot(char *id); +static int parse_security_context(context_struct_t *c); + +/* initialize all of the state variables for the scanner/parser */ +void init_parser(int pass_number) +{ + policydb_lineno = 1; + source_lineno = 1; + policydb_errors = 0; + pass = pass_number; +} + +void yyerror2(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsnprintf(errormsg, ERRORMSG_LEN, fmt, ap); + yyerror(errormsg); + va_end(ap); +} + +int insert_separator(int push) +{ + int error; + + if (push) + error = queue_push(id_queue, 0); + else + error = queue_insert(id_queue, 0); + + if (error) { + yyerror("queue overflow"); + return -1; + } + return 0; +} + +int insert_id(char *id, int push) +{ + char *newid = 0; + int error; + + newid = (char *)malloc(strlen(id) + 1); + if (!newid) { + yyerror("out of memory"); + return -1; + } + strcpy(newid, id); + if (push) + error = queue_push(id_queue, (queue_element_t) newid); + else + error = queue_insert(id_queue, (queue_element_t) newid); + + if (error) { + yyerror("queue overflow"); + free(newid); + return -1; + } + return 0; +} + +/* If the identifier has a dot within it and that its first character + is not a dot then return 1, else return 0. */ +static int id_has_dot(char *id) +{ + if (strchr(id, '.') >= id + 1) { + return 1; + } + return 0; +} + +int define_class(void) +{ + char *id = 0; + class_datum_t *datum = 0; + int ret; + uint32_t value; + + if (pass == 2) { + id = queue_remove(id_queue); + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no class name for class definition?"); + return -1; + } + datum = (class_datum_t *) malloc(sizeof(class_datum_t)); + if (!datum) { + yyerror("out of memory"); + goto bad; + } + memset(datum, 0, sizeof(class_datum_t)); + ret = declare_symbol(SYM_CLASSES, id, datum, &value, &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto bad; + } + case -2:{ + yyerror2("duplicate declaration of class %s", id); + goto bad; + } + case -1:{ + yyerror("could not declare class here"); + goto bad; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + datum->s.value = value; + return 0; + + bad: + if (id) + free(id); + if (datum) + free(datum); + return -1; +} + +int define_polcap(void) +{ + char *id = 0; + int capnum; + + if (pass == 2) { + id = queue_remove(id_queue); + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no capability name for policycap definition?"); + goto bad; + } + + /* Check for valid cap name -> number mapping */ + capnum = sepol_polcap_getnum(id); + if (capnum < 0) { + yyerror2("invalid policy capability name %s", id); + goto bad; + } + + /* Store it */ + if (ebitmap_set_bit(&policydbp->policycaps, capnum, TRUE)) { + yyerror("out of memory"); + goto bad; + } + + free(id); + return 0; + + bad: + free(id); + return -1; +} + +int define_initial_sid(void) +{ + char *id = 0; + ocontext_t *newc = 0, *c, *head; + + if (pass == 2) { + id = queue_remove(id_queue); + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no sid name for SID definition?"); + return -1; + } + newc = (ocontext_t *) malloc(sizeof(ocontext_t)); + if (!newc) { + yyerror("out of memory"); + goto bad; + } + memset(newc, 0, sizeof(ocontext_t)); + newc->u.name = id; + context_init(&newc->context[0]); + head = policydbp->ocontexts[OCON_ISID]; + + for (c = head; c; c = c->next) { + if (!strcmp(newc->u.name, c->u.name)) { + yyerror2("duplicate initial SID %s", id); + goto bad; + } + } + + if (head) { + newc->sid[0] = head->sid[0] + 1; + } else { + newc->sid[0] = 1; + } + newc->next = head; + policydbp->ocontexts[OCON_ISID] = newc; + + return 0; + + bad: + if (id) + free(id); + if (newc) + free(newc); + return -1; +} + +int define_common_perms(void) +{ + char *id = 0, *perm = 0; + common_datum_t *comdatum = 0; + perm_datum_t *perdatum = 0; + int ret; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no common name for common perm definition?"); + return -1; + } + comdatum = hashtab_search(policydbp->p_commons.table, id); + if (comdatum) { + yyerror2("duplicate declaration for common %s\n", id); + return -1; + } + comdatum = (common_datum_t *) malloc(sizeof(common_datum_t)); + if (!comdatum) { + yyerror("out of memory"); + goto bad; + } + memset(comdatum, 0, sizeof(common_datum_t)); + ret = hashtab_insert(policydbp->p_commons.table, + (hashtab_key_t) id, (hashtab_datum_t) comdatum); + + if (ret == SEPOL_EEXIST) { + yyerror("duplicate common definition"); + goto bad; + } + if (ret == SEPOL_ENOMEM) { + yyerror("hash table overflow"); + goto bad; + } + comdatum->s.value = policydbp->p_commons.nprim + 1; + if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE)) { + yyerror("out of memory"); + goto bad; + } + policydbp->p_commons.nprim++; + while ((perm = queue_remove(id_queue))) { + perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t)); + if (!perdatum) { + yyerror("out of memory"); + goto bad_perm; + } + memset(perdatum, 0, sizeof(perm_datum_t)); + perdatum->s.value = comdatum->permissions.nprim + 1; + + if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) { + yyerror + ("too many permissions to fit in an access vector"); + goto bad_perm; + } + ret = hashtab_insert(comdatum->permissions.table, + (hashtab_key_t) perm, + (hashtab_datum_t) perdatum); + + if (ret == SEPOL_EEXIST) { + yyerror2("duplicate permission %s in common %s", perm, + id); + goto bad_perm; + } + if (ret == SEPOL_ENOMEM) { + yyerror("hash table overflow"); + goto bad_perm; + } + comdatum->permissions.nprim++; + } + + return 0; + + bad: + if (id) + free(id); + if (comdatum) + free(comdatum); + return -1; + + bad_perm: + if (perm) + free(perm); + if (perdatum) + free(perdatum); + return -1; +} + +int define_av_perms(int inherits) +{ + char *id; + class_datum_t *cladatum; + common_datum_t *comdatum; + perm_datum_t *perdatum = 0, *perdatum2 = 0; + int ret; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no tclass name for av perm definition?"); + return -1; + } + cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, + (hashtab_key_t) id); + if (!cladatum) { + yyerror2("class %s is not defined", id); + goto bad; + } + free(id); + + if (cladatum->comdatum || cladatum->permissions.nprim) { + yyerror("duplicate access vector definition"); + return -1; + } + if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE)) { + yyerror("out of memory"); + return -1; + } + if (inherits) { + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror + ("no inherits name for access vector definition?"); + return -1; + } + comdatum = + (common_datum_t *) hashtab_search(policydbp->p_commons. + table, + (hashtab_key_t) id); + + if (!comdatum) { + yyerror2("common %s is not defined", id); + goto bad; + } + cladatum->comkey = id; + cladatum->comdatum = comdatum; + + /* + * Class-specific permissions start with values + * after the last common permission. + */ + cladatum->permissions.nprim += comdatum->permissions.nprim; + } + while ((id = queue_remove(id_queue))) { + perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t)); + if (!perdatum) { + yyerror("out of memory"); + goto bad; + } + memset(perdatum, 0, sizeof(perm_datum_t)); + perdatum->s.value = ++cladatum->permissions.nprim; + + if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) { + yyerror + ("too many permissions to fit in an access vector"); + goto bad; + } + if (inherits) { + /* + * Class-specific permissions and + * common permissions exist in the same + * name space. + */ + perdatum2 = + (perm_datum_t *) hashtab_search(cladatum->comdatum-> + permissions.table, + (hashtab_key_t) id); + if (perdatum2) { + yyerror2("permission %s conflicts with an " + "inherited permission", id); + goto bad; + } + } + ret = hashtab_insert(cladatum->permissions.table, + (hashtab_key_t) id, + (hashtab_datum_t) perdatum); + + if (ret == SEPOL_EEXIST) { + yyerror2("duplicate permission %s", id); + goto bad; + } + if (ret == SEPOL_ENOMEM) { + yyerror("hash table overflow"); + goto bad; + } + if (add_perm_to_class(perdatum->s.value, cladatum->s.value)) { + yyerror("out of memory"); + goto bad; + } + } + + return 0; + + bad: + if (id) + free(id); + if (perdatum) + free(perdatum); + return -1; +} + +int define_sens(void) +{ + char *id; + mls_level_t *level = 0; + level_datum_t *datum = 0, *aliasdatum = 0; + int ret; + uint32_t value; /* dummy variable -- its value is never used */ + + if (!mlspol) { + yyerror("sensitivity definition in non-MLS configuration"); + return -1; + } + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no sensitivity name for sensitivity definition?"); + return -1; + } + if (id_has_dot(id)) { + yyerror("sensitivity identifiers may not contain periods"); + goto bad; + } + level = (mls_level_t *) malloc(sizeof(mls_level_t)); + if (!level) { + yyerror("out of memory"); + goto bad; + } + mls_level_init(level); + level->sens = 0; /* actual value set in define_dominance */ + ebitmap_init(&level->cat); /* actual value set in define_level */ + + datum = (level_datum_t *) malloc(sizeof(level_datum_t)); + if (!datum) { + yyerror("out of memory"); + goto bad; + } + level_datum_init(datum); + datum->isalias = FALSE; + datum->level = level; + + ret = declare_symbol(SYM_LEVELS, id, datum, &value, &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto bad; + } + case -2:{ + yyerror("duplicate declaration of sensitivity level"); + goto bad; + } + case -1:{ + yyerror("could not declare sensitivity level here"); + goto bad; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + + while ((id = queue_remove(id_queue))) { + if (id_has_dot(id)) { + yyerror("sensitivity aliases may not contain periods"); + goto bad_alias; + } + aliasdatum = (level_datum_t *) malloc(sizeof(level_datum_t)); + if (!aliasdatum) { + yyerror("out of memory"); + goto bad_alias; + } + level_datum_init(aliasdatum); + aliasdatum->isalias = TRUE; + aliasdatum->level = level; + + ret = declare_symbol(SYM_LEVELS, id, aliasdatum, NULL, &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto bad_alias; + } + case -2:{ + yyerror + ("duplicate declaration of sensitivity alias"); + goto bad_alias; + } + case -1:{ + yyerror + ("could not declare sensitivity alias here"); + goto bad_alias; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + } + + return 0; + + bad: + if (id) + free(id); + if (level) + free(level); + if (datum) { + level_datum_destroy(datum); + free(datum); + } + return -1; + + bad_alias: + if (id) + free(id); + if (aliasdatum) { + level_datum_destroy(aliasdatum); + free(aliasdatum); + } + return -1; +} + +int define_dominance(void) +{ + level_datum_t *datum; + int order; + char *id; + + if (!mlspol) { + yyerror("dominance definition in non-MLS configuration"); + return -1; + } + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + order = 0; + while ((id = (char *)queue_remove(id_queue))) { + datum = + (level_datum_t *) hashtab_search(policydbp->p_levels.table, + (hashtab_key_t) id); + if (!datum) { + yyerror2("unknown sensitivity %s used in dominance " + "definition", id); + free(id); + return -1; + } + if (datum->level->sens != 0) { + yyerror2("sensitivity %s occurs multiply in dominance " + "definition", id); + free(id); + return -1; + } + datum->level->sens = ++order; + + /* no need to keep sensitivity name */ + free(id); + } + + if (order != policydbp->p_levels.nprim) { + yyerror + ("all sensitivities must be specified in dominance definition"); + return -1; + } + return 0; +} + +int define_category(void) +{ + char *id; + cat_datum_t *datum = 0, *aliasdatum = 0; + int ret; + uint32_t value; + + if (!mlspol) { + yyerror("category definition in non-MLS configuration"); + return -1; + } + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no category name for category definition?"); + return -1; + } + if (id_has_dot(id)) { + yyerror("category identifiers may not contain periods"); + goto bad; + } + datum = (cat_datum_t *) malloc(sizeof(cat_datum_t)); + if (!datum) { + yyerror("out of memory"); + goto bad; + } + cat_datum_init(datum); + datum->isalias = FALSE; + + ret = declare_symbol(SYM_CATS, id, datum, &value, &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto bad; + } + case -2:{ + yyerror("duplicate declaration of category"); + goto bad; + } + case -1:{ + yyerror("could not declare category here"); + goto bad; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + datum->s.value = value; + + while ((id = queue_remove(id_queue))) { + if (id_has_dot(id)) { + yyerror("category aliases may not contain periods"); + goto bad_alias; + } + aliasdatum = (cat_datum_t *) malloc(sizeof(cat_datum_t)); + if (!aliasdatum) { + yyerror("out of memory"); + goto bad_alias; + } + cat_datum_init(aliasdatum); + aliasdatum->isalias = TRUE; + aliasdatum->s.value = datum->s.value; + + ret = + declare_symbol(SYM_CATS, id, aliasdatum, NULL, + &datum->s.value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto bad_alias; + } + case -2:{ + yyerror + ("duplicate declaration of category aliases"); + goto bad_alias; + } + case -1:{ + yyerror + ("could not declare category aliases here"); + goto bad_alias; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + } + + return 0; + + bad: + if (id) + free(id); + if (datum) { + cat_datum_destroy(datum); + free(datum); + } + return -1; + + bad_alias: + if (id) + free(id); + if (aliasdatum) { + cat_datum_destroy(aliasdatum); + free(aliasdatum); + } + return -1; +} + +static int clone_level(hashtab_key_t key, hashtab_datum_t datum, void *arg) +{ + level_datum_t *levdatum = (level_datum_t *) datum; + mls_level_t *level = (mls_level_t *) arg, *newlevel; + + if (levdatum->level == level) { + levdatum->defined = 1; + if (!levdatum->isalias) + return 0; + newlevel = (mls_level_t *) malloc(sizeof(mls_level_t)); + if (!newlevel) + return -1; + if (mls_level_cpy(newlevel, level)) { + free(newlevel); + return -1; + } + levdatum->level = newlevel; + } + return 0; +} + +int define_level(void) +{ + char *id; + level_datum_t *levdatum; + + if (!mlspol) { + yyerror("level definition in non-MLS configuration"); + return -1; + } + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no level name for level definition?"); + return -1; + } + levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, + (hashtab_key_t) id); + if (!levdatum) { + yyerror2("unknown sensitivity %s used in level definition", id); + free(id); + return -1; + } + if (ebitmap_length(&levdatum->level->cat)) { + yyerror2("sensitivity %s used in multiple level definitions", + id); + free(id); + return -1; + } + free(id); + + levdatum->defined = 1; + + while ((id = queue_remove(id_queue))) { + cat_datum_t *cdatum; + int range_start, range_end, i; + + if (id_has_dot(id)) { + char *id_start = id; + char *id_end = strchr(id, '.'); + + *(id_end++) = '\0'; + + cdatum = + (cat_datum_t *) hashtab_search(policydbp->p_cats. + table, + (hashtab_key_t) + id_start); + if (!cdatum) { + yyerror2("unknown category %s", id_start); + free(id); + return -1; + } + range_start = cdatum->s.value - 1; + cdatum = + (cat_datum_t *) hashtab_search(policydbp->p_cats. + table, + (hashtab_key_t) + id_end); + if (!cdatum) { + yyerror2("unknown category %s", id_end); + free(id); + return -1; + } + range_end = cdatum->s.value - 1; + + if (range_end < range_start) { + yyerror2("category range is invalid"); + free(id); + return -1; + } + } else { + cdatum = + (cat_datum_t *) hashtab_search(policydbp->p_cats. + table, + (hashtab_key_t) id); + range_start = range_end = cdatum->s.value - 1; + } + + for (i = range_start; i <= range_end; i++) { + if (ebitmap_set_bit(&levdatum->level->cat, i, TRUE)) { + yyerror("out of memory"); + free(id); + return -1; + } + } + + free(id); + } + + if (hashtab_map + (policydbp->p_levels.table, clone_level, levdatum->level)) { + yyerror("out of memory"); + return -1; + } + + return 0; +} + +int define_attrib(void) +{ + if (pass == 2) { + free(queue_remove(id_queue)); + return 0; + } + + if (declare_type(TRUE, TRUE) == NULL) { + return -1; + } + return 0; +} + +static int add_aliases_to_type(type_datum_t * type) +{ + char *id; + type_datum_t *aliasdatum = NULL; + int ret; + while ((id = queue_remove(id_queue))) { + if (id_has_dot(id)) { + free(id); + yyerror + ("type alias identifiers may not contain periods"); + return -1; + } + aliasdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); + if (!aliasdatum) { + free(id); + yyerror("Out of memory!"); + return -1; + } + memset(aliasdatum, 0, sizeof(type_datum_t)); + aliasdatum->s.value = type->s.value; + + ret = declare_symbol(SYM_TYPES, id, aliasdatum, + NULL, &aliasdatum->s.value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto cleanup; + } + case -2:{ + yyerror2("duplicate declaration of alias %s", + id); + goto cleanup; + } + case -1:{ + yyerror("could not declare alias here"); + goto cleanup; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + } + return 0; + cleanup: + free(id); + type_datum_destroy(aliasdatum); + free(aliasdatum); + return -1; +} + +int define_typealias(void) +{ + char *id; + type_datum_t *t; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no type name for typealias definition?"); + return -1; + } + + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + return -1; + } + t = hashtab_search(policydbp->p_types.table, id); + if (!t || t->flavor == TYPE_ATTRIB) { + yyerror2("unknown type %s, or it was already declared as an " + "attribute", id); + free(id); + return -1; + } + return add_aliases_to_type(t); +} + +int define_typeattribute(void) +{ + char *id; + type_datum_t *t, *attr; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no type name for typeattribute definition?"); + return -1; + } + + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + return -1; + } + t = hashtab_search(policydbp->p_types.table, id); + if (!t || t->flavor == TYPE_ATTRIB) { + yyerror2("unknown type %s", id); + free(id); + return -1; + } + + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("attribute %s is not within scope", id); + free(id); + return -1; + } + attr = hashtab_search(policydbp->p_types.table, id); + if (!attr) { + /* treat it as a fatal error */ + yyerror2("attribute %s is not declared", id); + free(id); + return -1; + } + + if (attr->flavor != TYPE_ATTRIB) { + yyerror2("%s is a type, not an attribute", id); + free(id); + return -1; + } + + if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) { + yyerror("Out of memory!"); + return -1; + } + + if (ebitmap_set_bit(&attr->types, (t->s.value - 1), TRUE)) { + yyerror("out of memory"); + return -1; + } + } + + return 0; +} + +int define_type(int alias) +{ + char *id; + type_datum_t *datum, *attr; + int newattr = 0; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + if (alias) { + while ((id = queue_remove(id_queue))) + free(id); + } + return 0; + } + + if ((datum = declare_type(TRUE, FALSE)) == NULL) { + return -1; + } + + if (alias) { + if (add_aliases_to_type(datum) == -1) { + return -1; + } + } + + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("attribute %s is not within scope", id); + free(id); + return -1; + } + attr = hashtab_search(policydbp->p_types.table, id); + if (!attr) { + /* treat it as a fatal error */ + yyerror2("attribute %s is not declared", id); + return -1; + } else { + newattr = 0; + } + + if (attr->flavor != TYPE_ATTRIB) { + yyerror2("%s is a type, not an attribute", id); + return -1; + } + + if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) { + yyerror("Out of memory!"); + return -1; + } + + if (ebitmap_set_bit(&attr->types, datum->s.value - 1, TRUE)) { + yyerror("Out of memory"); + return -1; + } + } + + return 0; +} + +struct val_to_name { + unsigned int val; + char *name; +}; + +/* Adds a type, given by its textual name, to a typeset. If *add is + 0, then add the type to the negative set; otherwise if *add is 1 + then add it to the positive side. */ +static int set_types(type_set_t * set, char *id, int *add, char starallowed) +{ + type_datum_t *t; + + if (strcmp(id, "*") == 0) { + if (!starallowed) { + yyerror("* not allowed in this type of rule"); + return -1; + } + /* set TYPE_STAR flag */ + set->flags = TYPE_STAR; + free(id); + *add = 1; + return 0; + } + + if (strcmp(id, "~") == 0) { + if (!starallowed) { + yyerror("~ not allowed in this type of rule"); + return -1; + } + /* complement the set */ + set->flags = TYPE_COMP; + free(id); + *add = 1; + return 0; + } + + if (strcmp(id, "-") == 0) { + *add = 0; + free(id); + return 0; + } + + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + return -1; + } + t = hashtab_search(policydbp->p_types.table, id); + if (!t) { + yyerror2("unknown type %s", id); + free(id); + return -1; + } + + if (*add == 0) { + if (ebitmap_set_bit(&set->negset, t->s.value - 1, TRUE)) + goto oom; + } else { + if (ebitmap_set_bit(&set->types, t->s.value - 1, TRUE)) + goto oom; + } + free(id); + *add = 1; + return 0; + oom: + yyerror("Out of memory"); + free(id); + return -1; +} + +int define_compute_type_helper(int which, avrule_t ** rule) +{ + char *id; + type_datum_t *datum; + class_datum_t *cladatum; + ebitmap_t tclasses; + ebitmap_node_t *node; + avrule_t *avrule; + class_perm_node_t *perm; + int i, add = 1; + + avrule = malloc(sizeof(avrule_t)); + if (!avrule) { + yyerror("out of memory"); + return -1; + } + avrule_init(avrule); + avrule->specified = which; + avrule->line = policydb_lineno; + + while ((id = queue_remove(id_queue))) { + if (set_types(&avrule->stypes, id, &add, 0)) + return -1; + } + add = 1; + while ((id = queue_remove(id_queue))) { + if (set_types(&avrule->ttypes, id, &add, 0)) + return -1; + } + + ebitmap_init(&tclasses); + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); + free(id); + goto bad; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); + if (!cladatum) { + yyerror2("unknown class %s", id); + goto bad; + } + if (ebitmap_set_bit(&tclasses, cladatum->s.value - 1, TRUE)) { + yyerror("Out of memory"); + goto bad; + } + free(id); + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no newtype?"); + goto bad; + } + if (!is_id_in_scope(SYM_TYPES, id)) { + yyerror2("type %s is not within scope", id); + free(id); + goto bad; + } + datum = (type_datum_t *) hashtab_search(policydbp->p_types.table, + (hashtab_key_t) id); + if (!datum || datum->flavor == TYPE_ATTRIB) { + yyerror2("unknown type %s", id); + goto bad; + } + + ebitmap_for_each_bit(&tclasses, node, i) { + if (ebitmap_node_get_bit(node, i)) { + perm = malloc(sizeof(class_perm_node_t)); + if (!perm) { + yyerror("out of memory"); + return -1; + } + class_perm_node_init(perm); + perm->class = i + 1; + perm->data = datum->s.value; + perm->next = avrule->perms; + avrule->perms = perm; + } + } + ebitmap_destroy(&tclasses); + + *rule = avrule; + return 0; + + bad: + avrule_destroy(avrule); + free(avrule); + return -1; +} + +int define_compute_type(int which) +{ + char *id; + avrule_t *avrule; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + id = queue_remove(id_queue); + free(id); + return 0; + } + + if (define_compute_type_helper(which, &avrule)) + return -1; + + append_avrule(avrule); + return 0; +} + +avrule_t *define_cond_compute_type(int which) +{ + char *id; + avrule_t *avrule; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + id = queue_remove(id_queue); + free(id); + return (avrule_t *) 1; + } + + if (define_compute_type_helper(which, &avrule)) + return COND_ERR; + + return avrule; +} + +int define_bool(void) +{ + char *id, *bool_value; + cond_bool_datum_t *datum; + int ret; + uint32_t value; + + if (pass == 2) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no identifier for bool definition?"); + return -1; + } + if (id_has_dot(id)) { + free(id); + yyerror("boolean identifiers may not contain periods"); + return -1; + } + datum = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t)); + if (!datum) { + yyerror("out of memory"); + free(id); + return -1; + } + memset(datum, 0, sizeof(cond_bool_datum_t)); + ret = declare_symbol(SYM_BOOLS, id, datum, &value, &value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto cleanup; + } + case -2:{ + yyerror2("duplicate declaration of boolean %s", id); + goto cleanup; + } + case -1:{ + yyerror("could not declare boolean here"); + goto cleanup; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + datum->s.value = value; + + bool_value = (char *)queue_remove(id_queue); + if (!bool_value) { + yyerror("no default value for bool definition?"); + free(id); + return -1; + } + + datum->state = (int)(bool_value[0] == 'T') ? 1 : 0; + return 0; + cleanup: + cond_destroy_bool(id, datum, NULL); + return -1; +} + +avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl) +{ + if (pass == 1) { + /* return something so we get through pass 1 */ + return (avrule_t *) 1; + } + + if (sl == NULL) { + /* This is a require block, return previous list */ + return avlist; + } + + /* prepend the new avlist to the pre-existing one */ + sl->next = avlist; + return sl; +} + +int define_te_avtab_helper(int which, avrule_t ** rule) +{ + char *id; + class_datum_t *cladatum; + perm_datum_t *perdatum = NULL; + class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL; + ebitmap_t tclasses; + ebitmap_node_t *node; + avrule_t *avrule; + unsigned int i; + int add = 1, ret = 0; + int suppress = 0; + + avrule = (avrule_t *) malloc(sizeof(avrule_t)); + if (!avrule) { + yyerror("memory error"); + ret = -1; + goto out; + } + avrule_init(avrule); + avrule->specified = which; + avrule->line = policydb_lineno; + + while ((id = queue_remove(id_queue))) { + if (set_types + (&avrule->stypes, id, &add, + which == AVRULE_NEVERALLOW ? 1 : 0)) { + ret = -1; + goto out; + } + } + add = 1; + while ((id = queue_remove(id_queue))) { + if (strcmp(id, "self") == 0) { + free(id); + avrule->flags |= RULE_SELF; + continue; + } + if (set_types + (&avrule->ttypes, id, &add, + which == AVRULE_NEVERALLOW ? 1 : 0)) { + ret = -1; + goto out; + } + } + + ebitmap_init(&tclasses); + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); + ret = -1; + goto out; + } + cladatum = hashtab_search(policydbp->p_classes.table, id); + if (!cladatum) { + yyerror2("unknown class %s used in rule", id); + ret = -1; + goto out; + } + if (ebitmap_set_bit(&tclasses, cladatum->s.value - 1, TRUE)) { + yyerror("Out of memory"); + ret = -1; + goto out; + } + free(id); + } + + perms = NULL; + ebitmap_for_each_bit(&tclasses, node, i) { + if (!ebitmap_node_get_bit(node, i)) + continue; + cur_perms = + (class_perm_node_t *) malloc(sizeof(class_perm_node_t)); + if (!cur_perms) { + yyerror("out of memory"); + ret = -1; + goto out; + } + class_perm_node_init(cur_perms); + cur_perms->class = i + 1; + if (!perms) + perms = cur_perms; + if (tail) + tail->next = cur_perms; + tail = cur_perms; + } + + while ((id = queue_remove(id_queue))) { + cur_perms = perms; + ebitmap_for_each_bit(&tclasses, node, i) { + if (!ebitmap_node_get_bit(node, i)) + continue; + cladatum = policydbp->class_val_to_struct[i]; + + if (strcmp(id, "*") == 0) { + /* set all permissions in the class */ + cur_perms->data = ~0U; + goto next; + } + + if (strcmp(id, "~") == 0) { + /* complement the set */ + if (which == AVRULE_DONTAUDIT) + yywarn("dontaudit rule with a ~?"); + cur_perms->data = ~cur_perms->data; + goto next; + } + + perdatum = + hashtab_search(cladatum->permissions.table, id); + if (!perdatum) { + if (cladatum->comdatum) { + perdatum = + hashtab_search(cladatum->comdatum-> + permissions.table, + id); + } + } + if (!perdatum) { + if (!suppress) + yyerror2("permission %s is not defined" + " for class %s", id, + policydbp->p_class_val_to_name[i]); + continue; + } else + if (!is_perm_in_scope + (id, policydbp->p_class_val_to_name[i])) { + if (!suppress) { + yyerror2("permission %s of class %s is" + " not within scope", id, + policydbp->p_class_val_to_name[i]); + } + continue; + } else { + cur_perms->data |= 1U << (perdatum->s.value - 1); + } + next: + cur_perms = cur_perms->next; + } + + free(id); + } + + ebitmap_destroy(&tclasses); + + avrule->perms = perms; + *rule = avrule; + + out: + return ret; + +} + +avrule_t *define_cond_te_avtab(int which) +{ + char *id; + avrule_t *avrule; + int i; + + if (pass == 1) { + for (i = 0; i < 4; i++) { + while ((id = queue_remove(id_queue))) + free(id); + } + return (avrule_t *) 1; /* any non-NULL value */ + } + + if (define_te_avtab_helper(which, &avrule)) + return COND_ERR; + + return avrule; +} + +int define_te_avtab(int which) +{ + char *id; + avrule_t *avrule; + int i; + + if (pass == 1) { + for (i = 0; i < 4; i++) { + while ((id = queue_remove(id_queue))) + free(id); + } + return 0; + } + + if (define_te_avtab_helper(which, &avrule)) + return -1; + + /* append this avrule to the end of the current rules list */ + append_avrule(avrule); + return 0; +} + +int define_role_types(void) +{ + role_datum_t *role; + char *id; + int add = 1; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + if ((role = declare_role()) == NULL) { + return -1; + } + while ((id = queue_remove(id_queue))) { + if (set_types(&role->types, id, &add, 0)) + return -1; + } + + return 0; +} + +role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2) +{ + role_datum_t *new; + + if (pass == 1) { + return (role_datum_t *) 1; /* any non-NULL value */ + } + + new = malloc(sizeof(role_datum_t)); + if (!new) { + yyerror("out of memory"); + return NULL; + } + memset(new, 0, sizeof(role_datum_t)); + new->s.value = 0; /* temporary role */ + if (ebitmap_or(&new->dominates, &r1->dominates, &r2->dominates)) { + yyerror("out of memory"); + return NULL; + } + if (ebitmap_or(&new->types.types, &r1->types.types, &r2->types.types)) { + yyerror("out of memory"); + return NULL; + } + if (!r1->s.value) { + /* free intermediate result */ + type_set_destroy(&r1->types); + ebitmap_destroy(&r1->dominates); + free(r1); + } + if (!r2->s.value) { + /* free intermediate result */ + yyerror("right hand role is temporary?"); + type_set_destroy(&r2->types); + ebitmap_destroy(&r2->dominates); + free(r2); + } + return new; +} + +/* This function eliminates the ordering dependency of role dominance rule */ +static int dominate_role_recheck(hashtab_key_t key, hashtab_datum_t datum, + void *arg) +{ + role_datum_t *rdp = (role_datum_t *) arg; + role_datum_t *rdatum = (role_datum_t *) datum; + ebitmap_node_t *node; + int i; + + /* Don't bother to process against self role */ + if (rdatum->s.value == rdp->s.value) + return 0; + + /* If a dominating role found */ + if (ebitmap_get_bit(&(rdatum->dominates), rdp->s.value - 1)) { + ebitmap_t types; + ebitmap_init(&types); + if (type_set_expand(&rdp->types, &types, policydbp, 1)) { + ebitmap_destroy(&types); + return -1; + } + /* raise types and dominates from dominated role */ + ebitmap_for_each_bit(&rdp->dominates, node, i) { + if (ebitmap_node_get_bit(node, i)) + if (ebitmap_set_bit + (&rdatum->dominates, i, TRUE)) + goto oom; + } + ebitmap_for_each_bit(&types, node, i) { + if (ebitmap_node_get_bit(node, i)) + if (ebitmap_set_bit + (&rdatum->types.types, i, TRUE)) + goto oom; + } + ebitmap_destroy(&types); + } + + /* go through all the roles */ + return 0; + oom: + yyerror("Out of memory"); + return -1; +} + +role_datum_t *define_role_dom(role_datum_t * r) +{ + role_datum_t *role; + char *role_id; + ebitmap_node_t *node; + unsigned int i; + int ret; + + if (pass == 1) { + role_id = queue_remove(id_queue); + free(role_id); + return (role_datum_t *) 1; /* any non-NULL value */ + } + + yywarn("Role dominance has been deprecated"); + + role_id = queue_remove(id_queue); + if (!is_id_in_scope(SYM_ROLES, role_id)) { + yyerror2("role %s is not within scope", role_id); + free(role_id); + return NULL; + } + role = (role_datum_t *) hashtab_search(policydbp->p_roles.table, + role_id); + if (!role) { + role = (role_datum_t *) malloc(sizeof(role_datum_t)); + if (!role) { + yyerror("out of memory"); + free(role_id); + return NULL; + } + memset(role, 0, sizeof(role_datum_t)); + ret = + declare_symbol(SYM_ROLES, (hashtab_key_t) role_id, + (hashtab_datum_t) role, &role->s.value, + &role->s.value); + switch (ret) { + case -3:{ + yyerror("Out of memory!"); + goto cleanup; + } + case -2:{ + yyerror2("duplicate declaration of role %s", + role_id); + goto cleanup; + } + case -1:{ + yyerror("could not declare role here"); + goto cleanup; + } + case 0: + case 1:{ + break; + } + default:{ + assert(0); /* should never get here */ + } + } + if (ebitmap_set_bit(&role->dominates, role->s.value - 1, TRUE)) { + yyerror("Out of memory!"); + goto cleanup; + } + } + if (r) { + ebitmap_t types; + ebitmap_init(&types); + ebitmap_for_each_bit(&r->dominates, node, i) { + if (ebitmap_node_get_bit(node, i)) + if (ebitmap_set_bit(&role->dominates, i, TRUE)) + goto oom; + } + if (type_set_expand(&r->types, &types, policydbp, 1)) { + ebitmap_destroy(&types); + return NULL; + } + ebitmap_for_each_bit(&types, node, i) { + if (ebitmap_node_get_bit(node, i)) + if (ebitmap_set_bit + (&role->types.types, i, TRUE)) + goto oom; + } + ebitmap_destroy(&types); + if (!r->s.value) { + /* free intermediate result */ + type_set_destroy(&r->types); + ebitmap_destroy(&r->dominates); + free(r); + } + /* + * Now go through all the roles and escalate this role's + * dominates and types if a role dominates this role. + */ + hashtab_map(policydbp->p_roles.table, + dominate_role_recheck, role); + } + return role; + cleanup: + free(role_id); + role_datum_destroy(role); + free(role); + return NULL; + oom: + yyerror("Out of memory"); + goto cleanup; +} + +static int role_val_to_name_helper(hashtab_key_t key, hashtab_datum_t datum, + void *p) +{ + struct val_to_name *v = p; + role_datum_t *roldatum; + + roldatum = (role_datum_t *) datum; + + if (v->val == roldatum->s.value) { + v->name = key; + return 1; + } + + return 0; +} + +static char *role_val_to_name(unsigned int val) +{ + struct val_to_name v; + int rc; + + v.val = val; + rc = hashtab_map(policydbp->p_roles.table, role_val_to_name_helper, &v); + if (rc) + return v.name; + return NULL; +} + +static int set_roles(role_set_t * set, char *id) +{ + role_datum_t *r; + + if (strcmp(id, "*") == 0) { + free(id); + yyerror("* is not allowed for role sets"); + return -1; + } + + if (strcmp(id, "~") == 0) { + free(id); + yyerror("~ is not allowed for role sets"); + return -1; + } + if (!is_id_in_scope(SYM_ROLES, id)) { + yyerror2("role %s is not within scope", id); + free(id); + return -1; + } + r = hashtab_search(policydbp->p_roles.table, id); + if (!r) { + yyerror2("unknown role %s", id); + free(id); + return -1; + } + + if (ebitmap_set_bit(&set->roles, r->s.value - 1, TRUE)) { + yyerror("out of memory"); + free(id); + return -1; + } + free(id); + return 0; +} + +int define_role_trans(void) +{ + char *id; + role_datum_t *role; + role_set_t roles; + type_set_t types; + ebitmap_t e_types, e_roles; + ebitmap_node_t *tnode, *rnode; + struct role_trans *tr = NULL; + struct role_trans_rule *rule = NULL; + unsigned int i, j; + int add = 1; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + id = queue_remove(id_queue); + free(id); + return 0; + } + + role_set_init(&roles); + ebitmap_init(&e_roles); + type_set_init(&types); + ebitmap_init(&e_types); + + while ((id = queue_remove(id_queue))) { + if (set_roles(&roles, id)) + return -1; + } + add = 1; + while ((id = queue_remove(id_queue))) { + if (set_types(&types, id, &add, 0)) + return -1; + } + + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("no new role in transition definition?"); + goto bad; + } + if (!is_id_in_scope(SYM_ROLES, id)) { + yyerror2("role %s is not within scope", id); + free(id); + goto bad; + } + role = hashtab_search(policydbp->p_roles.table, id); + if (!role) { + yyerror2("unknown role %s used in transition definition", id); + goto bad; + } + + /* This ebitmap business is just to ensure that there are not conflicting role_trans rules */ + if (role_set_expand(&roles, &e_roles, policydbp)) + goto bad; + + if (type_set_expand(&types, &e_types, policydbp, 1)) + goto bad; + + ebitmap_for_each_bit(&e_roles, rnode, i) { + if (!ebitmap_node_get_bit(rnode, i)) + continue; + ebitmap_for_each_bit(&e_types, tnode, j) { + if (!ebitmap_node_get_bit(tnode, j)) + continue; + + for (tr = policydbp->role_tr; tr; tr = tr->next) { + if (tr->role == (i + 1) && tr->type == (j + 1)) { + yyerror2("duplicate role transition for (%s,%s)", + role_val_to_name(i + 1), + policydbp->p_type_val_to_name[j]); + goto bad; + } + } + + tr = malloc(sizeof(struct role_trans)); + if (!tr) { + yyerror("out of memory"); + return -1; + } + memset(tr, 0, sizeof(struct role_trans)); + tr->role = i + 1; + tr->type = j + 1; + tr->new_role = role->s.value; + tr->next = policydbp->role_tr; + policydbp->role_tr = tr; + } + } + /* Now add the real rule */ + rule = malloc(sizeof(struct role_trans_rule)); + if (!rule) { + yyerror("out of memory"); + return -1; + } + memset(rule, 0, sizeof(struct role_trans_rule)); + rule->roles = roles; + rule->types = types; + rule->new_role = role->s.value; + + append_role_trans(rule); + + ebitmap_destroy(&e_roles); + ebitmap_destroy(&e_types); + + return 0; + + bad: + return -1; +} + +int define_role_allow(void) +{ + char *id; + struct role_allow_rule *ra = 0; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + ra = malloc(sizeof(role_allow_rule_t)); + if (!ra) { + yyerror("out of memory"); + return -1; + } + role_allow_rule_init(ra); + + while ((id = queue_remove(id_queue))) { + if (set_roles(&ra->roles, id)) + return -1; + } + + while ((id = queue_remove(id_queue))) { + if (set_roles(&ra->new_roles, id)) + return -1; + } + + append_role_allow(ra); + return 0; +} + +static constraint_expr_t *constraint_expr_clone(constraint_expr_t * expr) +{ + constraint_expr_t *h = NULL, *l = NULL, *e, *newe; + for (e = expr; e; e = e->next) { + newe = malloc(sizeof(*newe)); + if (!newe) + goto oom; + if (constraint_expr_init(newe) == -1) { + free(newe); + goto oom; + } + if (l) + l->next = newe; + else + h = newe; + l = newe; + newe->expr_type = e->expr_type; + newe->attr = e->attr; + newe->op = e->op; + if (newe->expr_type == CEXPR_NAMES) { + if (newe->attr & CEXPR_TYPE) { + if (type_set_cpy + (newe->type_names, e->type_names)) + goto oom; + } else { + if (ebitmap_cpy(&newe->names, &e->names)) + goto oom; + } + } + } + + return h; + oom: + e = h; + while (e) { + l = e; + e = e->next; + constraint_expr_destroy(l); + } + return NULL; +} + +int define_constraint(constraint_expr_t * expr) +{ + struct constraint_node *node; + char *id; + class_datum_t *cladatum; + perm_datum_t *perdatum; + ebitmap_t classmap; + ebitmap_node_t *enode; + constraint_expr_t *e; + unsigned int i; + int depth; + unsigned char useexpr = 1; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + depth = -1; + for (e = expr; e; e = e->next) { + switch (e->expr_type) { + case CEXPR_NOT: + if (depth < 0) { + yyerror("illegal constraint expression"); + return -1; + } + break; + case CEXPR_AND: + case CEXPR_OR: + if (depth < 1) { + yyerror("illegal constraint expression"); + return -1; + } + depth--; + break; + case CEXPR_ATTR: + case CEXPR_NAMES: + if (e->attr & CEXPR_XTARGET) { + yyerror("illegal constraint expression"); + return -1; /* only for validatetrans rules */ + } + if (depth == (CEXPR_MAXDEPTH - 1)) { + yyerror("constraint expression is too deep"); + return -1; + } + depth++; + break; + default: + yyerror("illegal constraint expression"); + return -1; + } + } + if (depth != 0) { + yyerror("illegal constraint expression"); + return -1; + } + + ebitmap_init(&classmap); + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); + free(id); + return -1; + } + cladatum = + (class_datum_t *) hashtab_search(policydbp->p_classes.table, + (hashtab_key_t) id); + if (!cladatum) { + yyerror2("class %s is not defined", id); + ebitmap_destroy(&classmap); + free(id); + return -1; + } + if (ebitmap_set_bit(&classmap, cladatum->s.value - 1, TRUE)) { + yyerror("out of memory"); + ebitmap_destroy(&classmap); + free(id); + return -1; + } + node = malloc(sizeof(struct constraint_node)); + if (!node) { + yyerror("out of memory"); + return -1; + } + memset(node, 0, sizeof(constraint_node_t)); + if (useexpr) { + node->expr = expr; + useexpr = 0; + } else { + node->expr = constraint_expr_clone(expr); + } + if (!node->expr) { + yyerror("out of memory"); + return -1; + } + node->permissions = 0; + + node->next = cladatum->constraints; + cladatum->constraints = node; + + free(id); + } + + while ((id = queue_remove(id_queue))) { + ebitmap_for_each_bit(&classmap, enode, i) { + if (ebitmap_node_get_bit(enode, i)) { + cladatum = policydbp->class_val_to_struct[i]; + node = cladatum->constraints; + + perdatum = + (perm_datum_t *) hashtab_search(cladatum-> + permissions. + table, + (hashtab_key_t) + id); + if (!perdatum) { + if (cladatum->comdatum) { + perdatum = + (perm_datum_t *) + hashtab_search(cladatum-> + comdatum-> + permissions. + table, + (hashtab_key_t) + id); + } + if (!perdatum) { + yyerror2("permission %s is not" + " defined", id); + free(id); + ebitmap_destroy(&classmap); + return -1; + } + } + node->permissions |= + (1 << (perdatum->s.value - 1)); + } + } + free(id); + } + + ebitmap_destroy(&classmap); + + return 0; +} + +int define_validatetrans(constraint_expr_t * expr) +{ + struct constraint_node *node; + char *id; + class_datum_t *cladatum; + ebitmap_t classmap; + constraint_expr_t *e; + int depth; + unsigned char useexpr = 1; + + if (pass == 1) { + while ((id = queue_remove(id_queue))) + free(id); + return 0; + } + + depth = -1; + for (e = expr; e; e = e->next) { + switch (e->expr_type) { + case CEXPR_NOT: + if (depth < 0) { + yyerror("illegal validatetrans expression"); + return -1; + } + break; + case CEXPR_AND: + case CEXPR_OR: + if (depth < 1) { + yyerror("illegal validatetrans expression"); + return -1; + } + depth--; + break; + case CEXPR_ATTR: + case CEXPR_NAMES: + if (depth == (CEXPR_MAXDEPTH - 1)) { + yyerror("validatetrans expression is too deep"); + return -1; + } + depth++; + break; + default: + yyerror("illegal validatetrans expression"); + return -1; + } + } + if (depth != 0) { + yyerror("illegal validatetrans expression"); + return -1; + } + + ebitmap_init(&classmap); + while ((id = queue_remove(id_queue))) { + if (!is_id_in_scope(SYM_CLASSES, id)) { + yyerror2("class %s is not within scope", id); + free(id); + return -1; + } + cladatum = + (class_datum_t *) hashtab_search(policydbp->p_classes.table, + (hashtab_key_t) id); + if (!cladatum) { + yyerror2("class %s is not defined", id); + ebitmap_destroy(&classmap); + free(id); + return -1; + } + if (ebitmap_set_bit(&classmap, (cladatum->s.value - 1), TRUE)) { + yyerror("out of memory"); + ebitmap_destroy(&classmap); + free(id); + return -1; + } + + node = malloc(sizeof(struct constraint_node)); + if (!node) { + yyerror("out of memory"); + return -1; + } + memset(node, 0, sizeof(constraint_node_t)); + if (useexpr) { + node->expr = expr; + useexpr = 0; + } else { + node->expr = constraint_expr_clone(expr); + } + node->permissions = 0; + + node->next = cladatum->validatetrans; + cladatum->validatetrans = node; + + free(id); + } + + ebitmap_destroy(&classmap); + + return 0; +} + +uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) +{ + struct constraint_expr *expr, *e1 = NULL, *e2; + user_datum_t *user; + role_datum_t *role; + ebitmap_t negset; + char *id; + uint32_t val; + int add = 1; + + if (pass == 1) { + if (expr_type == CEXPR_NAMES) { + while ((id = queue_remove(id_queue))) + free(id); + } + return 1; /* any non-NULL value */ + } + + if ((expr = malloc(sizeof(*expr))) == NULL || + constraint_expr_init(expr) == -1) { + yyerror("out of memory"); + free(expr); + return 0; + } + expr->expr_type = expr_type; + + switch (expr_type) { + case CEXPR_NOT: + e1 = NULL; + e2 = (struct constraint_expr *)arg1; + while (e2) { + e1 = e2; + e2 = e2->next; + } + if (!e1 || e1->next) { + yyerror("illegal constraint expression"); + constraint_expr_destroy(expr); + return 0; + } + e1->next = expr; + return arg1; + case CEXPR_AND: + case CEXPR_OR: + e1 = NULL; + e2 = (struct constraint_expr *)arg1; + while (e2) { + e1 = e2; + e2 = e2->next; + } + if (!e1 || e1->next) { + yyerror("illegal constraint expression"); + constraint_expr_destroy(expr); + return 0; + } + e1->next = (struct constraint_expr *)arg2; + + e1 = NULL; + e2 = (struct constraint_expr *)arg2; + while (e2) { + e1 = e2; + e2 = e2->next; + } + if (!e1 || e1->next) { + yyerror("illegal constraint expression"); + constraint_expr_destroy(expr); + return 0; + } + e1->next = expr; + return arg1; + case CEXPR_ATTR: + expr->attr = arg1; + expr->op = arg2; + return (uintptr_t) expr; + case CEXPR_NAMES: + add = 1; + expr->attr = arg1; + expr->op = arg2; + ebitmap_init(&negset); + while ((id = (char *)queue_remove(id_queue))) { + if (expr->attr & CEXPR_USER) { + if (!is_id_in_scope(SYM_USERS, id)) { + yyerror2("user %s is not within scope", + id); + constraint_expr_destroy(expr); + return 0; + } + user = + (user_datum_t *) hashtab_search(policydbp-> + p_users. + table, + (hashtab_key_t) + id); + if (!user) { + yyerror2("unknown user %s", id); + constraint_expr_destroy(expr); + return 0; + } + val = user->s.value; + } else if (expr->attr & CEXPR_ROLE) { + if (!is_id_in_scope(SYM_ROLES, id)) { + yyerror2("role %s is not within scope", + id); + constraint_expr_destroy(expr); + return 0; + } + role = + (role_datum_t *) hashtab_search(policydbp-> + p_roles. + table, + (hashtab_key_t) + id); + if (!role) { + yyerror2("unknown role %s", id); + constraint_expr_destroy(expr); + return 0; + } + val = role->s.value; + } else if (expr->attr & CEXPR_TYPE) { + if (set_types(expr->type_names, id, &add, 0)) { + constraint_expr_destroy(expr); + return 0; + } + continue; + } else { + yyerror("invalid constraint expression"); + constraint_expr_destroy(expr); + return 0; + } + if (ebitmap_set_bit(&expr->names, val - 1, TRUE)) { + yyerror("out of memory"); + ebitmap_destroy(&expr->names); + constraint_expr_destroy(expr); + return 0; + } + free(id); + } + ebitmap_destroy(&negset); + return (uintptr_t) expr; + default: + yyerror("invalid constraint expression"); + constraint_expr_destroy(expr); + return 0; + } + + yyerror("invalid constraint expression"); + free(expr); + return 0; +} + +int define_conditional(cond_expr_t * expr, avrule_t * t, avrule_t * f) +{ + cond_expr_t *e; + int depth; + cond_node_t cn, *cn_old; + + /* expression cannot be NULL */ + if (!expr) { + yyerror("illegal conditional expression"); + return -1; + } + if (!t) { + if (!f) { + /* empty is fine, destroy expression and return */ + cond_expr_destroy(expr); + return 0; + } + /* Invert */ + t = f; + f = 0; + expr = define_cond_expr(COND_NOT, expr, 0); + if (!expr) { + yyerror("unable to invert"); + return -1; + } + } + + /* verify expression */ + depth = -1; + for (e = expr; e; e = e->next) { + switch (e->expr_type) { + case COND_NOT: + if (depth < 0) { + yyerror + ("illegal conditional expression; Bad NOT"); + return -1; + } + break; + case COND_AND: + case COND_OR: + case COND_XOR: + case COND_EQ: + case COND_NEQ: + if (depth < 1) { + yyerror + ("illegal conditional expression; Bad binary op"); + return -1; + } + depth--; + break; + case COND_BOOL: + if (depth == (COND_EXPR_MAXDEPTH - 1)) { + yyerror + ("conditional expression is like totally too deep"); + return -1; + } + depth++; + break; + default: + yyerror("illegal conditional expression"); + return -1; + } + } + if (depth != 0) { + yyerror("illegal conditional expression"); + return -1; + } + + /* use tmp conditional node to partially build new node */ + memset(&cn, 0, sizeof(cn)); + cn.expr = expr; + cn.avtrue_list = t; + cn.avfalse_list = f; + + /* normalize/precompute expression */ + if (cond_normalize_expr(policydbp, &cn) < 0) { + yyerror("problem normalizing conditional expression"); + return -1; + } + + /* get the existing conditional node, or create a new one */ + cn_old = get_current_cond_list(&cn); + if (!cn_old) { + return -1; + } + + append_cond_list(&cn); + + /* note that there is no check here for duplicate rules, nor + * check that rule already exists in base -- that will be + * handled during conditional expansion, in expand.c */ + + cn.avtrue_list = NULL; + cn.avfalse_list = NULL; + cond_node_destroy(&cn); + + return 0; +} + +cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void *arg2) +{ + struct cond_expr *expr, *e1 = NULL, *e2; + cond_bool_datum_t *bool_var; + char *id; + + /* expressions are handled in the second pass */ + if (pass == 1) { + if (expr_type == COND_BOOL) { + while ((id = queue_remove(id_queue))) { + free(id); + } + } + return (cond_expr_t *) 1; /* any non-NULL value */ + } + + /* create a new expression struct */ + expr = malloc(sizeof(struct cond_expr)); + if (!expr) { + yyerror("out of memory"); + return NULL; + } + memset(expr, 0, sizeof(cond_expr_t)); + expr->expr_type = expr_type; + + /* create the type asked for */ + switch (expr_type) { + case COND_NOT: + e1 = NULL; + e2 = (struct cond_expr *)arg1; + while (e2) { + e1 = e2; + e2 = e2->next; + } + if (!e1 || e1->next) { + yyerror("illegal conditional NOT expression"); + free(expr); + return NULL; + } + e1->next = expr; + return (struct cond_expr *)arg1; + case COND_AND: + case COND_OR: + case COND_XOR: + case COND_EQ: + case COND_NEQ: + e1 = NULL; + e2 = (struct cond_expr *)arg1; + while (e2) { + e1 = e2; + e2 = e2->next; + } + if (!e1 || e1->next) { + yyerror + ("illegal left side of conditional binary op expression"); + free(expr); + return NULL; + } + e1->next = (struct cond_expr *)arg2; + + e1 = NULL; + e2 = (struct cond_expr *)arg2; + while (e2) { + e1 = e2; + e2 = e2->next; + } + if (!e1 || e1->next) { + yyerror + ("illegal right side of conditional binary op expression"); + free(expr); + return NULL; + } + e1->next = expr; + return (struct cond_expr *)arg1; + case COND_BOOL: + id = (char *)queue_remove(id_queue); + if (!id) { + yyerror("bad conditional; expected boolean id"); + free(id); + free(expr); + return NULL; + } + if (!is_id_in_scope(SYM_BOOLS, id)) { + yyerror2("boolean %s is not within scope", id); + free(id); + free(expr); + return NULL; + } + bool_var = + (cond_bool_datum_t *) hashtab_search(policydbp->p_bools. + table, + (hashtab_key_t) id); + if (!bool_var) { + yyerror2("unknown boolean %s in conditional expression", + id); + free(expr); + free(id); + return NULL; + } + expr->bool = bool_var->s.value; + free(id); + return expr; + default: + yyerror("illegal conditional expression"); + return NULL; + } +} + +static int set_user_roles(role_set_t * set, char *id) +{ + role_datum_t *r; + unsigned int i; + ebitmap_node_t *node; + + if (strcmp(id, "*") == 0) { + free(id); + yyerror("* is not allowed in user declarations"); + return -1; + } + + if (strcmp(id, "~") == 0) { + free(id); + yyerror("~ is not allowed in user declarations"); + return -1; + } + + if (!is_id_in_scope(SYM_ROLES, id)) { + yyerror2("role %s is not within scope", id); + free(id); + return -1; + } + r = hashtab_search(policydbp->p_roles.table, id); + if (!r) { + yyerror2("unknown role %s", id); + free(id); + return -1; + } + + /* set the role and every role it dominates */ + ebitmap_for_each_bit(&r->dominates, node, i) { + if (ebitmap_node_get_bit(node, i)) + if (ebitmap_set_bit(&set->roles, i, TRUE)) + goto oom; + } + free(id); + return 0; + oom: + yyerror("out of memory"); + return -1; +} + +static int parse_categories(char *id, level_datum_t * levdatum, ebitmap_t * cats) +{ + cat_datum_t *cdatum; + int range_start, range_end, i; + + if (id_has_dot(id)) { + char *id_start = id; + char *id_end = strchr(id, '.'); + + *(id_end++) = '\0'; + + cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, + (hashtab_key_t) + id_start); + if (!cdatum) { + yyerror2("unknown category %s", id_start); + return -1; + } + range_start = cdatum->s.value - 1; + cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, ... [truncated message content] |