diff --git a/.gitignore b/.gitignore index a084e8f..e0e8a8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/libsepol-2.1.9.tgz +SOURCES/libsepol-2.5.tar.gz diff --git a/.libsepol.metadata b/.libsepol.metadata index c6a3a67..da98e06 100644 --- a/.libsepol.metadata +++ b/.libsepol.metadata @@ -1 +1 @@ -5ca22f919652958cbcd3e026048ea831ea54de47 SOURCES/libsepol-2.1.9.tgz +c232813ccba82eae32107228f73cf279bf02c353 SOURCES/libsepol-2.5.tar.gz diff --git a/SOURCES/libsepol-rhat.patch b/SOURCES/libsepol-rhat.patch deleted file mode 100644 index 552c827..0000000 --- a/SOURCES/libsepol-rhat.patch +++ /dev/null @@ -1,1118 +0,0 @@ -diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h -index c27275e..0165eed 100644 ---- a/libsepol/include/sepol/policydb/policydb.h -+++ b/libsepol/include/sepol/policydb/policydb.h -@@ -683,10 +683,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); - #define POLICYDB_VERSION_ROLETRANS 26 - #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 - #define POLICYDB_VERSION_DEFAULT_TYPE 28 -+#define POLICYDB_VERSION_CONSTRAINT_NAMES 29 - - /* Range of policy versions we understand*/ - #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE --#define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE -+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES - - /* Module versions and specific changes*/ - #define MOD_POLICYDB_VERSION_BASE 4 -@@ -704,9 +705,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); - #define MOD_POLICYDB_VERSION_TUNABLE_SEP 14 - #define MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 15 - #define MOD_POLICYDB_VERSION_DEFAULT_TYPE 16 -+#define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES 17 - - #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE --#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_DEFAULT_TYPE -+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_CONSTRAINT_NAMES - - #define POLICYDB_CONFIG_MLS 1 - -diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h -index aef0c7b..1969a10 100644 ---- a/libsepol/include/sepol/policydb/services.h -+++ b/libsepol/include/sepol/policydb/services.h -@@ -58,6 +58,38 @@ extern int sepol_compute_av_reason(sepol_security_id_t ssid, - struct sepol_av_decision *avd, - unsigned int *reason); - -+/* -+ * Same as above, but also returns the constraint expression calculations -+ * whether allowed or denied in a buffer. This buffer is allocated by -+ * this call and must be free'd by the caller using free(3). The contraint -+ * buffer will contain any constraints in infix notation. -+ * If the SHOW_GRANTED flag is set it will show granted and denied -+ * constraints. The default is to show only denied constraints. -+ */ -+#define SHOW_GRANTED 1 -+extern int sepol_compute_av_reason_buffer(sepol_security_id_t ssid, -+ sepol_security_id_t tsid, -+ sepol_security_class_t tclass, -+ sepol_access_vector_t requested, -+ struct sepol_av_decision *avd, -+ unsigned int *reason, -+ char **reason_buf, -+ unsigned int flags); -+/* -+ * Return a class ID associated with the class string representation -+ * specified by `class_name'. -+ */ -+extern int sepol_class_name_to_id(const char *class_name, -+ sepol_security_class_t *tclass); -+ -+/* -+ * Return a permission av bit associated with tclass and the string -+ * representation of the `perm_name'. -+ */ -+extern int sepol_perm_name_to_av(sepol_security_class_t tclass, -+ const char *perm_name, -+ sepol_access_vector_t *av); -+ - /* - * Compute a SID to use for labeling a new object in the - * class `tclass' based on a SID pair. -diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c -index f0555bb..6fd992f 100644 ---- a/libsepol/src/expand.c -+++ b/libsepol/src/expand.c -@@ -384,6 +384,17 @@ static int constraint_node_clone(constraint_node_t ** dst, - new_expr->op = expr->op; - if (new_expr->expr_type == CEXPR_NAMES) { - if (new_expr->attr & CEXPR_TYPE) { -+ /* -+ * Copy over constraint policy source types and/or -+ * attributes for sepol_compute_av_reason_buffer(3) so that -+ * utilities can analyse constraint errors. -+ */ -+ if (map_ebitmap(&expr->type_names->types, -+ &new_expr->type_names->types, -+ state->typemap)) { -+ ERR(NULL, "Failed to map type_names->types"); -+ goto out_of_mem; -+ } - /* Type sets require expansion and conversion. */ - if (expand_convert_type_set(state->out, - state-> -diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c -index 1f49261..8c7efbc 100644 ---- a/libsepol/src/policydb.c -+++ b/libsepol/src/policydb.c -@@ -165,6 +165,13 @@ static struct policydb_compat_info policydb_compat[] = { - .target_platform = SEPOL_TARGET_SELINUX, - }, - { -+ .type = POLICY_KERN, -+ .version = POLICYDB_VERSION_CONSTRAINT_NAMES, -+ .sym_num = SYM_NUM, -+ .ocon_num = OCON_NODE6 + 1, -+ .target_platform = SEPOL_TARGET_SELINUX, -+ }, -+ { - .type = POLICY_BASE, - .version = MOD_POLICYDB_VERSION_BASE, - .sym_num = SYM_NUM, -@@ -256,6 +263,13 @@ static struct policydb_compat_info policydb_compat[] = { - .target_platform = SEPOL_TARGET_SELINUX, - }, - { -+ .type = POLICY_BASE, -+ .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES, -+ .sym_num = SYM_NUM, -+ .ocon_num = OCON_NODE6 + 1, -+ .target_platform = SEPOL_TARGET_SELINUX, -+ }, -+ { - .type = POLICY_MOD, - .version = MOD_POLICYDB_VERSION_BASE, - .sym_num = SYM_NUM, -@@ -346,6 +360,13 @@ static struct policydb_compat_info policydb_compat[] = { - .ocon_num = 0, - .target_platform = SEPOL_TARGET_SELINUX, - }, -+ { -+ .type = POLICY_MOD, -+ .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES, -+ .sym_num = SYM_NUM, -+ .ocon_num = 0, -+ .target_platform = SEPOL_TARGET_SELINUX, -+ }, - }; - - #if 0 -@@ -2019,6 +2040,10 @@ static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep, - if (p->policy_type != POLICY_KERN && - type_set_read(e->type_names, fp)) - return -1; -+ else if (p->policy_type == POLICY_KERN && -+ p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES && -+ type_set_read(e->type_names, fp)) -+ return -1; - break; - default: - return -1; -diff --git a/libsepol/src/services.c b/libsepol/src/services.c -index 7fac4a0..43ec07e 100644 ---- a/libsepol/src/services.c -+++ b/libsepol/src/services.c -@@ -43,6 +43,11 @@ - * Implementation of the security services. - */ - -+/* The initial sizes malloc'd for sepol_compute_av_reason_buffer() support */ -+#define REASON_BUF_SIZE 2048 -+#define EXPR_BUF_SIZE 1024 -+#define STACK_LEN 32 -+ - #include - #include - #include -@@ -54,6 +59,7 @@ - #include - #include - #include -+#include - - #include "debug.h" - #include "private.h" -@@ -70,6 +76,50 @@ static int selinux_enforcing = 1; - static sidtab_t mysidtab, *sidtab = &mysidtab; - static policydb_t mypolicydb, *policydb = &mypolicydb; - -+/* Used by sepol_compute_av_reason_buffer() to keep track of entries */ -+static int reason_buf_used; -+static int reason_buf_len; -+ -+/* Stack services for RPN to infix conversion. */ -+static char **stack; -+static int stack_len; -+static int next_stack_entry; -+ -+static void push(char * expr_ptr) -+{ -+ if (next_stack_entry >= stack_len) { -+ char **new_stack = stack; -+ int new_stack_len; -+ -+ if (stack_len == 0) -+ new_stack_len = STACK_LEN; -+ else -+ new_stack_len = stack_len * 2; -+ -+ new_stack = realloc(stack, new_stack_len * sizeof(*stack)); -+ if (!new_stack) { -+ ERR(NULL, "unable to allocate stack space"); -+ return; -+ } -+ stack_len = new_stack_len; -+ stack = new_stack; -+ } -+ stack[next_stack_entry] = expr_ptr; -+ next_stack_entry++; -+} -+ -+static char *pop(void) -+{ -+ next_stack_entry--; -+ if (next_stack_entry < 0) { -+ next_stack_entry = 0; -+ ERR(NULL, "pop called with no stack entries"); -+ return NULL; -+ } -+ return stack[next_stack_entry]; -+} -+/* End Stack services */ -+ - int hidden sepol_set_sidtab(sidtab_t * s) - { - sidtab = s; -@@ -113,20 +163,195 @@ int sepol_set_policydb_from_file(FILE * fp) - static uint32_t latest_granting = 0; - - /* -- * Return the boolean value of a constraint expression -- * when it is applied to the specified source and target -+ * cat_expr_buf adds a string to an expression buffer and handles realloc's if -+ * buffer is too small. The array of expression text buffer pointers and its -+ * counter are globally defined here as constraint_expr_eval_reason() sets -+ * them up and cat_expr_buf updates the e_buf pointer if the buffer is realloc'ed. -+ */ -+static int expr_counter; -+static char **expr_list; -+static int expr_buf_used; -+static int expr_buf_len; -+ -+static void cat_expr_buf(char *e_buf, char *string) -+{ -+ int len, new_buf_len; -+ char *p, *new_buf = e_buf; -+ -+ while (1) { -+ p = e_buf + expr_buf_used; -+ len = snprintf(p, expr_buf_len - expr_buf_used, "%s", string); -+ if (len < 0 || len >= expr_buf_len - expr_buf_used) { -+ new_buf_len = expr_buf_len + EXPR_BUF_SIZE; -+ new_buf = realloc(e_buf, new_buf_len); -+ if (!new_buf) { -+ ERR(NULL, "failed to realloc expr buffer"); -+ return; -+ } -+ /* Update the new ptr in the expr list and locally + new len */ -+ expr_list[expr_counter] = new_buf; -+ e_buf = new_buf; -+ expr_buf_len = new_buf_len; -+ } else { -+ expr_buf_used += len; -+ return; -+ } -+ } -+} -+ -+/* -+ * If the POLICY_KERN version is < POLICYDB_VERSION_CONSTRAINT_NAMES, -+ * then just return. -+ * -+ * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES, -+ * then for 'types' only, read the types_names->types list as it will -+ * contain a list of types and attributes that were defined in the -+ * policy source. -+ */ -+static void get_names_list(constraint_expr_t *e, int type) -+{ -+ ebitmap_t *types; -+ types = &e->type_names->types; -+ int rc = 0; -+ unsigned int i; -+ char tmp_buf[128]; -+ /* if -type_names->types is 0, then output string */ -+ int empty_set = 0; -+ -+ if (policydb->policy_type == POLICY_KERN && -+ policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES && -+ type == CEXPR_TYPE) { -+ /* -+ * Process >= POLICYDB_VERSION_CONSTRAINT_NAMES with CEXPR_TYPE, then -+ * obtain the list of names defined in the policy source. -+ */ -+ cat_expr_buf(expr_list[expr_counter], "{ POLICY_SOURCE: "); -+ for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) { -+ if ((rc = ebitmap_get_bit(types, i)) == 0) -+ continue; -+ /* Collect entries */ -+ snprintf(tmp_buf, sizeof(tmp_buf), "%s ", policydb->p_type_val_to_name[i]); -+ cat_expr_buf(expr_list[expr_counter], tmp_buf); -+ empty_set++; -+ } -+ if (empty_set == 0) -+ cat_expr_buf(expr_list[expr_counter], " "); -+ cat_expr_buf(expr_list[expr_counter], "} "); -+ } -+ return; -+} -+ -+static void msgcat(char *src, char *tgt, char *rel, int failed) -+{ -+ char tmp_buf[1024]; -+ if (failed) -+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ", -+ src, rel, tgt); -+ else -+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Pass-) ", -+ src, rel, tgt); -+ cat_expr_buf(expr_list[expr_counter], tmp_buf); -+} -+ -+/* Returns a buffer with class, statement type and permissions */ -+static char *get_class_info(sepol_security_class_t tclass, -+ constraint_node_t *constraint, -+ context_struct_t * xcontext) -+{ -+ constraint_expr_t *e; -+ int mls, state_num; -+ -+ /* Find if MLS statement or not */ -+ mls = 0; -+ for (e = constraint->expr; e; e = e->next) { -+ if (e->attr >= CEXPR_L1L2) { -+ mls = 1; -+ break; -+ } -+ } -+ -+ /* Determine statement type */ -+ char *statements[] = { -+ "constrain ", /* 0 */ -+ "mlsconstrain ", /* 1 */ -+ "validatetrans ", /* 2 */ -+ "mlsvalidatetrans ", /* 3 */ -+ 0 }; -+ -+ if (xcontext == NULL) -+ state_num = mls + 0; -+ else -+ state_num = mls + 2; -+ -+ int class_buf_len = 0; -+ int new_class_buf_len; -+ int len, buf_used; -+ char *class_buf = NULL, *p; -+ char *new_class_buf = NULL; -+ -+ while (1) { -+ new_class_buf_len = class_buf_len + EXPR_BUF_SIZE; -+ new_class_buf = realloc(class_buf, new_class_buf_len); -+ if (!new_class_buf) -+ return NULL; -+ class_buf_len = new_class_buf_len; -+ class_buf = new_class_buf; -+ buf_used = 0; -+ p = class_buf; -+ -+ /* Add statement type */ -+ len = snprintf(p, class_buf_len - buf_used, "%s", statements[state_num]); -+ if (len < 0 || len >= class_buf_len - buf_used) -+ continue; -+ -+ /* Add class entry */ -+ p += len; -+ buf_used += len; -+ len = snprintf(p, class_buf_len - buf_used, "%s ", -+ policydb->p_class_val_to_name[tclass - 1]); -+ if (len < 0 || len >= class_buf_len - buf_used) -+ continue; -+ -+ /* Add permission entries */ -+ p += len; -+ buf_used += len; -+ len = snprintf(p, class_buf_len - buf_used, "{%s } (", -+ sepol_av_to_string(policydb, tclass, constraint->permissions)); -+ if (len < 0 || len >= class_buf_len - buf_used) -+ continue; -+ break; -+ } -+ return class_buf; -+} -+ -+/* -+ * Modified version of constraint_expr_eval that will process each -+ * constraint as before but adds the information to text buffers that -+ * will hold various components. The expression will be in RPN format, -+ * therefore there is a stack based RPN to infix converter to produce -+ * the final readable constraint. -+ * -+ * Return the boolean value of a constraint expression -+ * when it is applied to the specified source and target - * security contexts. - * - * xcontext is a special beast... It is used by the validatetrans rules - * only. For these rules, scontext is the context before the transition, - * tcontext is the context after the transition, and xcontext is the context - * of the process performing the transition. All other callers of -- * constraint_expr_eval should pass in NULL for xcontext. -+ * constraint_expr_eval_reason should pass in NULL for xcontext. -+ * -+ * This function will also build a buffer as the constraint is processed -+ * for analysis. If this option is not required, then: -+ * 'tclass' should be '0' and r_buf MUST be NULL. - */ --static int constraint_expr_eval(context_struct_t * scontext, -+static int constraint_expr_eval_reason(context_struct_t * scontext, - context_struct_t * tcontext, - context_struct_t * xcontext, -- constraint_expr_t * cexpr) -+ sepol_security_class_t tclass, -+ constraint_node_t *constraint, -+ char **r_buf, -+ unsigned int flags) - { - uint32_t val1, val2; - context_struct_t *c; -@@ -136,56 +361,137 @@ static int constraint_expr_eval(context_struct_t * scontext, - int s[CEXPR_MAXDEPTH]; - int sp = -1; - -- for (e = cexpr; e; e = e->next) { -+ char tmp_buf[128]; -+ -+/* -+ * Define the s_t_x_num values that make up r1, t2 etc. in text strings -+ * Set 1 = source, 2 = target, 3 = xcontext for validatetrans -+ */ -+#define SOURCE 1 -+#define TARGET 2 -+#define XTARGET 3 -+ -+ int s_t_x_num = SOURCE; -+ -+ /* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */ -+ int u_r_t = 0; -+ -+ char *name1, *name2; -+ char *src = NULL; -+ char *tgt = NULL; -+ -+ int rc = 0, x; -+ -+ char *class_buf = NULL; -+ -+ class_buf = get_class_info(tclass, constraint, xcontext); -+ if (!class_buf) { -+ ERR(NULL, "failed to allocate class buffer"); -+ return -ENOMEM; -+ } -+ -+ /* Original function but with buffer support */ -+ int expr_list_len = 0; -+ expr_counter = 0; -+ expr_list = NULL; -+ for (e = constraint->expr; e; e = e->next) { -+ /* Allocate a stack to hold expression buffer entries */ -+ if (expr_counter >= expr_list_len) { -+ char **new_expr_list = expr_list; -+ int new_expr_list_len; -+ -+ if (expr_list_len == 0) -+ new_expr_list_len = STACK_LEN; -+ else -+ new_expr_list_len = expr_list_len * 2; -+ -+ new_expr_list = realloc(expr_list, new_expr_list_len * sizeof(*expr_list)); -+ if (!new_expr_list) { -+ ERR(NULL, "failed to allocate expr buffer stack"); -+ rc = -ENOMEM; -+ goto out; -+ } -+ expr_list_len = new_expr_list_len; -+ expr_list = new_expr_list; -+ } -+ -+ /* -+ * malloc a buffer to store each expression text component. If the -+ * buffer is too small cat_expr_buf() will realloc extra space. -+ */ -+ expr_buf_len = EXPR_BUF_SIZE; -+ expr_list[expr_counter] = malloc(expr_buf_len); -+ if (!expr_list[expr_counter]) { -+ ERR(NULL, "failed to allocate expr buffer"); -+ rc = -ENOMEM; -+ goto out; -+ } -+ expr_buf_used = 0; -+ -+ /* Now process each expression of the constraint */ - switch (e->expr_type) { - case CEXPR_NOT: - BUG_ON(sp < 0); - s[sp] = !s[sp]; -+ cat_expr_buf(expr_list[expr_counter], "not"); - break; - case CEXPR_AND: - BUG_ON(sp < 1); - sp--; - s[sp] &= s[sp + 1]; -+ cat_expr_buf(expr_list[expr_counter], "and"); - break; - case CEXPR_OR: - BUG_ON(sp < 1); - sp--; - s[sp] |= s[sp + 1]; -+ cat_expr_buf(expr_list[expr_counter], "or"); - break; - case CEXPR_ATTR: - if (sp == (CEXPR_MAXDEPTH - 1)) -- return 0; -+ goto out; -+ - switch (e->attr) { - case CEXPR_USER: - val1 = scontext->user; - val2 = tcontext->user; -+ free(src); src = strdup("u1"); -+ free(tgt); tgt = strdup("u2"); - break; - case CEXPR_TYPE: - val1 = scontext->type; - val2 = tcontext->type; -+ free(src); src = strdup("t1"); -+ free(tgt); tgt = strdup("t2"); - break; - case CEXPR_ROLE: - val1 = scontext->role; - val2 = tcontext->role; - r1 = policydb->role_val_to_struct[val1 - 1]; - r2 = policydb->role_val_to_struct[val2 - 1]; -+ name1 = policydb->p_role_val_to_name[r1->s.value - 1]; -+ name2 = policydb->p_role_val_to_name[r2->s.value - 1]; -+ snprintf(tmp_buf, sizeof(tmp_buf), "r1=%s", name1); -+ free(src); src = strdup(tmp_buf); -+ snprintf(tmp_buf, sizeof(tmp_buf), "r2=%s ", name2); -+ free(tgt); tgt = strdup(tmp_buf); -+ - switch (e->op) { - case CEXPR_DOM: -- s[++sp] = -- ebitmap_get_bit(&r1->dominates, -- val2 - 1); -+ s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1); -+ msgcat(src, tgt, "dom", s[sp] == 0); -+ expr_counter++; - continue; - case CEXPR_DOMBY: -- s[++sp] = -- ebitmap_get_bit(&r2->dominates, -- val1 - 1); -+ s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1); -+ msgcat(src, tgt, "domby", s[sp] == 0); -+ expr_counter++; - continue; - case CEXPR_INCOMP: -- s[++sp] = -- (!ebitmap_get_bit -- (&r1->dominates, val2 - 1) -- && !ebitmap_get_bit(&r2->dominates, -- val1 - 1)); -+ s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1) -+ && !ebitmap_get_bit(&r2->dominates, val1 - 1)); -+ msgcat(src, tgt, "incomp", s[sp] == 0); -+ expr_counter++; - continue; - default: - break; -@@ -194,110 +500,327 @@ static int constraint_expr_eval(context_struct_t * scontext, - case CEXPR_L1L2: - l1 = &(scontext->range.level[0]); - l2 = &(tcontext->range.level[0]); -+ free(src); src = strdup("l1"); -+ free(tgt); tgt = strdup("l2"); - goto mls_ops; - case CEXPR_L1H2: - l1 = &(scontext->range.level[0]); - l2 = &(tcontext->range.level[1]); -+ free(src); src = strdup("l1"); -+ free(tgt); tgt = strdup("h2"); - goto mls_ops; - case CEXPR_H1L2: - l1 = &(scontext->range.level[1]); - l2 = &(tcontext->range.level[0]); -+ free(src); src = strdup("h1"); -+ free(tgt); tgt = strdup("L2"); - goto mls_ops; - case CEXPR_H1H2: - l1 = &(scontext->range.level[1]); - l2 = &(tcontext->range.level[1]); -+ free(src); src = strdup("h1"); -+ free(tgt); tgt = strdup("h2"); - goto mls_ops; - case CEXPR_L1H1: - l1 = &(scontext->range.level[0]); - l2 = &(scontext->range.level[1]); -+ free(src); src = strdup("l1"); -+ free(tgt); tgt = strdup("h1"); - goto mls_ops; - case CEXPR_L2H2: - l1 = &(tcontext->range.level[0]); - l2 = &(tcontext->range.level[1]); -- goto mls_ops; -- mls_ops: -+ free(src); src = strdup("l2"); -+ free(tgt); tgt = strdup("h2"); -+ mls_ops: - switch (e->op) { - case CEXPR_EQ: - s[++sp] = mls_level_eq(l1, l2); -+ msgcat(src, tgt, "eq", s[sp] == 0); -+ expr_counter++; - continue; - case CEXPR_NEQ: - s[++sp] = !mls_level_eq(l1, l2); -+ msgcat(src, tgt, "neq", s[sp] == 0); -+ expr_counter++; - continue; - case CEXPR_DOM: - s[++sp] = mls_level_dom(l1, l2); -+ msgcat(src, tgt, "dom", s[sp] == 0); -+ expr_counter++; - continue; - case CEXPR_DOMBY: - s[++sp] = mls_level_dom(l2, l1); -+ msgcat(src, tgt, "domby", s[sp] == 0); -+ expr_counter++; - continue; - case CEXPR_INCOMP: - s[++sp] = mls_level_incomp(l2, l1); -+ msgcat(src, tgt, "incomp", s[sp] == 0); -+ expr_counter++; - continue; - default: - BUG(); -- return 0; -+ goto out; - } - break; - default: - BUG(); -- return 0; -+ goto out; - } - - switch (e->op) { - case CEXPR_EQ: - s[++sp] = (val1 == val2); -+ msgcat(src, tgt, "eq", s[sp] == 0); - break; - case CEXPR_NEQ: - s[++sp] = (val1 != val2); -+ msgcat(src, tgt, "neq", s[sp] == 0); - break; - default: - BUG(); -- return 0; -+ goto out; - } - break; - case CEXPR_NAMES: - if (sp == (CEXPR_MAXDEPTH - 1)) -- return 0; -+ goto out; -+ s_t_x_num = SOURCE; - c = scontext; -- if (e->attr & CEXPR_TARGET) -+ if (e->attr & CEXPR_TARGET) { -+ s_t_x_num = TARGET; - c = tcontext; -- else if (e->attr & CEXPR_XTARGET) { -+ } else if (e->attr & CEXPR_XTARGET) { -+ s_t_x_num = XTARGET; - c = xcontext; -- if (!c) { -- BUG(); -- return 0; -- } - } -- if (e->attr & CEXPR_USER) -+ if (!c) { -+ BUG(); -+ goto out; -+ } -+ if (e->attr & CEXPR_USER) { -+ u_r_t = CEXPR_USER; - val1 = c->user; -- else if (e->attr & CEXPR_ROLE) -+ name1 = policydb->p_user_val_to_name[val1 - 1]; -+ snprintf(tmp_buf, sizeof(tmp_buf), "u%d=%s ", -+ s_t_x_num, name1); -+ free(src); src = strdup(tmp_buf); -+ } -+ else if (e->attr & CEXPR_ROLE) { -+ u_r_t = CEXPR_ROLE; - val1 = c->role; -- else if (e->attr & CEXPR_TYPE) -+ name1 = policydb->p_role_val_to_name[val1 - 1]; -+ snprintf(tmp_buf, sizeof(tmp_buf), "r%d=%s ", s_t_x_num, name1); -+ free(src); src = strdup(tmp_buf); -+ } -+ else if (e->attr & CEXPR_TYPE) { -+ u_r_t = CEXPR_TYPE; - val1 = c->type; -+ name1 = policydb->p_type_val_to_name[val1 - 1]; -+ snprintf(tmp_buf, sizeof(tmp_buf), -+ "t%d=%s ", s_t_x_num, name1); -+ free(src); src = strdup(tmp_buf); -+ } - else { - BUG(); -- return 0; -+ goto out; - } - - switch (e->op) { - case CEXPR_EQ: -+ switch (u_r_t) { -+ case CEXPR_USER: -+ free(tgt); tgt=strdup("USER_ENTRY"); -+ break; -+ case CEXPR_ROLE: -+ free(tgt); tgt=strdup("ROLE_ENTRY"); -+ break; -+ case CEXPR_TYPE: -+ free(tgt); tgt=strdup("TYPE_ENTRY"); -+ break; -+ default: -+ ERR(NULL, "unrecognized u_r_t Value: %d", u_r_t); -+ break; -+ } -+ - s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); -+ msgcat(src, tgt, "eq", s[sp] == 0); -+ if (s[sp] == 0) { -+ get_names_list(e, u_r_t); -+ } - break; -+ - case CEXPR_NEQ: -+ switch (u_r_t) { -+ case CEXPR_USER: -+ free(tgt); tgt=strdup("USER_ENTRY"); -+ break; -+ case CEXPR_ROLE: -+ free(tgt); tgt=strdup("ROLE_ENTRY"); -+ break; -+ case CEXPR_TYPE: -+ free(tgt); tgt=strdup("TYPE_ENTRY"); -+ break; -+ default: -+ ERR(NULL, "unrecognized u_r_t Value: %d", u_r_t); -+ break; -+ } -+ - s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); -+ msgcat(src, tgt, "neq", s[sp] == 0); -+ if (s[sp] == 0) { -+ get_names_list(e, u_r_t); -+ } - break; - default: - BUG(); -- return 0; -+ goto out; - } - break; - default: - BUG(); -- return 0; -+ goto out; - } -+ expr_counter++; -+ } -+ -+ /* -+ * At this point each expression of the constraint is in -+ * expr_list[n+1] and in RPN format. Now convert to 'infix' -+ */ -+ -+ /* -+ * Save expr count but zero expr_counter to detect if 'BUG(); goto out;' -+ * was called as we need to release any used expr_list malloc's. Normally -+ * they are released by the RPN to infix code. -+ */ -+ int expr_count = expr_counter; -+ expr_counter = 0; -+ -+ /* -+ * The array of expression answer buffer pointers and counter. Generate -+ * the same number of answer buffer entries as expression buffers (as -+ * there will never be more required). -+ */ -+ char **answer_list; -+ int answer_counter = 0; -+ -+ answer_list = malloc(expr_count * sizeof(*answer_list)); -+ if (!answer_list) { -+ ERR(NULL, "failed to allocate answer stack"); -+ rc = -ENOMEM; -+ goto out; - } - -- BUG_ON(sp != 0); -- return s[0]; -+ /* The pop operands */ -+ char *a; -+ char *b; -+ int a_len, b_len; -+ -+ /* Convert constraint from RPN to infix notation. */ -+ for (x = 0; x != expr_count; x++) { -+ if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x], -+ "or", 2) == 0) { -+ b = pop(); -+ b_len = strlen(b); -+ a = pop(); -+ a_len = strlen(a); -+ -+ /* get a buffer to hold the answer */ -+ answer_list[answer_counter] = malloc(a_len + b_len + 8); -+ if (!answer_list[answer_counter]) { -+ ERR(NULL, "failed to allocate answer buffer"); -+ rc = -ENOMEM; -+ goto out; -+ } -+ memset(answer_list[answer_counter], '\0', a_len + b_len + 8); -+ -+ sprintf(answer_list[answer_counter], "%s %s %s", a, expr_list[x], b); -+ push(answer_list[answer_counter++]); -+ free(a); -+ free(b); -+ } else if (strncmp(expr_list[x], "not", 3) == 0) { -+ b = pop(); -+ b_len = strlen(b); -+ -+ answer_list[answer_counter] = malloc(b_len + 8); -+ if (!answer_list[answer_counter]) { -+ ERR(NULL, "failed to allocate answer buffer"); -+ rc = -ENOMEM; -+ goto out; -+ } -+ memset(answer_list[answer_counter], '\0', b_len + 8); -+ -+ if (strncmp(b, "not", 3) == 0) -+ sprintf(answer_list[answer_counter], "%s (%s)", expr_list[x], b); -+ else -+ sprintf(answer_list[answer_counter], "%s%s", expr_list[x], b); -+ push(answer_list[answer_counter++]); -+ free(b); -+ } else { -+ push(expr_list[x]); -+ } -+ } -+ /* Get the final answer from tos and build constraint text */ -+ a = pop(); -+ -+ /* Constraint calculation: rc = 0 is denied, rc = 1 is granted */ -+ sprintf(tmp_buf,"Constraint %s\n", s[0] ? "GRANTED" : "DENIED"); -+ -+ int len, new_buf_len; -+ char *p, **new_buf = r_buf; -+ /* -+ * These contain the constraint components that are added to the -+ * callers reason buffer. -+ */ -+ char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 }; -+ -+ /* -+ * This will add the constraints to the callers reason buffer (who is -+ * responsible for freeing the memory). It will handle any realloc's -+ * should the buffer be too short. -+ * The reason_buf_used and reason_buf_len counters are defined globally -+ * as multiple constraints can be in the buffer. -+ */ -+ if (r_buf && ((s[0] == 0) || ((s[0] == 1 && -+ (flags & SHOW_GRANTED) == SHOW_GRANTED)))) { -+ for (x = 0; buffers[x] != NULL; x++) { -+ while (1) { -+ p = *r_buf + reason_buf_used; -+ len = snprintf(p, reason_buf_len - reason_buf_used, "%s", buffers[x]); -+ if (len < 0 || len >= reason_buf_len - reason_buf_used) { -+ new_buf_len = reason_buf_len + REASON_BUF_SIZE; -+ *new_buf = realloc(*r_buf, new_buf_len); -+ if (!new_buf) { -+ ERR(NULL, "failed to realloc reason buffer"); -+ goto out1; -+ } -+ **r_buf = **new_buf; -+ reason_buf_len = new_buf_len; -+ continue; -+ } else { -+ reason_buf_used += len; -+ break; -+ } -+ } -+ } -+ } -+ -+out1: -+ rc = s[0]; -+ free(a); -+ -+out: -+ free(class_buf); -+ free(src); -+ free(tgt); -+ -+ if (expr_counter) { -+ for (x = 0; expr_list[x] != NULL; x++) -+ free(expr_list[x]); -+ } -+ return rc; - } - - /* -@@ -309,7 +832,9 @@ static int context_struct_compute_av(context_struct_t * scontext, - sepol_security_class_t tclass, - sepol_access_vector_t requested, - struct sepol_av_decision *avd, -- unsigned int *reason) -+ unsigned int *reason, -+ char **r_buf, -+ unsigned int flags) - { - constraint_node_t *constraint; - struct role_allow *ra; -@@ -384,8 +909,8 @@ static int context_struct_compute_av(context_struct_t * scontext, - constraint = tclass_datum->constraints; - while (constraint) { - if ((constraint->permissions & (avd->allowed)) && -- !constraint_expr_eval(scontext, tcontext, NULL, -- constraint->expr)) { -+ !constraint_expr_eval_reason(scontext, tcontext, NULL, -+ tclass, constraint, r_buf, flags)) { - avd->allowed = - (avd->allowed) & ~(constraint->permissions); - } -@@ -460,8 +985,8 @@ int hidden sepol_validate_transition(sepol_security_id_t oldsid, - - constraint = tclass_datum->validatetrans; - while (constraint) { -- if (!constraint_expr_eval(ocontext, ncontext, tcontext, -- constraint->expr)) { -+ if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext, -+ 0, constraint, NULL, 0)) { - return -EPERM; - } - constraint = constraint->next; -@@ -494,11 +1019,59 @@ int hidden sepol_compute_av_reason(sepol_security_id_t ssid, - } - - rc = context_struct_compute_av(scontext, tcontext, tclass, -- requested, avd, reason); -+ requested, avd, reason, NULL, 0); - out: - return rc; - } - -+/* -+ * sepol_compute_av_reason_buffer - the reason buffer is malloc'd to -+ * REASON_BUF_SIZE. If the buffer size is exceeded, then it is realloc'd -+ * in the constraint_expr_eval_reason() function. -+ */ -+int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid, -+ sepol_security_id_t tsid, -+ sepol_security_class_t tclass, -+ sepol_access_vector_t requested, -+ struct sepol_av_decision *avd, -+ unsigned int *reason, -+ char **reason_buf, -+ unsigned int flags) -+{ -+ *reason_buf = malloc(REASON_BUF_SIZE); -+ if (!*reason_buf) { -+ ERR(NULL, "failed to allocate reason buffer"); -+ return -ENOMEM; -+ } -+ /* -+ * These are defined globally as the buffer can contain multiple -+ * constraint statements so need to keep track -+ */ -+ reason_buf_used = 0; -+ reason_buf_len = REASON_BUF_SIZE; -+ -+ context_struct_t *scontext = 0, *tcontext = 0; -+ int rc = 0; -+ -+ scontext = sepol_sidtab_search(sidtab, ssid); -+ if (!scontext) { -+ ERR(NULL, "unrecognized SID %d", ssid); -+ rc = -EINVAL; -+ goto out; -+ } -+ tcontext = sepol_sidtab_search(sidtab, tsid); -+ if (!tcontext) { -+ ERR(NULL, "unrecognized SID %d", tsid); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = context_struct_compute_av(scontext, tcontext, tclass, -+ requested, avd, reason, reason_buf, flags); -+out: -+ return rc; -+} -+ - int hidden sepol_compute_av(sepol_security_id_t ssid, - sepol_security_id_t tsid, - sepol_security_class_t tclass, -@@ -511,6 +1084,70 @@ int hidden sepol_compute_av(sepol_security_id_t ssid, - } - - /* -+ * Return a class ID associated with the class string specified by -+ * class_name. -+ */ -+int hidden sepol_class_name_to_id(const char *class_name, -+ sepol_security_class_t *tclass) -+{ -+ char *class = NULL; -+ sepol_security_class_t id; -+ -+ for (id = 1; ; id++) { -+ if ((class = policydb->p_class_val_to_name[id - 1]) == NULL) { -+ ERR(NULL, "could not convert %s to class id", class_name); -+ return STATUS_ERR; -+ } -+ if ((strcmp(class, class_name)) == 0) { -+ *tclass = id; -+ return STATUS_SUCCESS; -+ } -+ } -+} -+ -+/* -+ * Return access vector bit associated with the class ID and permission -+ * string. -+ */ -+int hidden sepol_perm_name_to_av(sepol_security_class_t tclass, -+ const char *perm_name, -+ sepol_access_vector_t *av) -+{ -+ class_datum_t *tclass_datum; -+ perm_datum_t *perm_datum; -+ -+ if (!tclass || tclass > policydb->p_classes.nprim) { -+ ERR(NULL, "unrecognized class %d", tclass); -+ return -EINVAL; -+ } -+ tclass_datum = policydb->class_val_to_struct[tclass - 1]; -+ -+ /* Check for unique perms then the common ones (if any) */ -+ perm_datum = (perm_datum_t *) -+ hashtab_search(tclass_datum->permissions.table, -+ (hashtab_key_t)perm_name); -+ if (perm_datum != NULL) { -+ *av = 0x1 << (perm_datum->s.value - 1); -+ return STATUS_SUCCESS; -+ } -+ -+ if (tclass_datum->comdatum == NULL) -+ goto out; -+ -+ perm_datum = (perm_datum_t *) -+ hashtab_search(tclass_datum->comdatum->permissions.table, -+ (hashtab_key_t)perm_name); -+ -+ if (perm_datum != NULL) { -+ *av = 0x1 << (perm_datum->s.value - 1); -+ return STATUS_SUCCESS; -+ } -+out: -+ ERR(NULL, "could not convert %s to av bit", perm_name); -+ return STATUS_ERR; -+} -+ -+/* - * Write the security context string representation of - * the context associated with `sid' into a dynamically - * allocated string of the correct size. Set `*scontext' -@@ -1339,7 +1976,7 @@ int hidden sepol_get_user_sids(sepol_security_id_t fromsid, - rc = context_struct_compute_av(fromcon, &usercon, - SECCLASS_PROCESS, - PROCESS__TRANSITION, -- &avd, &reason); -+ &avd, &reason, NULL, 0); - if (rc || !(avd.allowed & PROCESS__TRANSITION)) - continue; - rc = sepol_sidtab_context_to_sid(sidtab, &usercon, -diff --git a/libsepol/src/write.c b/libsepol/src/write.c -index 55992f8..6fe73e6 100644 ---- a/libsepol/src/write.c -+++ b/libsepol/src/write.c -@@ -893,8 +893,11 @@ static int write_cons_helper(policydb_t * p, - if (ebitmap_write(&e->names, fp)) { - return POLICYDB_ERROR; - } -- if (p->policy_type != POLICY_KERN && -- type_set_write(e->type_names, fp)) { -+ if ((p->policy_type != POLICY_KERN && -+ type_set_write(e->type_names, fp)) || -+ (p->policy_type == POLICY_KERN && -+ (p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) && -+ type_set_write(e->type_names, fp))) { - return POLICYDB_ERROR; - } - break; diff --git a/SOURCES/libsepol-rhel.patch b/SOURCES/libsepol-rhel.patch new file mode 100644 index 0000000..0efef6b --- /dev/null +++ b/SOURCES/libsepol-rhel.patch @@ -0,0 +1,3458 @@ +diff --git libsepol-2.5/Android.mk libsepol-2.5/Android.mk +index a43b343..21c1af8 100644 +--- libsepol-2.5/Android.mk ++++ libsepol-2.5/Android.mk +@@ -68,10 +68,6 @@ common_cflags := \ + -Wshadow -Wmissing-noreturn \ + -Wmissing-format-attribute + +-ifeq ($(HOST_OS), darwin) +-common_cflags += -DDARWIN +-endif +- + common_includes := \ + $(LOCAL_PATH)/include/ \ + $(LOCAL_PATH)/src/ \ +diff --git libsepol-2.5/ChangeLog libsepol-2.5/ChangeLog +index ace3d54..c7cc464 100644 +--- libsepol-2.5/ChangeLog ++++ libsepol-2.5/ChangeLog +@@ -1,3 +1,25 @@ ++ * Fix memory leak in expand.c, from William Roberts. ++ * Fix invalid read when policy file is corrupt, from William Roberts. ++ * Fix possible use of uninitialized variables, from William Roberts. ++ * Warn instead of fail if permission is not resolved, from James Carter. ++ * Ignore object_r when adding userrole mappings to policydb, from Steve Lawrence. ++ * Add missing return to sepol_node_query(), from Petr Lautrbach. ++ * Correctly detect unknown classes in sepol_string_to_security_class, from Joshua Brindle. ++ * Sort object files for deterministic linking order, from Laurent Bigonville. ++ * Fix neverallowxperm checking on attributes, from Jeff Vander Stoep. ++ * Remove libsepol.map when cleaning, from Nicolas Iooss. ++ * Add high-level language line marking support to CIL, from James Carter. ++ * Change logic of bounds checking to match change in kernel, from James Carter. ++ * Fix multiple spelling errors, from Laurent Bigonville. ++ * Only apply bounds checking to source types in rules, from Stephen Smalley. ++ * Fix CIL and not add an attribute as a type in the attr_type_map, from James Carter ++ * Build policy on systems not supporting DCCP protocol, from Richard Haines. ++ * Fix extended permissions neverallow checking, from Jeff Vander Stoep. ++ * Fix CIL neverallow and bounds checking, from James Carter ++ * Android.mk: Add -D_GNU_SOURCE to common_cflags, from Nick Kralevich. ++ * Add support for portcon dccp protocol, from Richard Haines ++ * Fix bug in CIL when resetting classes, from Steve Lawrence ++ + 2.5 2016-02-23 + * Fix unused variable annotations, from Nicolas Iooss. + * Fix uninitialized variable in CIL, from Nicolas Iooss. +diff --git libsepol-2.5/cil/src/cil.c libsepol-2.5/cil/src/cil.c +index afdc240..929ab19 100644 +--- libsepol-2.5/cil/src/cil.c ++++ libsepol-2.5/cil/src/cil.c +@@ -108,6 +108,7 @@ static void cil_init_keys(void) + CIL_KEY_STAR = cil_strpool_add("*"); + CIL_KEY_UDP = cil_strpool_add("udp"); + CIL_KEY_TCP = cil_strpool_add("tcp"); ++ CIL_KEY_DCCP = cil_strpool_add("dccp"); + CIL_KEY_AUDITALLOW = cil_strpool_add("auditallow"); + CIL_KEY_TUNABLEIF = cil_strpool_add("tunableif"); + CIL_KEY_ALLOW = cil_strpool_add("allow"); +@@ -232,6 +233,9 @@ static void cil_init_keys(void) + CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx"); + CIL_KEY_IOCTL = cil_strpool_add("ioctl"); + CIL_KEY_UNORDERED = cil_strpool_add("unordered"); ++ CIL_KEY_SRC_INFO = cil_strpool_add(""); ++ CIL_KEY_SRC_CIL = cil_strpool_add(""); ++ CIL_KEY_SRC_HLL = cil_strpool_add(""); + } + + void cil_db_init(struct cil_db **db) +@@ -756,6 +760,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor) + case CIL_MLS: + cil_destroy_mls(*data); + break; ++ case CIL_SRC_INFO: ++ cil_destroy_src_info(*data); ++ break; + case CIL_OP: + case CIL_CONS_OPERAND: + break; +@@ -763,8 +770,8 @@ void cil_destroy_data(void **data, enum cil_flavor flavor) + cil_log(CIL_INFO, "Unknown data flavor: %d\n", flavor); + break; + } +- +- *data = NULL; ++ ++ *data = NULL; + } + + int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *sym_index) +@@ -1108,6 +1115,8 @@ const char * cil_node_to_string(struct cil_tree_node *node) + return CIL_KEY_HANDLEUNKNOWN; + case CIL_MLS: + return CIL_KEY_MLS; ++ case CIL_SRC_INFO: ++ return CIL_KEY_SRC_INFO; + case CIL_ALL: + return CIL_KEY_ALL; + case CIL_RANGE: +@@ -1755,8 +1764,7 @@ int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_s + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Failed to get symtab from node at line %d of %s\n", +- ast_node->line, ast_node->path); ++ cil_tree_log(ast_node, CIL_ERR, "Failed to get symtab from node"); + return SEPOL_ERR; + } + +@@ -2553,3 +2561,10 @@ void cil_mls_init(struct cil_mls **mls) + *mls = cil_malloc(sizeof(**mls)); + (*mls)->value = 0; + } ++ ++void cil_src_info_init(struct cil_src_info **info) ++{ ++ *info = cil_malloc(sizeof(**info)); ++ (*info)->is_cil = 0; ++ (*info)->path = NULL; ++} +diff --git libsepol-2.5/cil/src/cil_binary.c libsepol-2.5/cil/src/cil_binary.c +index f749e53..46fea4b 100644 +--- libsepol-2.5/cil/src/cil_binary.c ++++ libsepol-2.5/cil/src/cil_binary.c +@@ -31,6 +31,9 @@ + #include + #include + #include ++#ifndef IPPROTO_DCCP ++#define IPPROTO_DCCP 33 ++#endif + + #include + #include +@@ -606,9 +609,11 @@ int __cil_typeattr_bitmap_init(policydb_t *pdb) + rc = SEPOL_ERR; + goto exit; + } +- if (ebitmap_set_bit(&pdb->attr_type_map[i], i, 1)) { +- rc = SEPOL_ERR; +- goto exit; ++ if (pdb->type_val_to_struct[i] && pdb->type_val_to_struct[i]->flavor != TYPE_ATTRIB) { ++ if (ebitmap_set_bit(&pdb->attr_type_map[i], i, 1)) { ++ rc = SEPOL_ERR; ++ goto exit; ++ } + } + + } +@@ -749,6 +754,12 @@ int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct ci + goto exit; + } + ++ if (sepol_role->s.value == 1) { ++ // role is object_r, ignore it since it is implicitly associated ++ // with all users ++ continue; ++ } ++ + if (ebitmap_set_bit(&sepol_user->roles.roles, sepol_role->s.value - 1, 1)) { + cil_log(CIL_INFO, "Failed to set role bit for user\n"); + rc = SEPOL_ERR; +@@ -1770,13 +1781,12 @@ int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unu + cil_typetrans = (struct cil_nametypetransition*)node->data; + if (DATUM(cil_typetrans->name)->fqn != CIL_KEY_STAR) { + cil_log(CIL_ERR, "typetransition with file name not allowed within a booleanif block.\n"); +- cil_log(CIL_ERR,"Invalid typetransition statement at line %d of %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR,"Invalid typetransition statement"); + goto exit; + } + rc = __cil_typetransition_to_avtab(pdb, db, cil_typetrans, cond_node, cond_flavor, filename_trans_table); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to insert type transition into avtab at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Failed to insert type transition into avtab"); + goto exit; + } + break; +@@ -1784,7 +1794,7 @@ int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unu + cil_type_rule = node->data; + rc = __cil_type_rule_to_avtab(pdb, db, cil_type_rule, cond_node, cond_flavor); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to insert typerule into avtab at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Failed to insert typerule into avtab"); + goto exit; + } + break; +@@ -1792,7 +1802,7 @@ int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unu + cil_avrule = node->data; + rc = __cil_avrule_to_avtab(pdb, db, cil_avrule, cond_node, cond_flavor); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to insert avrule into avtab at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Failed to insert avrule into avtab"); + goto exit; + } + break; +@@ -1800,8 +1810,7 @@ int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unu + case CIL_TUNABLEIF: + break; + default: +- cil_log(CIL_ERR, "Invalid statement within booleanif at line %d of %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid statement within booleanif"); + goto exit; + } + +@@ -2060,14 +2069,13 @@ int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c + tmp_cond = cond_node_create(pdb, NULL); + if (tmp_cond == NULL) { + rc = SEPOL_ERR; +- cil_log(CIL_INFO, "Failed to create sepol conditional node at line %d of %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_INFO, "Failed to create sepol conditional node"); + goto exit; + } + + rc = __cil_cond_expr_to_sepol_expr(pdb, cil_boolif->datum_expr, &tmp_cond->expr); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Failed to convert CIL conditional expression to sepol expression at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_INFO, "Failed to convert CIL conditional expression to sepol expression"); + goto exit; + } + +@@ -2123,7 +2131,7 @@ int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c + bool_args.cond_flavor = CIL_CONDTRUE; + rc = cil_tree_walk(true_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failure while walking true conditional block at line %d of %s\n", true_node->line, true_node->path); ++ cil_tree_log(true_node, CIL_ERR, "Failure while walking true conditional block"); + goto exit; + } + } +@@ -2132,7 +2140,7 @@ int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c + bool_args.cond_flavor = CIL_CONDFALSE; + rc = cil_tree_walk(false_node, __cil_cond_to_policydb_helper, NULL, NULL, &bool_args); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failure while walking false conditional block at line %d of %s\n", false_node->line, false_node->path); ++ cil_tree_log(false_node, CIL_ERR, "Failure while walking false conditional block"); + goto exit; + } + } +@@ -3035,6 +3043,9 @@ int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons) + case CIL_PROTOCOL_TCP: + new_ocon->u.port.protocol = IPPROTO_TCP; + break; ++ case CIL_PROTOCOL_DCCP: ++ new_ocon->u.port.protocol = IPPROTO_DCCP; ++ break; + default: + /* should not get here */ + rc = SEPOL_ERR; +@@ -3583,7 +3594,7 @@ int __cil_node_to_policydb(struct cil_tree_node *node, void *extra_args) + + exit: + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Binary policy creation failed at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Binary policy creation failed"); + } + return rc; + } +@@ -4227,6 +4238,9 @@ exit: + static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *node) + { + avrule_t *avrule; ++ struct cil_tree_node *source_node; ++ char *source_path; ++ int is_cil; + + avrule = cil_malloc(sizeof(avrule_t)); + avrule->specified = kind; +@@ -4235,8 +4249,17 @@ static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *no + __cil_init_sepol_type_set(&avrule->ttypes); + avrule->perms = NULL; + avrule->line = node->line; +- avrule->source_filename = node->path; ++ ++ avrule->source_filename = NULL; + avrule->source_line = node->line; ++ source_node = cil_tree_get_next_path(node, &source_path, &is_cil); ++ if (source_node) { ++ avrule->source_filename = source_path; ++ if (!is_cil) { ++ avrule->source_line = node->hll_line; ++ } ++ } ++ + avrule->next = NULL; + return avrule; + } +@@ -4263,10 +4286,8 @@ static void __cil_print_parents(const char *pad, struct cil_tree_node *n) + + __cil_print_parents(pad, n->parent); + +- if (!n->path) { +- cil_log(CIL_ERR,"%s%s\n", pad, cil_node_to_string(n)); +- } else { +- cil_log(CIL_ERR,"%s%s at line %d of %s\n", pad, cil_node_to_string(n), n->line, n->path); ++ if (n->flavor != CIL_SRC_INFO) { ++ cil_tree_log(n, CIL_ERR,"%s%s", pad, cil_node_to_string(n)); + } + } + +@@ -4357,7 +4378,7 @@ static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tr + allow_str = CIL_KEY_ALLOWX; + avrule_flavor = CIL_AVRULEX; + } +- cil_log(CIL_ERR, "%s check failed at line %d of %s\n", neverallow_str, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "%s check failed", neverallow_str); + __cil_print_rule(" ", neverallow_str, cil_rule); + cil_list_init(&matching, CIL_NODE); + rc = cil_find_matching_avrule_in_ast(db->ast->root, avrule_flavor, &target, matching, CIL_FALSE); +@@ -4380,10 +4401,9 @@ exit: + return rc; + } + +-static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct cil_tree_node *node) ++static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct cil_tree_node *node, int *violation) + { +- int rc = SEPOL_ERR; +- int ret = CIL_FALSE; ++ int rc = SEPOL_OK; + struct cil_avrule *cil_rule = node->data; + struct cil_symtab_datum *tgt = cil_rule->tgt; + uint32_t kind; +@@ -4422,11 +4442,11 @@ static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct + + rc = check_assertion(pdb, rule); + if (rc == CIL_TRUE) { ++ *violation = CIL_TRUE; + rc = __cil_print_neverallow_failure(db, node); + if (rc != SEPOL_OK) { + goto exit; + } +- ret = CIL_TRUE; + } + + } else { +@@ -4444,12 +4464,11 @@ static int cil_check_neverallow(const struct cil_db *db, policydb_t *pdb, struct + rule->xperms = item->data; + rc = check_assertion(pdb, rule); + if (rc == CIL_TRUE) { ++ *violation = CIL_TRUE; + rc = __cil_print_neverallow_failure(db, node); + if (rc != SEPOL_OK) { + goto exit; + } +- ret = CIL_TRUE; +- goto exit; + } + } + } +@@ -4466,34 +4485,23 @@ exit: + rule->xperms = NULL; + __cil_destroy_sepol_avrules(rule); + +- if (rc) { +- return rc; +- } else { +- return ret; +- } ++ return rc; + } + +-static int cil_check_neverallows(const struct cil_db *db, policydb_t *pdb, struct cil_list *neverallows) ++static int cil_check_neverallows(const struct cil_db *db, policydb_t *pdb, struct cil_list *neverallows, int *violation) + { + int rc = SEPOL_OK; +- int ret = CIL_FALSE; + struct cil_list_item *item; + + cil_list_for_each(item, neverallows) { +- rc = cil_check_neverallow(db, pdb, item->data); +- if (rc < 0) { ++ rc = cil_check_neverallow(db, pdb, item->data, violation); ++ if (rc != SEPOL_OK) { + goto exit; +- } else if (rc > 0) { +- ret = CIL_TRUE; + } + } + + exit: +- if (rc || ret) { +- return SEPOL_ERR; +- } else { +- return SEPOL_OK; +- } ++ return rc; + } + + static struct cil_list *cil_classperms_from_sepol(policydb_t *pdb, uint16_t class, uint32_t data, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) +@@ -4548,7 +4556,7 @@ exit: + return rc; + } + +-static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void *type_value_to_cil, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[]) ++static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void *type_value_to_cil, struct cil_class *class_value_to_cil[], struct cil_perm **perm_value_to_cil[], int *violation) + { + int rc = SEPOL_OK; + int i; +@@ -4574,6 +4582,9 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void + if (bad) { + avtab_ptr_t cur; + struct cil_avrule target; ++ struct cil_tree_node *n1 = NULL; ++ ++ *violation = CIL_TRUE; + + target.is_extended = 0; + target.rule_kind = CIL_AVRULE_ALLOWED; +@@ -4585,7 +4596,6 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void + for (cur = bad; cur; cur = cur->next) { + struct cil_list_item *i2; + struct cil_list *matching; +- struct cil_tree_node *n; + + rc = cil_avrule_from_sepol(pdb, cur, &target, type_value_to_cil, class_value_to_cil, perm_value_to_cil); + if (rc != SEPOL_OK) { +@@ -4594,7 +4604,7 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void + } + __cil_print_rule(" ", "allow", &target); + cil_list_init(&matching, CIL_NODE); +- rc = cil_find_matching_avrule_in_ast(db->ast->root, CIL_AVRULE, &target, matching, CIL_FALSE); ++ rc = cil_find_matching_avrule_in_ast(db->ast->root, CIL_AVRULE, &target, matching, CIL_TRUE); + if (rc) { + cil_log(CIL_ERR, "Error occurred while checking type bounds\n"); + cil_list_destroy(&matching, CIL_FALSE); +@@ -4602,14 +4612,17 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void + bounds_destroy_bad(bad); + goto exit; + } +- + cil_list_for_each(i2, matching) { +- __cil_print_parents(" ", (struct cil_tree_node *)i2->data); ++ struct cil_tree_node *n2 = i2->data; ++ struct cil_avrule *r2 = n2->data; ++ if (n1 == n2) { ++ cil_log(CIL_ERR, " \n"); ++ } else { ++ n1 = n2; ++ __cil_print_parents(" ", n2); ++ __cil_print_rule(" ", "allow", r2); ++ } + } +- i2 = matching->tail; +- n = i2->data; +- __cil_print_rule(" ", "allow", n->data); +- cil_log(CIL_ERR,"\n"); + cil_list_destroy(&matching, CIL_FALSE); + cil_list_destroy(&target.perms.classperms, CIL_TRUE); + } +@@ -4753,20 +4766,32 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p + __cil_set_conditional_state_and_flags(pdb); + + if (db->disable_neverallow != CIL_TRUE) { ++ int violation = CIL_FALSE; + cil_log(CIL_INFO, "Checking Neverallows\n"); +- rc = cil_check_neverallows(db, pdb, neverallows); ++ rc = cil_check_neverallows(db, pdb, neverallows, &violation); + if (rc != SEPOL_OK) goto exit; + + cil_log(CIL_INFO, "Checking User Bounds\n"); +- bounds_check_users(NULL, pdb); ++ rc = bounds_check_users(NULL, pdb); ++ if (rc) { ++ violation = CIL_TRUE; ++ } + + cil_log(CIL_INFO, "Checking Role Bounds\n"); +- bounds_check_roles(NULL, pdb); ++ rc = bounds_check_roles(NULL, pdb); ++ if (rc) { ++ violation = CIL_TRUE; ++ } + + cil_log(CIL_INFO, "Checking Type Bounds\n"); +- rc = cil_check_type_bounds(db, pdb, type_value_to_cil, class_value_to_cil, perm_value_to_cil); ++ rc = cil_check_type_bounds(db, pdb, type_value_to_cil, class_value_to_cil, perm_value_to_cil, &violation); + if (rc != SEPOL_OK) goto exit; + ++ if (violation == CIL_TRUE) { ++ rc = SEPOL_ERR; ++ goto exit; ++ } ++ + } + + rc = SEPOL_OK; +diff --git libsepol-2.5/cil/src/cil_build_ast.c libsepol-2.5/cil/src/cil_build_ast.c +index 1135e06..1505873 100644 +--- libsepol-2.5/cil/src/cil_build_ast.c ++++ libsepol-2.5/cil/src/cil_build_ast.c +@@ -108,8 +108,7 @@ int cil_gen_node(__attribute__((unused)) struct cil_db *db, struct cil_tree_node + if (cil_symtab_get_datum(symtab, key, &datum) == SEPOL_OK) { + if (sflavor == CIL_SYM_BLOCKS) { + struct cil_tree_node *node = datum->nodes->head->data; +- cil_log(CIL_ERR, "Previous declaration at line %d of %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Previous declaration"); + } + } + goto exit; +@@ -186,8 +185,7 @@ int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad block declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad block declaration"); + cil_destroy_block(block); + cil_clear_node(ast_node); + return rc; +@@ -236,8 +234,7 @@ int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad blockinherit declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad blockinherit declaration"); + cil_destroy_blockinherit(inherit); + return rc; + } +@@ -281,8 +278,7 @@ int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad blockabstract declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad blockabstract declaration"); + cil_destroy_blockabstract(abstract); + return rc; + } +@@ -326,8 +322,7 @@ int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct ci + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Bad in statement at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad in statement"); + cil_destroy_in(in); + return rc; + } +@@ -387,8 +382,7 @@ int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad class declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad class declaration"); + cil_destroy_class(class); + cil_clear_node(ast_node); + return rc; +@@ -456,8 +450,7 @@ int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, s + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad classorder declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad classorder declaration"); + cil_destroy_classorder(classorder); + return rc; + } +@@ -527,7 +520,7 @@ int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, st + cil_tree_node_init(&new_ast); + new_ast->parent = ast_node; + new_ast->line = current_perm->line; +- new_ast->path = current_perm->path; ++ new_ast->hll_line = current_perm->hll_line; + + rc = cil_gen_perm(db, current_perm, new_ast, flavor, num_perms); + if (rc != SEPOL_OK) { +@@ -738,8 +731,7 @@ int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_curre + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad classpermission declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad classpermission declaration"); + cil_destroy_classpermission(cp); + cil_clear_node(ast_node); + return rc; +@@ -800,8 +792,7 @@ int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_cu + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad classpermissionset at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad classpermissionset"); + cil_destroy_classpermissionset(cps); + return rc; + } +@@ -852,8 +843,7 @@ int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad map class declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad map class declaration"); + cil_destroy_class(map); + cil_clear_node(ast_node); + return rc; +@@ -897,8 +887,7 @@ int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad classmapping declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad classmapping declaration"); + cil_destroy_classmapping(mapping); + return rc; + } +@@ -954,8 +943,7 @@ int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struc + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad common declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad common declaration"); + cil_destroy_class(common); + cil_clear_node(ast_node); + return rc; +@@ -994,8 +982,7 @@ int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad classcommon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad classcommon declaration"); + cil_destroy_classcommon(clscom); + return rc; + +@@ -1043,8 +1030,7 @@ int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct c + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad sid declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad sid declaration"); + cil_destroy_sid(sid); + cil_clear_node(ast_node); + return rc; +@@ -1102,8 +1088,7 @@ int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, s + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad sidcontext declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad sidcontext declaration"); + cil_destroy_sidcontext(sidcon); + return rc; + } +@@ -1163,8 +1148,7 @@ int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad sidorder declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad sidorder declaration"); + cil_destroy_sidorder(sidorder); + return rc; + } +@@ -1215,8 +1199,7 @@ int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad user declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad user declaration"); + cil_destroy_user(user); + cil_clear_node(ast_node); + return rc; +@@ -1265,8 +1248,7 @@ int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Bad userattribute declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad userattribute declaration"); + cil_destroy_userattribute(attr); + cil_clear_node(ast_node); + return rc; +@@ -1336,8 +1318,7 @@ int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_curr + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad userattributeset declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad userattributeset declaration"); + cil_destroy_userattributeset(attrset); + + return rc; +@@ -1397,8 +1378,7 @@ int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad userlevel declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad userlevel declaration"); + cil_destroy_userlevel(usrlvl); + return rc; + } +@@ -1458,8 +1438,7 @@ int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad userrange declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad userrange declaration"); + cil_destroy_userrange(userrange); + return rc; + } +@@ -1508,8 +1487,7 @@ int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, s + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Bad userprefix declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad userprefix declaration"); + cil_destroy_userprefix(userprefix); + return rc; + } +@@ -1566,8 +1544,7 @@ int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Bad selinuxuser declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuser declaration"); + cil_destroy_selinuxuser(selinuxuser); + return rc; + } +@@ -1614,8 +1591,7 @@ int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_cu + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Bad selinuxuserdefault declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuserdefault declaration"); + cil_destroy_selinuxuser(selinuxuser); + return rc; + } +@@ -1666,8 +1642,7 @@ int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad role declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad role declaration"); + cil_destroy_role(role); + cil_clear_node(ast_node); + return rc; +@@ -1717,8 +1692,7 @@ int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad roletype declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad roletype declaration"); + cil_destroy_roletype(roletype); + return rc; + } +@@ -1764,8 +1738,7 @@ int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad userrole declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad userrole declaration"); + cil_destroy_userrole(userrole); + return rc; + } +@@ -1815,8 +1788,7 @@ int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_ + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad roletransition rule at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad roletransition rule"); + cil_destroy_roletransition(roletrans); + return rc; + } +@@ -1862,8 +1834,7 @@ int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad roleallow rule at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad roleallow rule"); + cil_destroy_roleallow(roleallow); + return rc; + } +@@ -1914,8 +1885,7 @@ int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Bad roleattribute declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad roleattribute declaration"); + cil_destroy_roleattribute(attr); + cil_clear_node(ast_node); + return rc; +@@ -1982,8 +1952,7 @@ int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_curr + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad roleattributeset declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad roleattributeset declaration"); + cil_destroy_roleattributeset(attrset); + + return rc; +@@ -2042,8 +2011,7 @@ int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *as + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad allow rule at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad allow rule"); + cil_destroy_avrule(rule); + return rc; + } +@@ -2099,8 +2067,7 @@ int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permiss + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad permissionx content at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad permissionx content"); + return rc; + } + +@@ -2143,8 +2110,7 @@ int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad permissionx statement at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad permissionx statement"); + cil_destroy_permissionx(permx); + cil_clear_node(ast_node); + return rc; +@@ -2210,8 +2176,7 @@ int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *a + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad allowx rule at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad allowx rule"); + cil_destroy_avrule(rule); + return rc; + } +@@ -2253,8 +2218,7 @@ int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad type rule at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad type rule"); + cil_destroy_type_rule(rule); + return rc; + } +@@ -2306,8 +2270,7 @@ int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad type declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad type declaration"); + cil_destroy_type(type); + cil_clear_node(ast_node); + return rc; +@@ -2361,8 +2324,7 @@ int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad typeattribute declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad typeattribute declaration"); + cil_destroy_typeattribute(attr); + cil_clear_node(ast_node); + return rc; +@@ -2439,11 +2401,9 @@ int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct + + exit: + if (tunableif) { +- cil_log(CIL_ERR, "Bad tunable (treated as a boolean due to preserve-tunables) declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad tunable (treated as a boolean due to preserve-tunables) declaration"); + } else { +- cil_log(CIL_ERR, "Bad boolean declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad boolean declaration"); + } + cil_destroy_bool(boolean); + cil_clear_node(ast_node); +@@ -2504,8 +2464,7 @@ int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad tunable declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad tunable declaration"); + cil_destroy_tunable(tunable); + cil_clear_node(ast_node); + return rc; +@@ -2880,11 +2839,9 @@ int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struc + + exit: + if (tunableif) { +- cil_log(CIL_ERR, "Bad tunableif (treated as a booleanif due to preserve-tunables) declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad tunableif (treated as a booleanif due to preserve-tunables) declaration"); + } else { +- cil_log(CIL_ERR, "Bad booleanif declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad booleanif declaration"); + } + cil_destroy_boolif(bif); + return rc; +@@ -2964,8 +2921,7 @@ int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad tunableif declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad tunableif declaration"); + cil_destroy_tunif(tif); + return rc; + } +@@ -3018,8 +2974,8 @@ int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad %s condition declaration at line %d of %s\n", +- (char*)parse_current->data, parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad %s condition declaration", ++ (char*)parse_current->data); + cil_destroy_condblock(cb); + return rc; + } +@@ -3079,8 +3035,7 @@ int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad %s declaration at line %d of %s\n", +- (char*)parse_current->data, parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", (char*)parse_current->data); + cil_destroy_alias(alias); + cil_clear_node(ast_node); + return rc; +@@ -3137,8 +3092,7 @@ int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad %s association at line %d of %s\n", +- cil_node_to_string(parse_current),parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad %s association", cil_node_to_string(parse_current)); + cil_clear_node(ast_node); + return rc; + } +@@ -3187,8 +3141,7 @@ int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_curr + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad typeattributeset statement at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad typeattributeset statement"); + cil_destroy_typeattributeset(attrset); + return rc; + } +@@ -3235,8 +3188,7 @@ int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_curren + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad typepermissive declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad typepermissive declaration"); + cil_destroy_typepermissive(typeperm); + return rc; + } +@@ -3319,8 +3271,7 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad typetransition declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad typetransition declaration"); + return rc; + } + +@@ -3391,8 +3342,7 @@ int cil_gen_rangetransition(struct cil_db *db, struct cil_tree_node *parse_curre + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad rangetransition declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad rangetransition declaration"); + cil_destroy_rangetransition(rangetrans); + return rc; + } +@@ -3443,8 +3393,7 @@ int cil_gen_sensitivity(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad sensitivity declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad sensitivity declaration"); + cil_destroy_sensitivity(sens); + cil_clear_node(ast_node); + return rc; +@@ -3496,8 +3445,7 @@ int cil_gen_category(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad category declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad category declaration"); + cil_destroy_category(cat); + cil_clear_node(ast_node); + return rc; +@@ -3552,8 +3500,7 @@ int cil_gen_catset(struct cil_db *db, struct cil_tree_node *parse_current, struc + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad categoryset declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad categoryset declaration"); + cil_destroy_catset(catset); + cil_clear_node(ast_node); + return rc; +@@ -3614,8 +3561,7 @@ int cil_gen_catorder(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad categoryorder declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad categoryorder declaration"); + cil_destroy_catorder(catorder); + return rc; + } +@@ -3675,8 +3621,7 @@ int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_curr + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad sensitivityorder declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad sensitivityorder declaration"); + cil_destroy_sensitivityorder(sensorder); + return rc; + } +@@ -3730,8 +3675,7 @@ int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad sensitivitycategory declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad sensitivitycategory declaration"); + cil_destroy_senscat(senscat); + return rc; + } +@@ -3786,8 +3730,7 @@ int cil_gen_level(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad level declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad level declaration"); + cil_destroy_level(level); + cil_clear_node(ast_node); + return rc; +@@ -3893,8 +3836,7 @@ int cil_gen_levelrange(struct cil_db *db, struct cil_tree_node *parse_current, s + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad levelrange declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad levelrange declaration"); + cil_destroy_levelrange(lvlrange); + cil_clear_node(ast_node); + return rc; +@@ -3958,8 +3900,7 @@ int cil_gen_constrain(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad constrain declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad constrain declaration"); + cil_destroy_constrain(cons); + return rc; + } +@@ -4013,8 +3954,7 @@ int cil_gen_validatetrans(struct cil_db *db, struct cil_tree_node *parse_current + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad validatetrans declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad validatetrans declaration"); + cil_destroy_validatetrans(validtrans); + return rc; + +@@ -4118,8 +4058,7 @@ int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad context declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad context declaration"); + cil_destroy_context(context); + cil_clear_node(ast_node); + return SEPOL_ERR; +@@ -4211,8 +4150,7 @@ int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad filecon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad filecon declaration"); + cil_destroy_filecon(filecon); + return rc; + } +@@ -4261,6 +4199,8 @@ int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, stru + portcon->proto = CIL_PROTOCOL_UDP; + } else if (proto == CIL_KEY_TCP) { + portcon->proto = CIL_PROTOCOL_TCP; ++ } else if (proto == CIL_KEY_DCCP) { ++ portcon->proto = CIL_PROTOCOL_DCCP; + } else { + cil_log(CIL_ERR, "Invalid protocol\n"); + rc = SEPOL_ERR; +@@ -4311,8 +4251,7 @@ int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad portcon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad portcon declaration"); + cil_destroy_portcon(portcon); + return rc; + } +@@ -4393,8 +4332,7 @@ int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad nodecon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad nodecon declaration"); + cil_destroy_nodecon(nodecon); + return rc; + } +@@ -4464,8 +4402,7 @@ int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad genfscon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad genfscon declaration"); + cil_destroy_genfscon(genfscon); + return SEPOL_ERR; + } +@@ -4538,8 +4475,7 @@ int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad netifcon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad netifcon declaration"); + cil_destroy_netifcon(netifcon); + return SEPOL_ERR; + } +@@ -4606,8 +4542,7 @@ int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, stru + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad pirqcon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad pirqcon declaration"); + cil_destroy_pirqcon(pirqcon); + return rc; + } +@@ -4692,8 +4627,7 @@ int cil_gen_iomemcon(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad iomemcon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad iomemcon declaration"); + cil_destroy_iomemcon(iomemcon); + return rc; + } +@@ -4778,8 +4712,7 @@ int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad ioportcon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad ioportcon declaration"); + cil_destroy_ioportcon(ioportcon); + return rc; + } +@@ -4842,8 +4775,7 @@ int cil_gen_pcidevicecon(struct cil_db *db, struct cil_tree_node *parse_current, + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad pcidevicecon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad pcidevicecon declaration"); + cil_destroy_pcidevicecon(pcidevicecon); + return rc; + } +@@ -4903,8 +4835,7 @@ int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad devicetreecon declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad devicetreecon declaration"); + cil_destroy_devicetreecon(devicetreecon); + return rc; + } +@@ -4979,8 +4910,7 @@ int cil_gen_fsuse(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad fsuse declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad fsuse declaration"); + cil_destroy_fsuse(fsuse); + return SEPOL_ERR; + } +@@ -5137,8 +5067,7 @@ int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad macro declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad macro declaration"); + cil_destroy_macro(macro); + cil_clear_node(ast_node); + return SEPOL_ERR; +@@ -5196,8 +5125,7 @@ int cil_gen_call(struct cil_db *db, struct cil_tree_node *parse_current, struct + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad macro call at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad macro call"); + cil_destroy_call(call); + return rc; + } +@@ -5299,8 +5227,7 @@ int cil_gen_optional(struct cil_db *db, struct cil_tree_node *parse_current, str + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad optional at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad optional"); + cil_destroy_optional(optional); + cil_clear_node(ast_node); + return rc; +@@ -5348,8 +5275,7 @@ int cil_gen_policycap(struct cil_db *db, struct cil_tree_node *parse_current, st + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad policycap statement at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad policycap statement"); + cil_destroy_policycap(polcap); + cil_clear_node(ast_node); + return rc; +@@ -5404,8 +5330,7 @@ int cil_gen_ipaddr(struct cil_db *db, struct cil_tree_node *parse_current, struc + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad ipaddr statement at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad ipaddr statement"); + cil_destroy_ipaddr(ipaddr); + cil_clear_node(ast_node); + return rc; +@@ -5609,8 +5534,7 @@ int cil_gen_bounds(struct cil_db *db, struct cil_tree_node *parse_current, struc + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad bounds declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad bounds declaration"); + cil_destroy_bounds(bounds); + return rc; + } +@@ -5671,8 +5595,7 @@ int cil_gen_default(struct cil_tree_node *parse_current, struct cil_tree_node *a + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad %s declaration at line %d of %s\n", +- cil_node_to_string(parse_current), parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", cil_node_to_string(parse_current)); + cil_destroy_default(def); + return rc; + } +@@ -5758,8 +5681,7 @@ int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_no + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad defaultrange declaration at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad defaultrange declaration"); + cil_destroy_defaultrange(def); + return rc; + } +@@ -5819,8 +5741,7 @@ int cil_gen_handleunknown(struct cil_tree_node *parse_current, struct cil_tree_n + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad handleunknown at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad handleunknown"); + cil_destroy_handleunknown(unknown); + return rc; + } +@@ -5868,8 +5789,7 @@ int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_n + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad mls at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Bad mls"); + cil_destroy_mls(mls); + return rc; + } +@@ -5879,6 +5799,27 @@ void cil_destroy_mls(struct cil_mls *mls) + free(mls); + } + ++int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node) ++{ ++ /* No need to check syntax, because this is auto generated */ ++ struct cil_src_info *info = NULL; ++ ++ cil_src_info_init(&info); ++ ++ info->is_cil = (parse_current->next->data == CIL_KEY_SRC_CIL) ? CIL_TRUE : CIL_FALSE; ++ info->path = parse_current->next->next->data; ++ ++ ast_node->data = info; ++ ast_node->flavor = CIL_SRC_INFO; ++ ++ return SEPOL_OK; ++} ++ ++void cil_destroy_src_info(struct cil_src_info *info) ++{ ++ free(info); ++} ++ + int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *finished, void *extra_args) + { + struct cil_args_build *args = NULL; +@@ -5913,7 +5854,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + if (parse_current->parent->parent == NULL) { + rc = SEPOL_OK; + } else { +- cil_log(CIL_ERR, "Keyword expected after open parenthesis in line %d of %s\n", parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Keyword expected after open parenthesis"); + } + goto exit; + } +@@ -5926,7 +5867,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + parse_current->data == CIL_KEY_BLOCKINHERIT || + parse_current->data == CIL_KEY_BLOCKABSTRACT) { + rc = SEPOL_ERR; +- cil_log(CIL_ERR, "%s is not allowed in macros (%s:%d)\n", (char *)parse_current->data, parse_current->path, parse_current->line); ++ cil_tree_log(parse_current, CIL_ERR, "%s is not allowed in macros", (char *)parse_current->data); + goto exit; + } + } +@@ -5942,8 +5883,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + parse_current->data != CIL_KEY_TYPECHANGE && + parse_current->data != CIL_KEY_CALL) { + rc = SEPOL_ERR; +- cil_log(CIL_ERR, "Found %s at line %d of %s\n", +- (char*)parse_current->data, parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Found %s", (char*)parse_current->data); + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { + cil_log(CIL_ERR, "%s cannot be defined within tunableif statement (treated as a booleanif due to preserve-tunables)\n", + (char*)parse_current->data); +@@ -5958,8 +5898,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + if (tunif != NULL) { + if (parse_current->data == CIL_KEY_TUNABLE) { + rc = SEPOL_ERR; +- cil_log(CIL_ERR, "Found tunable at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Found tunable"); + cil_log(CIL_ERR, "Tunables cannot be defined within tunableif statement\n"); + goto exit; + } +@@ -5968,8 +5907,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + if (in != NULL) { + if (parse_current->data == CIL_KEY_IN) { + rc = SEPOL_ERR; +- cil_log(CIL_ERR, "Found in-statement at line %d of %s\n", +- parse_current->line, parse_current->path); ++ cil_tree_log(parse_current, CIL_ERR, "Found in-statement"); + cil_log(CIL_ERR, "in-statements cannot be defined within in-statements\n"); + goto exit; + } +@@ -5979,7 +5917,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + + ast_node->parent = ast_current; + ast_node->line = parse_current->line; +- ast_node->path = parse_current->path; ++ ast_node->hll_line = parse_current->hll_line; + + if (parse_current->data == CIL_KEY_BLOCK) { + rc = cil_gen_block(db, parse_current, ast_node, 0); +@@ -6242,8 +6180,10 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + } else if (parse_current->data == CIL_KEY_MLS) { + rc = cil_gen_mls(parse_current, ast_node); + *finished = CIL_TREE_SKIP_NEXT; ++ } else if (parse_current->data == CIL_KEY_SRC_INFO) { ++ rc = cil_gen_src_info(parse_current, ast_node); + } else { +- cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char*)parse_current->data); ++ cil_log(CIL_ERR, "Error: Unknown keyword %s\n", (char *)parse_current->data); + rc = SEPOL_ERR; + } + +@@ -6264,7 +6204,7 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f + if (ast_current->flavor == CIL_IN) { + args->in = ast_current; + } +- ++ + ast_current->cl_head = ast_node; + } else { + ast_current->cl_tail->next = ast_node; +diff --git libsepol-2.5/cil/src/cil_build_ast.h libsepol-2.5/cil/src/cil_build_ast.h +index f428394..825029e 100644 +--- libsepol-2.5/cil/src/cil_build_ast.h ++++ libsepol-2.5/cil/src/cil_build_ast.h +@@ -215,6 +215,8 @@ int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_n + void cil_destroy_mls(struct cil_mls *mls); + int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node); + void cil_destroy_defaultrange(struct cil_defaultrange *def); ++int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node); ++void cil_destroy_src_info(struct cil_src_info *info); + + int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats); + void cil_destroy_cats(struct cil_cats *cats); +diff --git libsepol-2.5/cil/src/cil_copy_ast.c libsepol-2.5/cil/src/cil_copy_ast.c +index 0be1dda..5debd0d 100644 +--- libsepol-2.5/cil/src/cil_copy_ast.c ++++ libsepol-2.5/cil/src/cil_copy_ast.c +@@ -1666,6 +1666,21 @@ int cil_copy_bounds(__attribute__((unused)) struct cil_db *db, void *data, void + return SEPOL_OK; + } + ++int cil_copy_src_info(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab) ++{ ++ struct cil_src_info *orig = data; ++ struct cil_src_info *new = NULL; ++ ++ cil_src_info_init(&new); ++ ++ new->is_cil = orig->is_cil; ++ new->path = orig->path; ++ ++ *copy = new; ++ ++ return SEPOL_OK; ++} ++ + int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) uint32_t *finished, void *extra_args) + { + int rc = SEPOL_ERR; +@@ -1942,6 +1957,9 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + case CIL_MLS: + copy_func = &cil_copy_mls; + break; ++ case CIL_SRC_INFO: ++ copy_func = &cil_copy_src_info; ++ break; + default: + goto exit; + } +@@ -1964,7 +1982,7 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + + new->parent = parent; + new->line = orig->line; +- new->path = orig->path; ++ new->hll_line = orig->hll_line; + new->flavor = orig->flavor; + new->data = data; + +@@ -1985,8 +2003,8 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u + param = item->data; + if (param->flavor == new->flavor) { + if (param->str == ((struct cil_symtab_datum*)new->data)->name) { +- cil_log(CIL_ERR, "%s %s shadows a macro parameter (%s line:%d)\n", cil_node_to_string(new), ((struct cil_symtab_datum*)orig->data)->name, orig->path, orig->line); +- cil_log(CIL_ERR, "Note: macro declaration (%s line:%d)\n", namespace->path, namespace->line); ++ cil_tree_log(orig, CIL_ERR, "%s %s shadows a macro parameter", cil_node_to_string(new), ((struct cil_symtab_datum*)orig->data)->name); ++ cil_tree_log(namespace, CIL_ERR, "Note: macro declaration"); + rc = SEPOL_ERR; + goto exit; + } +diff --git libsepol-2.5/cil/src/cil_find.c libsepol-2.5/cil/src/cil_find.c +index 75de886..4134242 100644 +--- libsepol-2.5/cil/src/cil_find.c ++++ libsepol-2.5/cil/src/cil_find.c +@@ -69,7 +69,11 @@ static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_dat + /* Both are attributes */ + struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1; + struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2; +- return ebitmap_match_any(a1->types, a2->types); ++ if (d1 == d2) { ++ return CIL_TRUE; ++ } else if (ebitmap_match_any(a1->types, a2->types)) { ++ return CIL_TRUE; ++ } + } + return CIL_FALSE; + } +@@ -379,7 +383,7 @@ int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flav + + rc = cil_tree_walk(current, __cil_find_matching_avrule_in_ast, NULL, NULL, &args); + if (rc) { +- cil_log(CIL_ERR, "An error occured while searching for avrule in AST\n"); ++ cil_log(CIL_ERR, "An error occurred while searching for avrule in AST\n"); + } + + return rc; +diff --git libsepol-2.5/cil/src/cil_flavor.h libsepol-2.5/cil/src/cil_flavor.h +index 9fb5083..cd08b97 100644 +--- libsepol-2.5/cil/src/cil_flavor.h ++++ libsepol-2.5/cil/src/cil_flavor.h +@@ -111,6 +111,7 @@ enum cil_flavor { + CIL_DEFAULTRANGE, + CIL_HANDLEUNKNOWN, + CIL_MLS, ++ CIL_SRC_INFO, + + /* + * boolean constraint set catset +diff --git libsepol-2.5/cil/src/cil_fqn.c libsepol-2.5/cil/src/cil_fqn.c +index 865bd7d..dad1347 100644 +--- libsepol-2.5/cil/src/cil_fqn.c ++++ libsepol-2.5/cil/src/cil_fqn.c +@@ -121,7 +121,7 @@ static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, has + + exit: + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR,"Problem qualifying names in block at line %d of %s\n", child_args.node->line, child_args.node->path); ++ cil_tree_log(child_args.node, CIL_ERR,"Problem qualifying names in block"); + } + + return rc; +diff --git libsepol-2.5/cil/src/cil_internal.h libsepol-2.5/cil/src/cil_internal.h +index a0a5480..5875dc9 100644 +--- libsepol-2.5/cil/src/cil_internal.h ++++ libsepol-2.5/cil/src/cil_internal.h +@@ -101,6 +101,7 @@ char *CIL_KEY_OBJECT_R; + char *CIL_KEY_STAR; + char *CIL_KEY_TCP; + char *CIL_KEY_UDP; ++char *CIL_KEY_DCCP; + char *CIL_KEY_AUDITALLOW; + char *CIL_KEY_TUNABLEIF; + char *CIL_KEY_ALLOW; +@@ -225,6 +226,9 @@ char *CIL_KEY_NEVERALLOWX; + char *CIL_KEY_PERMISSIONX; + char *CIL_KEY_IOCTL; + char *CIL_KEY_UNORDERED; ++char *CIL_KEY_SRC_INFO; ++char *CIL_KEY_SRC_CIL; ++char *CIL_KEY_SRC_HLL; + + /* + Symbol Table Array Indices +@@ -713,7 +717,8 @@ struct cil_filecon { + + enum cil_protocol { + CIL_PROTOCOL_UDP = 1, +- CIL_PROTOCOL_TCP ++ CIL_PROTOCOL_TCP, ++ CIL_PROTOCOL_DCCP + }; + + struct cil_portcon { +@@ -915,6 +920,11 @@ struct cil_mls { + int value; + }; + ++struct cil_src_info { ++ int is_cil; ++ char *path; ++}; ++ + void cil_db_init(struct cil_db **db); + void cil_db_destroy(struct cil_db **db); + +@@ -1017,6 +1027,7 @@ void cil_default_init(struct cil_default **def); + void cil_defaultrange_init(struct cil_defaultrange **def); + void cil_handleunknown_init(struct cil_handleunknown **unk); + void cil_mls_init(struct cil_mls **mls); ++void cil_src_info_init(struct cil_src_info **info); + void cil_userattribute_init(struct cil_userattribute **attribute); + void cil_userattributeset_init(struct cil_userattributeset **attrset); + +diff --git libsepol-2.5/cil/src/cil_lexer.h libsepol-2.5/cil/src/cil_lexer.h +index 1537d5e..ab555d8 100644 +--- libsepol-2.5/cil/src/cil_lexer.h ++++ libsepol-2.5/cil/src/cil_lexer.h +@@ -37,8 +37,10 @@ + #define SYMBOL 3 + #define QSTRING 4 + #define COMMENT 5 +-#define END_OF_FILE 6 +-#define UNKNOWN 7 ++#define HLL_LINEMARK 6 ++#define NEWLINE 7 ++#define END_OF_FILE 8 ++#define UNKNOWN 9 + + struct token { + uint32_t type; +diff --git libsepol-2.5/cil/src/cil_lexer.l libsepol-2.5/cil/src/cil_lexer.l +index 8e4c207..e28c33e 100644 +--- libsepol-2.5/cil/src/cil_lexer.l ++++ libsepol-2.5/cil/src/cil_lexer.l +@@ -50,15 +50,17 @@ symbol ({digit}|{alpha}|{spec_char})+ + white [ \t] + newline [\n\r] + qstring \"[^"\n]*\" +-comment ;[^\n]* ++hll_lm ^;;\* ++comment ; + + %% +-{newline} line++; ++{newline} line++; return NEWLINE; ++{hll_lm} value=yytext; return HLL_LINEMARK; + {comment} value=yytext; return COMMENT; + "(" value=yytext; return OPAREN; +-")" value=yytext; return CPAREN; ++")" value=yytext; return CPAREN; + {symbol} value=yytext; return SYMBOL; +-{white} //cil_log(CIL_INFO, "white, "); ++{white} ; + {qstring} value=yytext; return QSTRING; + <> return END_OF_FILE; + . value=yytext; return UNKNOWN; +@@ -73,7 +75,7 @@ int cil_lexer_setup(char *buffer, uint32_t size) + } + + line = 1; +- ++ + return SEPOL_OK; + } + +@@ -87,7 +89,6 @@ int cil_lexer_next(struct token *tok) + tok->type = yylex(); + tok->value = value; + tok->line = line; +- ++ + return SEPOL_OK; + } +- +diff --git libsepol-2.5/cil/src/cil_parser.c libsepol-2.5/cil/src/cil_parser.c +index d0e108c..101520c 100644 +--- libsepol-2.5/cil/src/cil_parser.c ++++ libsepol-2.5/cil/src/cil_parser.c +@@ -36,9 +36,165 @@ + #include "cil_internal.h" + #include "cil_log.h" + #include "cil_mem.h" +-#include "cil_tree.h" ++#include "cil_tree.h" + #include "cil_lexer.h" + #include "cil_strpool.h" ++#include "cil_stack.h" ++ ++char *CIL_KEY_HLL_LMS; ++char *CIL_KEY_HLL_LMX; ++char *CIL_KEY_HLL_LME; ++ ++struct hll_info { ++ int hll_lineno; ++ int hll_expand; ++}; ++ ++static void push_hll_info(struct cil_stack *stack, int hll_lineno, int hll_expand) ++{ ++ struct hll_info *new = cil_malloc(sizeof(*new)); ++ ++ new->hll_lineno = hll_lineno; ++ new->hll_expand = hll_expand; ++ ++ cil_stack_push(stack, CIL_NONE, new); ++} ++ ++static void pop_hll_info(struct cil_stack *stack, int *hll_lineno, int *hll_expand) ++{ ++ struct cil_stack_item *curr = cil_stack_pop(stack); ++ struct cil_stack_item *prev = cil_stack_peek(stack); ++ struct hll_info *old; ++ ++ free(curr->data); ++ ++ if (!prev) { ++ *hll_lineno = -1; ++ *hll_expand = -1; ++ } else { ++ old = prev->data; ++ *hll_lineno = old->hll_lineno; ++ *hll_expand = old->hll_expand; ++ } ++} ++ ++static void create_node(struct cil_tree_node **node, struct cil_tree_node *current, int line, int hll_line, void *value) ++{ ++ cil_tree_node_init(node); ++ (*node)->parent = current; ++ (*node)->flavor = CIL_NODE; ++ (*node)->line = line; ++ (*node)->hll_line = hll_line; ++ (*node)->data = value; ++} ++ ++static void insert_node(struct cil_tree_node *node, struct cil_tree_node *current) ++{ ++ if (current->cl_head == NULL) { ++ current->cl_head = node; ++ } else { ++ current->cl_tail->next = node; ++ } ++ current->cl_tail = node; ++} ++ ++static int add_hll_linemark(struct cil_tree_node **current, int *hll_lineno, int *hll_expand, struct cil_stack *stack, char *path) ++{ ++ char *hll_type; ++ struct cil_tree_node *node; ++ struct token tok; ++ char *hll_file; ++ char *end = NULL; ++ ++ cil_lexer_next(&tok); ++ hll_type = cil_strpool_add(tok.value); ++ if (hll_type == CIL_KEY_HLL_LME) { ++ if (cil_stack_is_empty(stack)) { ++ cil_log(CIL_ERR, "Line mark end without start\n"); ++ goto exit; ++ } ++ pop_hll_info(stack, hll_lineno, hll_expand); ++ *current = (*current)->parent; ++ } else { ++ create_node(&node, *current, tok.line, *hll_lineno, NULL); ++ insert_node(node, *current); ++ *current = node; ++ ++ create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_INFO); ++ insert_node(node, *current); ++ ++ create_node(&node, *current, tok.line, *hll_lineno, CIL_KEY_SRC_HLL); ++ insert_node(node, *current); ++ ++ if (hll_type == CIL_KEY_HLL_LMS) { ++ *hll_expand = 0; ++ } else if (hll_type == CIL_KEY_HLL_LMX) { ++ *hll_expand = 1; ++ } else { ++ cil_log(CIL_ERR, "Invalid line mark syntax\n"); ++ goto exit; ++ } ++ ++ cil_lexer_next(&tok); ++ if (tok.type != SYMBOL) { ++ cil_log(CIL_ERR, "Invalid line mark syntax\n"); ++ goto exit; ++ } ++ *hll_lineno = strtol(tok.value, &end, 10); ++ if (errno == ERANGE || *end != '\0') { ++ cil_log(CIL_ERR, "Problem parsing line number for line mark\n"); ++ goto exit; ++ } ++ ++ push_hll_info(stack, *hll_lineno, *hll_expand); ++ ++ cil_lexer_next(&tok); ++ if (tok.type != SYMBOL && tok.type != QSTRING) { ++ cil_log(CIL_ERR, "Invalid line mark syntax\n"); ++ goto exit; ++ } ++ ++ if (tok.type == QSTRING) { ++ tok.value[strlen(tok.value) - 1] = '\0'; ++ tok.value = tok.value+1; ++ } ++ ++ hll_file = cil_strpool_add(tok.value); ++ ++ create_node(&node, *current, tok.line, *hll_lineno, hll_file); ++ insert_node(node, *current); ++ } ++ ++ cil_lexer_next(&tok); ++ if (tok.type != NEWLINE) { ++ cil_log(CIL_ERR, "Invalid line mark syntax\n"); ++ goto exit; ++ } ++ ++ return SEPOL_OK; ++ ++exit: ++ cil_log(CIL_ERR, "Problem with high-level line mark at line %d of %s\n", tok.line, path); ++ return SEPOL_ERR; ++} ++ ++static void add_cil_path(struct cil_tree_node **current, char *path) ++{ ++ struct cil_tree_node *node; ++ ++ create_node(&node, *current, 0, 0, NULL); ++ insert_node(node, *current); ++ *current = node; ++ ++ create_node(&node, *current, 0, 0, CIL_KEY_SRC_INFO); ++ insert_node(node, *current); ++ ++ create_node(&node, *current, 0, 0, CIL_KEY_SRC_CIL); ++ insert_node(node, *current); ++ ++ create_node(&node, *current, 0, 0, path); ++ insert_node(node, *current); ++} + + int cil_parser(char *_path, char *buffer, uint32_t size, struct cil_tree **parse_tree) + { +@@ -47,89 +203,112 @@ int cil_parser(char *_path, char *buffer, uint32_t size, struct cil_tree **parse + + struct cil_tree *tree = NULL; + struct cil_tree_node *node = NULL; +- struct cil_tree_node *item = NULL; + struct cil_tree_node *current = NULL; + char *path = cil_strpool_add(_path); +- ++ struct cil_stack *stack; ++ int hll_lineno = -1; ++ int hll_expand = -1; + struct token tok; ++ int rc = SEPOL_OK; ++ ++ CIL_KEY_HLL_LMS = cil_strpool_add("lms"); ++ CIL_KEY_HLL_LMX = cil_strpool_add("lmx"); ++ CIL_KEY_HLL_LME = cil_strpool_add("lme"); ++ ++ cil_stack_init(&stack); + + cil_lexer_setup(buffer, size); + + tree = *parse_tree; +- current = tree->root; ++ current = tree->root; ++ ++ add_cil_path(¤t, path); + + do { + cil_lexer_next(&tok); + switch (tok.type) { ++ case HLL_LINEMARK: ++ rc = add_hll_linemark(¤t, &hll_lineno, &hll_expand, stack, path); ++ if (rc != SEPOL_OK) { ++ goto exit; ++ } ++ break; + case OPAREN: + paren_count++; +- cil_tree_node_init(&node); +- node->parent = current; +- node->flavor = CIL_NODE; +- node->line = tok.line; +- node->path = path; +- if (current->cl_head == NULL) { +- current->cl_head = node; +- } else { +- current->cl_tail->next = node; +- } +- current->cl_tail = node; ++ ++ create_node(&node, current, tok.line, hll_lineno, NULL); ++ insert_node(node, current); + current = node; + break; + case CPAREN: + paren_count--; + if (paren_count < 0) { + cil_log(CIL_ERR, "Close parenthesis without matching open at line %d of %s\n", tok.line, path); +- return SEPOL_ERR; ++ goto exit; + } + current = current->parent; + break; +- case SYMBOL: + case QSTRING: ++ tok.value[strlen(tok.value) - 1] = '\0'; ++ tok.value = tok.value+1; ++ case SYMBOL: + if (paren_count == 0) { + cil_log(CIL_ERR, "Symbol not inside parenthesis at line %d of %s\n", tok.line, path); +- return SEPOL_ERR; ++ goto exit; + } +- cil_tree_node_init(&item); +- item->parent = current; +- if (tok.type == QSTRING) { +- tok.value[strlen(tok.value) - 1] = '\0'; +- item->data = cil_strpool_add(tok.value + 1); +- } else { +- item->data = cil_strpool_add(tok.value); +- } +- item->flavor = CIL_NODE; +- item->line = tok.line; +- item->path = path; +- if (current->cl_head == NULL) { +- current->cl_head = item; +- } else { +- current->cl_tail->next = item; ++ ++ create_node(&node, current, tok.line, hll_lineno, cil_strpool_add(tok.value)); ++ insert_node(node, current); ++ break; ++ case NEWLINE : ++ if (!hll_expand) { ++ hll_lineno++; + } +- current->cl_tail = item; + break; ++ case COMMENT: ++ while (tok.type != NEWLINE && tok.type != END_OF_FILE) { ++ cil_lexer_next(&tok); ++ } ++ if (!hll_expand) { ++ hll_lineno++; ++ } ++ if (tok.type != END_OF_FILE) { ++ break; ++ } ++ // Fall through if EOF + case END_OF_FILE: + if (paren_count > 0) { + cil_log(CIL_ERR, "Open parenthesis without matching close at line %d of %s\n", tok.line, path); +- return SEPOL_ERR; ++ goto exit; ++ } ++ if (!cil_stack_is_empty(stack)) { ++ cil_log(CIL_ERR, "High-level language line marker start without close at line %d of %s\n", tok.line, path); ++ goto exit; + } +- break; +- case COMMENT: +- // ignore + break; + case UNKNOWN: + cil_log(CIL_ERR, "Invalid token '%s' at line %d of %s\n", tok.value, tok.line, path); +- return SEPOL_ERR; ++ goto exit; + default: + cil_log(CIL_ERR, "Unknown token type '%d' at line %d of %s\n", tok.type, tok.line, path); +- return SEPOL_ERR; ++ goto exit; + } + } + while (tok.type != END_OF_FILE); + + cil_lexer_destroy(); + ++ cil_stack_destroy(&stack); ++ + *parse_tree = tree; + + return SEPOL_OK; ++ ++exit: ++ while (!cil_stack_is_empty(stack)) { ++ pop_hll_info(stack, &hll_lineno, &hll_expand); ++ } ++ cil_stack_destroy(&stack); ++ ++ return SEPOL_ERR; + } +diff --git libsepol-2.5/cil/src/cil_policy.c libsepol-2.5/cil/src/cil_policy.c +index 2c9b158..382129b 100644 +--- libsepol-2.5/cil/src/cil_policy.c ++++ libsepol-2.5/cil/src/cil_policy.c +@@ -123,6 +123,8 @@ int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort) + fprintf(file_arr[NETIFCONS], "udp "); + } else if (portcon->proto == CIL_PROTOCOL_TCP) { + fprintf(file_arr[NETIFCONS], "tcp "); ++ } else if (portcon->proto == CIL_PROTOCOL_DCCP) { ++ fprintf(file_arr[NETIFCONS], "dccp "); + } + fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low); + fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high); +diff --git libsepol-2.5/cil/src/cil_reset_ast.c libsepol-2.5/cil/src/cil_reset_ast.c +index 06146ca..de00679 100644 +--- libsepol-2.5/cil/src/cil_reset_ast.c ++++ libsepol-2.5/cil/src/cil_reset_ast.c +@@ -23,7 +23,7 @@ static void cil_reset_class(struct cil_class *class) + { + if (class->common != NULL) { + struct cil_class *common = class->common; +- cil_symtab_map(&common->perms, __class_reset_perm_values, &common->num_perms); ++ cil_symtab_map(&class->perms, __class_reset_perm_values, &common->num_perms); + /* during a re-resolve, we need to reset the common, so a classcommon + * statement isn't seen as a duplicate */ + class->num_perms -= common->num_perms; +diff --git libsepol-2.5/cil/src/cil_resolve_ast.c libsepol-2.5/cil/src/cil_resolve_ast.c +index 1489680..8348d57 100644 +--- libsepol-2.5/cil/src/cil_resolve_ast.c ++++ libsepol-2.5/cil/src/cil_resolve_ast.c +@@ -131,10 +131,10 @@ static int __cil_resolve_perms(symtab_t *class_symtab, symtab_t *common_symtab, + } + } + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Failed to resolve permission %s\n", (char*)curr->data); +- goto exit; ++ cil_log(CIL_WARN, "Failed to resolve permission %s\n", (char*)curr->data); ++ } else { ++ cil_list_append(*perm_datums, CIL_DATUM, perm_datum); + } +- cil_list_append(*perm_datums, CIL_DATUM, perm_datum); + } else { + cil_list_append(*perm_datums, curr->flavor, curr->data); + } +@@ -497,7 +497,7 @@ int cil_resolve_alias_to_actual(struct cil_tree_node *current, enum cil_flavor f + int limit = 2; + + if (alias->actual == NULL) { +- cil_log(CIL_ERR, "Alias declared but not used at line %d of %s\n",current->line, current->path); ++ cil_tree_log(current, CIL_ERR, "Alias declared but not used"); + return SEPOL_ERR; + } + +@@ -1380,7 +1380,7 @@ struct cil_list *__cil_ordered_lists_merge_all(struct cil_list **ordered_lists, + cil_list_for_each(curr, *ordered_lists) { + struct cil_ordered_list *ordered_list = curr->data; + if (ordered_list->merged == CIL_FALSE) { +- cil_log(CIL_ERR, "Unable to merge ordered list at line %d of %s\n",ordered_list->node->line, ordered_list->node->path); ++ cil_tree_log(ordered_list->node, CIL_ERR, "Unable to merge ordered list"); + } + } + goto exit; +@@ -2252,12 +2252,10 @@ void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_ + + cil_list_for_each(item, trace) { + curr = item->data; +- cil_log(CIL_ERR, " %s:%d: ", curr->path, curr->line); +- + if (curr->flavor == CIL_BLOCK) { +- cil_log(CIL_ERR, "block %s\n", DATUM(curr->data)->name); ++ cil_tree_log(curr, CIL_ERR, "block %s", DATUM(curr->data)->name); + } else { +- cil_log(CIL_ERR, "blockinherit %s\n", ((struct cil_blockinherit *)curr->data)->block_str); ++ cil_tree_log(curr, CIL_ERR, "blockinherit %s", ((struct cil_blockinherit *)curr->data)->block_str); + } + } + +@@ -2442,7 +2440,7 @@ int cil_resolve_in_list(void *extra_args) + } + + if (unresolved > 0 && resolved == 0) { +- cil_log(CIL_ERR, "Failed to resolve in-statement on line %d of %s\n", last_failed_node->line, last_failed_node->path); ++ cil_tree_log(last_failed_node, CIL_ERR, "Failed to resolve in-statement"); + rc = SEPOL_ERR; + goto exit; + } +@@ -2485,7 +2483,7 @@ int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil + + if (user->bounds != NULL) { + struct cil_tree_node *node = user->bounds->datum.nodes->head->data; +- cil_log(CIL_ERR, "User %s already bound by parent at line %u of %s\n", bounds->child_str, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "User %s already bound by parent", bounds->child_str); + rc = SEPOL_ERR; + goto exit; + } +@@ -2498,7 +2496,7 @@ int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil + + if (role->bounds != NULL) { + struct cil_tree_node *node = role->bounds->datum.nodes->head->data; +- cil_log(CIL_ERR, "Role %s already bound by parent at line %u of %s\n", bounds->child_str, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Role %s already bound by parent", bounds->child_str); + rc = SEPOL_ERR; + goto exit; + } +@@ -2512,8 +2510,8 @@ int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil + + if (type->bounds != NULL) { + node = ((struct cil_symtab_datum *)type->bounds)->nodes->head->data; +- cil_log(CIL_ERR, "Type %s already bound by parent at line %u of %s\n", bounds->child_str, node->line, node->path); +- cil_log(CIL_ERR, "Now being bound to parent %s at line %u of %s\n", bounds->parent_str, current->line, current->path); ++ cil_tree_log(node, CIL_ERR, "Type %s already bound by parent", bounds->child_str); ++ cil_tree_log(current, CIL_ERR, "Now being bound to parent %s", bounds->parent_str); + rc = SEPOL_ERR; + goto exit; + } +@@ -2542,7 +2540,7 @@ int cil_resolve_bounds(struct cil_tree_node *current, void *extra_args, enum cil + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Bad bounds statement at line %u of %s\n", current->line, current->path); ++ cil_tree_log(current, CIL_ERR, "Bad bounds statement"); + return rc; + } + +@@ -2617,12 +2615,10 @@ void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_n + + cil_list_for_each(item, trace) { + curr = item->data; +- cil_log(CIL_ERR, " %s:%d: ", curr->path, curr->line); +- + if (curr->flavor == CIL_MACRO) { +- cil_log(CIL_ERR, "macro %s\n", DATUM(curr->data)->name); ++ cil_tree_log(curr, CIL_ERR, "macro %s", DATUM(curr->data)->name); + } else { +- cil_log(CIL_ERR, "call %s\n", ((struct cil_call *)curr->data)->macro_str); ++ cil_tree_log(curr, CIL_ERR, "call %s", ((struct cil_call *)curr->data)->macro_str); + } + } + +@@ -2700,7 +2696,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) + struct cil_tree_node *pc = NULL; + + if (new_call->args_tree == NULL) { +- cil_log(CIL_ERR, "Missing arguments (%s, line: %d)\n", current->path, current->line); ++ cil_tree_log(current, CIL_ERR, "Missing arguments"); + rc = SEPOL_ERR; + goto exit; + } +@@ -2713,7 +2709,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) + enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor; + + if (pc == NULL) { +- cil_log(CIL_ERR, "Missing arguments (%s, line: %d)\n", current->path, current->line); ++ cil_tree_log(current, CIL_ERR, "Missing arguments"); + rc = SEPOL_ERR; + goto exit; + } +@@ -2890,12 +2886,12 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args) + } + + if (pc != NULL) { +- cil_log(CIL_ERR, "Unexpected arguments (%s, line: %d)\n", current->path, current->line); ++ cil_tree_log(current, CIL_ERR, "Unexpected arguments"); + rc = SEPOL_ERR; + goto exit; + } + } else if (new_call->args_tree != NULL) { +- cil_log(CIL_ERR, "Unexpected arguments (%s, line: %d)\n", current->path, current->line); ++ cil_tree_log(current, CIL_ERR, "Unexpected arguments"); + rc = SEPOL_ERR; + goto exit; + } +@@ -3593,7 +3589,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + if (optstack != NULL) { + if (node->flavor == CIL_TUNABLE || node->flavor == CIL_MACRO) { + /* tuanbles and macros are not allowed in optionals*/ +- cil_log(CIL_ERR, "%s statement is not allowed in optionals (%s:%d)\n", cil_node_to_string(node), node->path, node->line); ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in optionals", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } +@@ -3601,7 +3597,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + + if (blockstack != NULL) { + if (node->flavor == CIL_CAT || node->flavor == CIL_SENS) { +- cil_log(CIL_ERR, "%s statement is not allowed in blocks (%s:%d)\n", cil_node_to_string(node), node->path, node->line); ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in blocks", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } +@@ -3612,7 +3608,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + node->flavor == CIL_BLOCK || + node->flavor == CIL_BLOCKABSTRACT || + node->flavor == CIL_MACRO) { +- cil_log(CIL_ERR, "%s statement is not allowed in macros (%s:%d)\n", cil_node_to_string(node), node->path, node->line); ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in macros", cil_node_to_string(node)); + rc = SEPOL_ERR; + goto exit; + } +@@ -3626,9 +3622,9 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + node->flavor == CIL_TUNABLEIF || + node->flavor == CIL_NAMETYPETRANSITION)) { + if (((struct cil_booleanif*)boolif->data)->preserved_tunable) { +- cil_log(CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif) (%s:%d)\n", cil_node_to_string(node), node->path, node->line); ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs (tunableif treated as a booleanif)", cil_node_to_string(node)); + } else { +- cil_log(CIL_ERR, "%s statement is not allowed in booleanifs (%s:%d)\n", cil_node_to_string(node), node->path, node->line); ++ cil_tree_log(node, CIL_ERR, "%s statement is not allowed in booleanifs", cil_node_to_string(node)); + } + rc = SEPOL_ERR; + goto exit; +@@ -3658,14 +3654,13 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished + + struct cil_optional *opt = (struct cil_optional *)optstack->data; + struct cil_tree_node *opt_node = opt->datum.nodes->head->data; +- cil_log(lvl, "Disabling optional '%s' at line %d of %s: ", opt->datum.name, opt_node->line, opt_node->path); ++ cil_tree_log(opt_node, lvl, "Disabling optional '%s'", opt->datum.name); + /* disable an optional if something failed to resolve */ + opt->enabled = CIL_FALSE; + rc = SEPOL_OK; + } + +- cil_log(lvl, "Failed to resolve '%s' in %s statement at line %d of %s\n", +- args->last_resolved_name, cil_node_to_string(node), node->line, node->path); ++ cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node)); + goto exit; + } + +diff --git libsepol-2.5/cil/src/cil_tree.c libsepol-2.5/cil/src/cil_tree.c +index 1c23efc..9ff9d4b 100644 +--- libsepol-2.5/cil/src/cil_tree.c ++++ libsepol-2.5/cil/src/cil_tree.c +@@ -59,6 +59,92 @@ __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_tree_e + exit(1); + } + ++struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **path, int* is_cil) ++{ ++ if (!node) { ++ return NULL; ++ } ++ ++ node = node->parent; ++ ++ while (node) { ++ if (node->flavor == CIL_NODE && node->data == NULL) { ++ if (node->cl_head->data == CIL_KEY_SRC_INFO) { ++ /* Parse Tree */ ++ *path = node->cl_head->next->next->data; ++ *is_cil = (node->cl_head->next->data == CIL_KEY_SRC_CIL); ++ return node; ++ } ++ node = node->parent; ++ } else if (node->flavor == CIL_SRC_INFO) { ++ /* AST */ ++ struct cil_src_info *info = node->data; ++ *path = info->path; ++ *is_cil = info->is_cil; ++ return node; ++ } else { ++ if (node->flavor == CIL_CALL) { ++ struct cil_call *call = node->data; ++ node = NODE(call->macro); ++ } else if (node->flavor == CIL_BLOCKINHERIT) { ++ struct cil_blockinherit *inherit = node->data; ++ node = NODE(inherit->block); ++ } else { ++ node = node->parent; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++char *cil_tree_get_cil_path(struct cil_tree_node *node) ++{ ++ char *path = NULL; ++ int is_cil; ++ ++ while (node) { ++ node = cil_tree_get_next_path(node, &path, &is_cil); ++ if (node && is_cil) { ++ return path; ++ } ++ } ++ ++ return NULL; ++} ++ ++__attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, msg); ++ cil_vlog(lvl, msg, ap); ++ va_end(ap); ++ ++ if (node) { ++ char *path = NULL; ++ int is_cil; ++ unsigned hll_line = node->hll_line; ++ ++ path = cil_tree_get_cil_path(node); ++ ++ if (path != NULL) { ++ cil_log(lvl, " at %s:%d", path, node->line); ++ } ++ ++ while (node) { ++ node = cil_tree_get_next_path(node, &path, &is_cil); ++ if (node && !is_cil) { ++ cil_log(lvl," from %s:%d", path, hll_line); ++ path = NULL; ++ hll_line = node->hll_line; ++ } ++ } ++ } ++ ++ cil_log(lvl,"\n"); ++} ++ + int cil_tree_init(struct cil_tree **tree) + { + struct cil_tree *new_tree = cil_malloc(sizeof(*new_tree)); +@@ -128,8 +214,8 @@ void cil_tree_node_init(struct cil_tree_node **node) + new_node->data = NULL; + new_node->next = NULL; + new_node->flavor = CIL_ROOT; +- new_node->line = 0; +- new_node->path = NULL; ++ new_node->line = 0; ++ new_node->hll_line = 0; + + *node = new_node; + } +@@ -185,7 +271,7 @@ int cil_tree_walk_core(struct cil_tree_node *node, + if (process_node != NULL) { + rc = (*process_node)(node, &finished, extra_args); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Problem at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_INFO, "Problem"); + return rc; + } + } +@@ -222,7 +308,7 @@ int cil_tree_walk(struct cil_tree_node *node, + if (first_child != NULL) { + rc = (*first_child)(node->cl_head, extra_args); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Problem at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_INFO, "Problem"); + return rc; + } + } +@@ -235,7 +321,7 @@ int cil_tree_walk(struct cil_tree_node *node, + if (last_child != NULL) { + rc = (*last_child)(node->cl_tail, extra_args); + if (rc != SEPOL_OK) { +- cil_log(CIL_INFO, "Problem at line %d of %s\n",node->line, node->path); ++ cil_tree_log(node, CIL_INFO, "Problem"); + return rc; + } + } +@@ -1319,6 +1405,8 @@ void cil_tree_print_node(struct cil_tree_node *node) + cil_log(CIL_INFO, " udp"); + } else if (portcon->proto == CIL_PROTOCOL_TCP) { + cil_log(CIL_INFO, " tcp"); ++ } else if (portcon->proto == CIL_PROTOCOL_DCCP) { ++ cil_log(CIL_INFO, " dccp"); + } + cil_log(CIL_INFO, " (%d %d)", portcon->port_low, portcon->port_high); + +diff --git libsepol-2.5/cil/src/cil_tree.h libsepol-2.5/cil/src/cil_tree.h +index 9bb602f..aeded56 100644 +--- libsepol-2.5/cil/src/cil_tree.h ++++ libsepol-2.5/cil/src/cil_tree.h +@@ -46,10 +46,14 @@ struct cil_tree_node { + struct cil_tree_node *next; //Each element in the list points to the next element + enum cil_flavor flavor; + uint32_t line; +- char *path; ++ uint32_t hll_line; + void *data; + }; + ++struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node, char **path, int* is_cil); ++char *cil_tree_get_cil_path(struct cil_tree_node *node); ++__attribute__((format (printf, 3, 4))) void cil_tree_log(struct cil_tree_node *node, enum cil_log_level lvl, const char* msg, ...); ++ + int cil_tree_init(struct cil_tree **tree); + void cil_tree_destroy(struct cil_tree **tree); + void cil_tree_subtree_destroy(struct cil_tree_node *node); +diff --git libsepol-2.5/cil/src/cil_verify.c libsepol-2.5/cil/src/cil_verify.c +index 36ec45a..038f77a 100644 +--- libsepol-2.5/cil/src/cil_verify.c ++++ libsepol-2.5/cil/src/cil_verify.c +@@ -377,25 +377,25 @@ int __cil_verify_ordered_node_helper(struct cil_tree_node *node, __attribute__(( + if (node->flavor == CIL_SID) { + struct cil_sid *sid = node->data; + if (sid->ordered == CIL_FALSE) { +- cil_log(CIL_ERR, "SID %s not in sidorder statement at line %d of %s\n", sid->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "SID %s not in sidorder statement", sid->datum.name); + return SEPOL_ERR; + } + } else if (node->flavor == CIL_CLASS) { + struct cil_class *class = node->data; + if (class->ordered == CIL_FALSE) { +- cil_log(CIL_ERR, "Class %s not in classorder statement at line %d of %s\n", class->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Class %s not in classorder statement", class->datum.name); + return SEPOL_ERR; + } + } else if (node->flavor == CIL_CAT) { + struct cil_cat *cat = node->data; + if (cat->ordered == CIL_FALSE) { +- cil_log(CIL_ERR, "Category %s not in categoryorder statement at line %d of %s\n", cat->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Category %s not in categoryorder statement", cat->datum.name); + return SEPOL_ERR; + } + } else if (node->flavor == CIL_SENS) { + struct cil_sens *sens = node->data; + if (sens->ordered == CIL_FALSE) { +- cil_log(CIL_ERR, "Sensitivity %s not in sensitivityorder statement at line %d of %s\n", sens->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Sensitivity %s not in sensitivityorder statement", sens->datum.name); + return SEPOL_ERR; + } + } +@@ -430,7 +430,7 @@ int __cil_verify_initsids(struct cil_list *sids) + struct cil_sid *sid = i->data; + if (sid->context == NULL) { + struct cil_tree_node *node = sid->datum.nodes->head->data; +- cil_log(CIL_ERR, "No context assigned to SID %s declared at line %d in %s\n",sid->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "No context assigned to SID %s declared",sid->datum.name); + rc = SEPOL_ERR; + } + } +@@ -598,7 +598,7 @@ int __cil_verify_named_levelrange(struct cil_db *db, struct cil_tree_node *node) + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid named range at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid named range"); + return rc; + } + +@@ -638,7 +638,7 @@ static int __cil_verify_user_pre_eval(struct cil_tree_node *node) + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid user at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid user"); + return rc; + } + +@@ -657,7 +657,7 @@ static int __cil_verify_user_post_eval(struct cil_db *db, struct cil_tree_node * + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid user at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid user"); + return rc; + } + +@@ -688,7 +688,7 @@ int __cil_verify_role(struct cil_tree_node *node) + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid role at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid role"); + return rc; + } + +@@ -719,7 +719,7 @@ int __cil_verify_type(struct cil_tree_node *node) + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid type at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid type"); + return rc; + } + +@@ -813,7 +813,7 @@ int __cil_verify_named_context(struct cil_db *db, struct cil_tree_node *node) + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid named context at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid named context"); + return rc; + } + +@@ -852,8 +852,7 @@ int __cil_verify_rule(struct cil_tree_node *node, struct cil_complex_symtab *sym + struct cil_complex_symtab_datum *datum = NULL; + cil_complex_symtab_search(symtab, &ckey, &datum); + if (datum == NULL) { +- cil_log(CIL_ERR, "Duplicate rule defined on line %d of %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Duplicate rule defined"); + rc = SEPOL_ERR; + goto exit; + } +@@ -861,7 +860,7 @@ int __cil_verify_rule(struct cil_tree_node *node, struct cil_complex_symtab *sym + + return SEPOL_OK; + exit: +- cil_log(CIL_ERR, "Invalid rule at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid rule"); + return rc; + } + +@@ -877,11 +876,9 @@ int __cil_verify_booleanif_helper(struct cil_tree_node *node, __attribute__((unu + avrule = rule_node->data; + if (avrule->rule_kind == CIL_AVRULE_NEVERALLOW) { + if (bif->preserved_tunable) { +- cil_log(CIL_ERR, "Neverallow found in tunableif block (treated as a booleanif due to preserve-tunables) at line %d or %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Neverallow found in tunableif block (treated as a booleanif due to preserve-tunables)"); + } else { +- cil_log(CIL_ERR, "Neverallow found in booleanif block at line %d or %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Neverallow found in booleanif block"); + } + rc = SEPOL_ERR; + goto exit; +@@ -942,11 +939,9 @@ int __cil_verify_booleanif_helper(struct cil_tree_node *node, __attribute__((unu + default: { + const char * flavor = cil_node_to_string(node); + if (bif->preserved_tunable) { +- cil_log(CIL_ERR, "Invalid %s statement in tunableif (treated as a booleanif due to preserve-tunables) at line %d of %s\n", +- flavor, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid %s statement in tunableif (treated as a booleanif due to preserve-tunables)", flavor); + } else { +- cil_log(CIL_ERR, "Invalid %s statement in booleanif at line %d of %s\n", +- flavor, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid %s statement in booleanif", flavor); + } + goto exit; + } +@@ -974,9 +969,9 @@ int __cil_verify_booleanif(struct cil_tree_node *node, struct cil_complex_symtab + return SEPOL_OK; + exit: + if (bif->preserved_tunable) { +- cil_log(CIL_ERR, "Invalid tunableif (treated as a booleanif due to preserve-tunables) at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid tunableif (treated as a booleanif due to preserve-tunables)"); + } else { +- cil_log(CIL_ERR, "Invalid booleanif at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid booleanif"); + } + return rc; + } +@@ -1007,7 +1002,7 @@ int __cil_verify_netifcon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid netifcon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid netifcon"); + return rc; + } + +@@ -1028,7 +1023,7 @@ int __cil_verify_genfscon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid genfscon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid genfscon"); + return rc; + } + +@@ -1047,8 +1042,7 @@ int __cil_verify_filecon(struct cil_db *db, struct cil_tree_node *node) + if (ctx->datum.name == NULL) { + rc = __cil_verify_context(db, ctx); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Invalid filecon at line %d of %s\n", +- node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid filecon"); + goto exit; + } + } +@@ -1076,7 +1070,7 @@ int __cil_verify_nodecon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid nodecon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid nodecon"); + return rc; + } + +@@ -1097,7 +1091,7 @@ int __cil_verify_portcon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid portcon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid portcon"); + return rc; + } + +@@ -1118,7 +1112,7 @@ int __cil_verify_pirqcon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid pirqcon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid pirqcon"); + return rc; + } + +@@ -1139,7 +1133,7 @@ int __cil_verify_iomemcon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid iomemcon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid iomemcon"); + return rc; + } + +@@ -1160,7 +1154,7 @@ int __cil_verify_ioportcon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid ioportcon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid ioportcon"); + return rc; + } + +@@ -1181,7 +1175,7 @@ int __cil_verify_pcidevicecon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid pcidevicecon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid pcidevicecon"); + return rc; + } + +@@ -1202,7 +1196,7 @@ int __cil_verify_devicetreecon(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid devicetreecon at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid devicetreecon"); + return rc; + } + +@@ -1223,7 +1217,7 @@ int __cil_verify_fsuse(struct cil_db *db, struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid fsuse at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid fsuse"); + return rc; + } + +@@ -1241,7 +1235,7 @@ int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tree_node + kind_str = CIL_KEY_IOCTL; + break; + default: +- cil_log(CIL_ERR, "Invalid permissionx kind (%d) at line %d of %s\n", permx->kind, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid permissionx kind (%d)", permx->kind); + rc = SEPOL_ERR; + goto exit; + } +@@ -1257,7 +1251,7 @@ int __cil_verify_permissionx(struct cil_permissionx *permx, struct cil_tree_node + } + + if (rc == SEPOL_ENOENT) { +- cil_log(CIL_ERR, "Invalid permissionx at line %d of %s: %s is not a permission of class %s\n", node->line, node->path, kind_str, class->datum.name); ++ cil_tree_log(node, CIL_ERR, "Invalid permissionx: %s is not a permission of class %s", kind_str, class->datum.name); + rc = SEPOL_ERR; + goto exit; + } +@@ -1312,7 +1306,7 @@ int __cil_verify_class(struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid class at line %d of %s\n", node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid class"); + return rc; + } + +@@ -1329,8 +1323,7 @@ int __cil_verify_policycap(struct cil_tree_node *node) + return SEPOL_OK; + + exit: +- cil_log(CIL_ERR, "Invalid policycap (%s) at line %d of %s\n", +- (const char*)polcap->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Invalid policycap (%s)", (const char*)polcap->datum.name); + return rc; + } + +@@ -1547,14 +1540,14 @@ static int __cil_verify_classpermission(struct cil_tree_node *node) + struct cil_classpermission *cp = node->data; + + if (cp->classperms == NULL) { +- cil_log(CIL_ERR, "Classpermission %s does not have a classpermissionset at line %d of %s\n", cp->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Classpermission %s does not have a classpermissionset", cp->datum.name); + rc = SEPOL_ERR; + goto exit; + } + + rc = __cil_verify_classperms(cp->classperms, &cp->datum); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Found circular class permissions involving the set %s at line %d of %s\n",cp->datum.name, node->line, node->path); ++ cil_tree_log(node, CIL_ERR, "Found circular class permissions involving the set %s",cp->datum.name); + goto exit; + } + +@@ -1577,14 +1570,14 @@ static int __verify_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, + struct cil_perm *cmp = (struct cil_perm *)d; + + if (cmp->classperms == NULL) { +- cil_log(CIL_ERR, "Map class %s does not have a classmapping for %s at line %d of %s\n", map_args->class->datum.name, cmp->datum.name, map_args->node->line, map_args->node->path); ++ cil_tree_log(map_args->node, CIL_ERR, "Map class %s does not have a classmapping for %s", map_args->class->datum.name, cmp->datum.name); + map_args->rc = SEPOL_ERR; + goto exit; + } + + rc = __cil_verify_classperms(cmp->classperms, &cmp->datum); + if (rc != SEPOL_OK) { +- cil_log(CIL_ERR, "Found circular class permissions involving the map class %s and permission %s at line %d of %s\n", map_args->class->datum.name, cmp->datum.name, map_args->node->line, map_args->node->path); ++ cil_tree_log(map_args->node, CIL_ERR, "Found circular class permissions involving the map class %s and permission %s", map_args->class->datum.name, cmp->datum.name); + map_args->rc = SEPOL_ERR; + goto exit; + } +diff --git libsepol-2.5/include/sepol/port_record.h libsepol-2.5/include/sepol/port_record.h +index 697cea4..c07d1fa 100644 +--- libsepol-2.5/include/sepol/port_record.h ++++ libsepol-2.5/include/sepol/port_record.h +@@ -14,6 +14,7 @@ typedef struct sepol_port_key sepol_port_key_t; + + #define SEPOL_PROTO_UDP 0 + #define SEPOL_PROTO_TCP 1 ++#define SEPOL_PROTO_DCCP 2 + + /* Key */ + extern int sepol_port_compare(const sepol_port_t * port, +diff --git libsepol-2.5/src/Makefile libsepol-2.5/src/Makefile +index db6c2ba..b0c901f 100644 +--- libsepol-2.5/src/Makefile ++++ libsepol-2.5/src/Makefile +@@ -18,15 +18,15 @@ TARGET=libsepol.so + LIBPC=libsepol.pc + LIBMAP=libsepol.map + LIBSO=$(TARGET).$(LIBVERSION) +-OBJS= $(patsubst %.c,%.o,$(wildcard *.c)) +-LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c)) ++OBJS= $(patsubst %.c,%.o,$(sort $(wildcard *.c))) ++LOBJS= $(patsubst %.c,%.lo,$(sort $(wildcard *.c))) + CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-format-attribute -O2 + + override CFLAGS += -I. -I../include -D_GNU_SOURCE + + ifneq ($(DISABLE_CIL),y) +-OBJS += $(sort $(patsubst %.c,%.o,$(wildcard $(CILDIR)/src/*.c) $(CIL_GENERATED))) +-LOBJS += $(sort $(patsubst %.c,%.lo,$(wildcard $(CILDIR)/src/*.c) $(CIL_GENERATED))) ++OBJS += $(sort $(patsubst %.c,%.o,$(sort $(wildcard $(CILDIR)/src/*.c)) $(CIL_GENERATED))) ++LOBJS += $(sort $(patsubst %.c,%.lo,$(sort $(wildcard $(CILDIR)/src/*.c)) $(CIL_GENERATED))) + override CFLAGS += -I$(CILDIR)/include + endif + +@@ -76,7 +76,7 @@ relabel: + /sbin/restorecon $(SHLIBDIR)/$(LIBSO) + + clean: +- -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) $(CIL_GENERATED) ++ -rm -f $(LIBPC) $(LIBMAP) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) $(CIL_GENERATED) + + indent: + ../../scripts/Lindent $(wildcard *.[ch]) +diff --git libsepol-2.5/src/assertion.c libsepol-2.5/src/assertion.c +index fbf397f..a4be880 100644 +--- libsepol-2.5/src/assertion.c ++++ libsepol-2.5/src/assertion.c +@@ -147,36 +147,49 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle, + avtab_key_t tmp_key; + avtab_extended_perms_t *xperms; + avtab_extended_perms_t error; ++ ebitmap_t *sattr = &p->type_attr_map[stype]; ++ ebitmap_t *tattr = &p->type_attr_map[ttype]; ++ ebitmap_node_t *snode, *tnode; ++ unsigned int i, j; + int rc = 1; + int ret = 0; + + memcpy(&tmp_key, k, sizeof(avtab_key_t)); + tmp_key.specified = AVTAB_XPERMS_ALLOWED; + +- for (node = avtab_search_node(avtab, &tmp_key); +- node; +- node = avtab_search_node_next(node, tmp_key.specified)) { +- xperms = node->datum.xperms; +- if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) +- && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) ++ ebitmap_for_each_bit(sattr, snode, i) { ++ if (!ebitmap_node_get_bit(snode, i)) + continue; ++ ebitmap_for_each_bit(tattr, tnode, j) { ++ if (!ebitmap_node_get_bit(tnode, j)) ++ continue; ++ tmp_key.source_type = i + 1; ++ tmp_key.target_type = j + 1; ++ for (node = avtab_search_node(avtab, &tmp_key); ++ node; ++ node = avtab_search_node_next(node, tmp_key.specified)) { ++ xperms = node->datum.xperms; ++ if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) ++ && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) ++ continue; + +- rc = check_extended_permissions(avrule->xperms, xperms); +- /* failure on the extended permission check_extended_permissionss */ +- if (rc) { +- extended_permissions_violated(&error, avrule->xperms, xperms); +- ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n" +- "allowxperm %s %s:%s %s;", +- avrule->source_line, avrule->source_filename, avrule->line, +- p->p_type_val_to_name[stype], +- p->p_type_val_to_name[ttype], +- p->p_class_val_to_name[curperm->tclass - 1], +- sepol_extended_perms_to_string(&error)); +- +- rc = 0; +- ret++; ++ rc = check_extended_permissions(avrule->xperms, xperms); ++ /* failure on the extended permission check_extended_permissions */ ++ if (rc) { ++ extended_permissions_violated(&error, avrule->xperms, xperms); ++ ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n" ++ "allowxperm %s %s:%s %s;", ++ avrule->source_line, avrule->source_filename, avrule->line, ++ p->p_type_val_to_name[i], ++ p->p_type_val_to_name[j], ++ p->p_class_val_to_name[curperm->tclass - 1], ++ sepol_extended_perms_to_string(&error)); ++ ++ rc = 0; ++ ret++; ++ } ++ } + } +- + } + + /* failure on the regular permissions */ +@@ -304,9 +317,57 @@ oom: + } + + /* +- * If the ioctl permission is granted in check_assertion_avtab_match for the +- * source/target/class matching the current avrule neverallow, a lookup is +- * performed to determine if extended permissions exist for the source/target/class. ++ * Look up the extended permissions in avtab and verify that neverallowed ++ * permissions are not granted. ++ */ ++static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t *avtab, ++ unsigned int stype, unsigned int ttype, ++ avtab_key_t *k, policydb_t *p) ++{ ++ avtab_ptr_t node; ++ avtab_key_t tmp_key; ++ avtab_extended_perms_t *xperms; ++ av_extended_perms_t *neverallow_xperms = avrule->xperms; ++ ebitmap_t *sattr = &p->type_attr_map[stype]; ++ ebitmap_t *tattr = &p->type_attr_map[ttype]; ++ ebitmap_node_t *snode, *tnode; ++ unsigned int i, j; ++ int rc = 1; ++ ++ memcpy(&tmp_key, k, sizeof(avtab_key_t)); ++ tmp_key.specified = AVTAB_XPERMS_ALLOWED; ++ ++ ebitmap_for_each_bit(sattr, snode, i) { ++ if (!ebitmap_node_get_bit(snode, i)) ++ continue; ++ ebitmap_for_each_bit(tattr, tnode, j) { ++ if (!ebitmap_node_get_bit(tnode, j)) ++ continue; ++ tmp_key.source_type = i + 1; ++ tmp_key.target_type = j + 1; ++ for (node = avtab_search_node(avtab, &tmp_key); ++ node; ++ node = avtab_search_node_next(node, tmp_key.specified)) { ++ xperms = node->datum.xperms; ++ ++ if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) ++ && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) ++ continue; ++ rc = check_extended_permissions(neverallow_xperms, xperms); ++ if (rc) ++ break; ++ } ++ } ++ } ++ ++ return rc; ++} ++ ++/* ++ * When the ioctl permission is granted on an avtab entry that matches an ++ * avrule neverallowxperm entry, enumerate over the matching ++ * source/target/class sets to determine if the extended permissions exist ++ * and if the neverallowed ioctls are granted. + * + * Four scenarios of interest: + * 1. PASS - the ioctl permission is not granted for this source/target/class +@@ -319,33 +380,72 @@ oom: + * granted + */ + static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab, +- avtab_key_t *k) ++ avtab_key_t *k, policydb_t *p) + { +- avtab_ptr_t node; +- avtab_key_t tmp_key; +- avtab_extended_perms_t *xperms; +- av_extended_perms_t *neverallow_xperms = avrule->xperms; +- int rc = 1; ++ ebitmap_t src_matches, tgt_matches, matches; ++ unsigned int i, j; ++ ebitmap_node_t *snode, *tnode; ++ class_perm_node_t *cp; ++ int rc; ++ int ret = 1; + +- memcpy(&tmp_key, k, sizeof(avtab_key_t)); +- tmp_key.specified = AVTAB_XPERMS_ALLOWED; ++ ebitmap_init(&src_matches); ++ ebitmap_init(&tgt_matches); ++ ebitmap_init(&matches); ++ rc = ebitmap_and(&src_matches, &avrule->stypes.types, ++ &p->attr_type_map[k->source_type - 1]); ++ if (rc) ++ goto oom; + +- for (node = avtab_search_node(avtab, &tmp_key); +- node; +- node = avtab_search_node_next(node, tmp_key.specified)) { +- xperms = node->datum.xperms; +- if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) +- && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) +- continue; ++ if (ebitmap_length(&src_matches) == 0) ++ goto exit; + +- rc = check_extended_permissions(neverallow_xperms, xperms); ++ if (avrule->flags == RULE_SELF) { ++ rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], ++ &p->attr_type_map[k->target_type - 1]); + if (rc) +- break; ++ goto oom; ++ rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches); ++ if (rc) ++ goto oom; ++ } else { ++ rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, ++ &p->attr_type_map[k->target_type -1]); ++ if (rc) ++ goto oom; + } + +- return rc; +-} ++ if (ebitmap_length(&tgt_matches) == 0) ++ goto exit; + ++ for (cp = avrule->perms; cp; cp = cp->next) { ++ if (cp->tclass != k->target_class) ++ continue; ++ ebitmap_for_each_bit(&src_matches, snode, i) { ++ if (!ebitmap_node_get_bit(snode, i)) ++ continue; ++ ebitmap_for_each_bit(&tgt_matches, tnode, j) { ++ if (!ebitmap_node_get_bit(tnode, j)) ++ continue; ++ ++ ret = check_assertion_extended_permissions_avtab( ++ avrule, avtab, i, j, k, p); ++ if (ret) ++ goto exit; ++ } ++ } ++ } ++ goto exit; ++ ++oom: ++ ERR(NULL, "Out of memory - unable to check neverallows"); ++ ++exit: ++ ebitmap_destroy(&src_matches); ++ ebitmap_destroy(&tgt_matches); ++ ebitmap_destroy(&matches); ++ return ret; ++} + + static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args) + { +@@ -355,7 +455,7 @@ static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *a + avrule_t *avrule = a->avrule; + avtab_t *avtab = a->avtab; + +- if (k->specified != AVTAB_ALLOWED && k->specified != AVTAB_XPERMS_ALLOWED) ++ if (k->specified != AVTAB_ALLOWED) + goto exit; + + if (!match_any_class_permissions(avrule->perms, k->target_class, d->data)) +@@ -386,7 +486,7 @@ static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *a + goto exit; + + if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) { +- rc = check_assertion_extended_permissions(avrule, avtab, k); ++ rc = check_assertion_extended_permissions(avrule, avtab, k, p); + if (rc == 0) + goto exit; + } +diff --git libsepol-2.5/src/expand.c libsepol-2.5/src/expand.c +index 9cb7965..0ad57f5 100644 +--- libsepol-2.5/src/expand.c ++++ libsepol-2.5/src/expand.c +@@ -2497,6 +2497,7 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + unsigned int i; + ebitmap_t types, neg_types; + ebitmap_node_t *tnode; ++ int rc =-1; + + ebitmap_init(&types); + ebitmap_init(t); +@@ -2505,17 +2506,25 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + /* First go through the types and OR all the attributes to types */ + ebitmap_for_each_bit(&set->types, tnode, i) { + if (ebitmap_node_get_bit(tnode, i)) { ++ ++ /* ++ * invalid policies might have more types set in the ebitmap than ++ * what's available in the type_val_to_struct mapping ++ */ ++ if (i > p->p_types.nprim - 1) ++ goto err_types; ++ + if (p->type_val_to_struct[i]->flavor == + TYPE_ATTRIB) { + if (ebitmap_union + (&types, + &p->type_val_to_struct[i]-> + types)) { +- return -1; ++ goto err_types; + } + } else { + if (ebitmap_set_bit(&types, i, 1)) { +- return -1; ++ goto err_types; + } + } + } +@@ -2523,7 +2532,7 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + } else { + /* No expansion of attributes, just copy the set as is. */ + if (ebitmap_cpy(&types, &set->types)) +- return -1; ++ goto err_types; + } + + /* Now do the same thing for negset */ +@@ -2535,11 +2544,11 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + if (ebitmap_union + (&neg_types, + &p->type_val_to_struct[i]->types)) { +- return -1; ++ goto err_neg; + } + } else { + if (ebitmap_set_bit(&neg_types, i, 1)) { +- return -1; ++ goto err_neg; + } + } + } +@@ -2554,7 +2563,7 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) + continue; + if (ebitmap_set_bit(t, i, 1)) +- return -1; ++ goto err_neg; + } + goto out; + } +@@ -2563,7 +2572,7 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + if (ebitmap_node_get_bit(tnode, i) + && (!ebitmap_get_bit(&neg_types, i))) + if (ebitmap_set_bit(t, i, 1)) +- return -1; ++ goto err_neg; + } + + if (set->flags & TYPE_COMP) { +@@ -2575,20 +2584,23 @@ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, + } + if (ebitmap_get_bit(t, i)) { + if (ebitmap_set_bit(t, i, 0)) +- return -1; ++ goto err_neg; + } else { + if (ebitmap_set_bit(t, i, 1)) +- return -1; ++ goto err_neg; + } + } + } + +- out: ++ out: ++ rc = 0; + +- ebitmap_destroy(&types); ++ err_neg: + ebitmap_destroy(&neg_types); ++ err_types: ++ ebitmap_destroy(&types); + +- return 0; ++ return rc; + } + + static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap, +diff --git libsepol-2.5/src/genbools.c libsepol-2.5/src/genbools.c +index 6a06ec9..c81e848 100644 +--- libsepol-2.5/src/genbools.c ++++ libsepol-2.5/src/genbools.c +@@ -79,7 +79,7 @@ static int load_booleans(struct policydb *policydb, const char *path, + if (boolf == NULL) + goto localbool; + +-#ifdef DARWIN ++#ifdef __APPLE__ + if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) { + ERR(NULL, "out of memory"); + return -1; +@@ -111,7 +111,7 @@ static int load_booleans(struct policydb *policydb, const char *path, + boolf = fopen(localbools, "r"); + if (boolf != NULL) { + +-#ifdef DARWIN ++#ifdef __APPLE__ + + while(fgets(buffer, 255, boolf) != NULL) { + #else +diff --git libsepol-2.5/src/genusers.c libsepol-2.5/src/genusers.c +index 7826b71..0b98a76 100644 +--- libsepol-2.5/src/genusers.c ++++ libsepol-2.5/src/genusers.c +@@ -7,7 +7,7 @@ + + #include + +-#ifndef DARWIN ++#ifndef __APPLE__ + #include + #endif + +@@ -47,7 +47,7 @@ static int load_users(struct policydb *policydb, const char *path) + if (fp == NULL) + return -1; + +-#ifdef DARWIN ++#ifdef __APPLE__ + if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) { + ERR(NULL, "out of memory"); + return -1; +diff --git libsepol-2.5/src/hierarchy.c libsepol-2.5/src/hierarchy.c +index 6f73195..778541a 100644 +--- libsepol-2.5/src/hierarchy.c ++++ libsepol-2.5/src/hierarchy.c +@@ -121,18 +121,6 @@ static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p, + } + } + +- if (ebitmap_get_bit(&p->attr_type_map[tgt - 1], parent - 1)) { +- avtab_key.target_type = parent; +- ebitmap_for_each_bit(&p->attr_type_map[src - 1], tnode, i) { +- if (!ebitmap_node_get_bit(tnode, i)) +- continue; +- avtab_key.source_type = i + 1; +- rc = bounds_insert_rule(handle, avtab, global, other, +- &avtab_key, &datum); +- if (rc) goto exit; +- } +- } +- + exit: + return rc; + } +@@ -313,45 +301,21 @@ static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p, + ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) { + if (!ebitmap_node_get_bit(tnode, i)) + continue; +- avtab_key.target_type = i + 1; +- d = bounds_not_covered(global_avtab, cur_avtab, +- &avtab_key, data); +- if (!d) continue; + td = p->type_val_to_struct[i]; + if (td && td->bounds) { + avtab_key.target_type = td->bounds; + d = bounds_not_covered(global_avtab, cur_avtab, + &avtab_key, data); +- if (!d) continue; +- } +- (*numbad)++; +- rc = bounds_add_bad(handle, child, i+1, class, d, bad); +- if (rc) goto exit; +- } +- } +- if (ebitmap_get_bit(&p->attr_type_map[tgt - 1], child - 1)) { +- avtab_key.target_type = parent; +- ebitmap_for_each_bit(&p->attr_type_map[src - 1], tnode, i) { +- if (!ebitmap_node_get_bit(tnode, i)) +- continue; +- avtab_key.source_type = i + 1; +- if (avtab_key.source_type == child) { +- /* Checked above */ +- continue; +- } +- d = bounds_not_covered(global_avtab, cur_avtab, +- &avtab_key, data); +- if (!d) continue; +- td = p->type_val_to_struct[i]; +- if (td && td->bounds) { +- avtab_key.source_type = td->bounds; ++ } else { ++ avtab_key.target_type = i + 1; + d = bounds_not_covered(global_avtab, cur_avtab, + &avtab_key, data); +- if (!d) continue; + } +- (*numbad)++; +- rc = bounds_add_bad(handle, i+1, child, class, d, bad); +- if (rc) goto exit; ++ if (d) { ++ (*numbad)++; ++ rc = bounds_add_bad(handle, child, i+1, class, d, bad); ++ if (rc) goto exit; ++ } + } + } + +diff --git libsepol-2.5/src/module_to_cil.c libsepol-2.5/src/module_to_cil.c +index 18ec6b9..36f3b7d 100644 +--- libsepol-2.5/src/module_to_cil.c ++++ libsepol-2.5/src/module_to_cil.c +@@ -26,6 +26,9 @@ + #include + #include + #include ++#ifndef IPPROTO_DCCP ++#define IPPROTO_DCCP 33 ++#endif + #include + #include + #include +@@ -1070,6 +1073,10 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a + struct type_set *ts; + + for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) { ++ if (avrule->specified == AVRULE_NEVERALLOW && avrule->source_filename) { ++ cil_println(0, ";;* lmx %lu %s\n",avrule->source_line, avrule->source_filename); ++ } ++ + ts = &avrule->stypes; + rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames); + if (rc != 0) { +@@ -1100,6 +1107,10 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a + + names_destroy(&snames, &num_snames); + names_destroy(&tnames, &num_tnames); ++ ++ if (avrule->specified == AVRULE_NEVERALLOW && avrule->source_filename) { ++ cil_println(0, ";;* lme\n"); ++ } + } + + return 0; +@@ -1292,7 +1303,7 @@ static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node * + { + int rc = -1; + struct cond_node *cond; +- struct list *attr_list; ++ struct list *attr_list = NULL; + + rc = list_init(&attr_list); + if (rc != 0) { +@@ -2537,6 +2548,7 @@ static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *p + switch (portcon->u.port.protocol) { + case IPPROTO_TCP: protocol = "tcp"; break; + case IPPROTO_UDP: protocol = "udp"; break; ++ case IPPROTO_DCCP: protocol = "dccp"; break; + default: + log_err("Unknown portcon protocol: %i", portcon->u.port.protocol); + rc = -1; +@@ -3470,7 +3482,7 @@ static int block_to_cil(struct policydb *pdb, struct avrule_block *block, struct + { + int rc = -1; + struct avrule_decl *decl; +- struct list *attr_list; ++ struct list *attr_list = NULL; + + decl = block->branch_list; + +@@ -3619,7 +3631,7 @@ static int blocks_to_cil(struct policydb *pdb) + int rc = -1; + struct avrule_block *block; + int indent = 0; +- struct stack *stack; ++ struct stack *stack = NULL; + + rc = stack_init(&stack); + if (rc != 0) { +@@ -3687,7 +3699,7 @@ static int linked_blocks_to_cil(struct policydb *pdb) + // Since it is linked, all optional blocks have been resolved + int rc = -1; + struct avrule_block *block; +- struct stack *stack; ++ struct stack *stack = NULL; + + rc = stack_init(&stack); + if (rc != 0) { +diff --git libsepol-2.5/src/node_record.c libsepol-2.5/src/node_record.c +index bd48ba0..21043b6 100644 +--- libsepol-2.5/src/node_record.c ++++ libsepol-2.5/src/node_record.c +@@ -70,7 +70,7 @@ static int node_parse_addr(sepol_handle_t * handle, + return STATUS_ERR; + } + +-#ifdef DARWIN ++#ifdef __APPLE__ + memcpy(addr_bytes, in_addr.s6_addr, 16); + #else + memcpy(addr_bytes, in_addr.s6_addr32, 16); +@@ -162,7 +162,7 @@ static int node_expand_addr(sepol_handle_t * handle, + { + struct in6_addr addr; + memset(&addr, 0, sizeof(struct in6_addr)); +-#ifdef DARWIN ++#ifdef __APPLE__ + memcpy(&addr.s6_addr[0], addr_bytes, 16); + #else + memcpy(&addr.s6_addr32[0], addr_bytes, 16); +diff --git libsepol-2.5/src/nodes.c libsepol-2.5/src/nodes.c +index 50cf21d..820346d 100644 +--- libsepol-2.5/src/nodes.c ++++ libsepol-2.5/src/nodes.c +@@ -273,6 +273,7 @@ int sepol_node_query(sepol_handle_t * handle, + c, SEPOL_PROTO_IP6, + response) < 0) + goto err; ++ return STATUS_SUCCESS; + } + } + break; +diff --git libsepol-2.5/src/port_record.c libsepol-2.5/src/port_record.c +index 6a33d93..ed9093b 100644 +--- libsepol-2.5/src/port_record.c ++++ libsepol-2.5/src/port_record.c +@@ -184,6 +184,8 @@ const char *sepol_port_get_proto_str(int proto) + return "udp"; + case SEPOL_PROTO_TCP: + return "tcp"; ++ case SEPOL_PROTO_DCCP: ++ return "dccp"; + default: + return "???"; + } +diff --git libsepol-2.5/src/ports.c libsepol-2.5/src/ports.c +index 607a629..62ec602 100644 +--- libsepol-2.5/src/ports.c ++++ libsepol-2.5/src/ports.c +@@ -1,4 +1,7 @@ + #include ++#ifndef IPPROTO_DCCP ++#define IPPROTO_DCCP 33 ++#endif + #include + + #include "debug.h" +@@ -16,6 +19,8 @@ static inline int sepol2ipproto(sepol_handle_t * handle, int proto) + return IPPROTO_TCP; + case SEPOL_PROTO_UDP: + return IPPROTO_UDP; ++ case SEPOL_PROTO_DCCP: ++ return IPPROTO_DCCP; + default: + ERR(handle, "unsupported protocol %u", proto); + return STATUS_ERR; +@@ -30,6 +35,8 @@ static inline int ipproto2sepol(sepol_handle_t * handle, int proto) + return SEPOL_PROTO_TCP; + case IPPROTO_UDP: + return SEPOL_PROTO_UDP; ++ case IPPROTO_DCCP: ++ return SEPOL_PROTO_DCCP; + default: + ERR(handle, "invalid protocol %u " "found in policy", proto); + return STATUS_ERR; +diff --git libsepol-2.5/src/private.h libsepol-2.5/src/private.h +index 8a6d4bb..9c700c9 100644 +--- libsepol-2.5/src/private.h ++++ libsepol-2.5/src/private.h +@@ -5,7 +5,7 @@ + #include + + +-#ifdef DARWIN ++#ifdef __APPLE__ + #include + #include + #else +@@ -16,7 +16,7 @@ + #include + #include + +-#ifdef DARWIN ++#ifdef __APPLE__ + #define __BYTE_ORDER BYTE_ORDER + #define __LITTLE_ENDIAN LITTLE_ENDIAN + #endif +diff --git libsepol-2.5/src/services.c libsepol-2.5/src/services.c +index d64a8e8..d2b80b4 100644 +--- libsepol-2.5/src/services.c ++++ libsepol-2.5/src/services.c +@@ -1152,20 +1152,16 @@ int hidden sepol_compute_av(sepol_security_id_t ssid, + int hidden sepol_string_to_security_class(const char *class_name, + sepol_security_class_t *tclass) + { +- char *class = NULL; +- sepol_security_class_t id; +- +- for (id = 1;; id++) { +- class = policydb->p_class_val_to_name[id - 1]; +- if (class == NULL) { +- ERR(NULL, "could not convert %s to class id", class_name); +- return STATUS_ERR; +- } +- if ((strcmp(class, class_name)) == 0) { +- *tclass = id; +- return STATUS_SUCCESS; +- } ++ class_datum_t *tclass_datum; ++ ++ tclass_datum = hashtab_search(policydb->p_classes.table, ++ (hashtab_key_t) class_name); ++ if (!tclass_datum) { ++ ERR(NULL, "unrecognized class %s", class_name); ++ return STATUS_ERR; + } ++ *tclass = tclass_datum->s.value; ++ return STATUS_SUCCESS; + } + + /* +diff --git libsepol-2.5/tests/.gitignore libsepol-2.5/tests/.gitignore +new file mode 100644 +index 0000000..c3f60fd +--- /dev/null ++++ libsepol-2.5/tests/.gitignore +@@ -0,0 +1 @@ ++libsepol-tests +diff --git libsepol-2.5/tests/policies/.gitignore libsepol-2.5/tests/policies/.gitignore +new file mode 100644 +index 0000000..5a547a8 +--- /dev/null ++++ libsepol-2.5/tests/policies/.gitignore +@@ -0,0 +1,3 @@ ++test-downgrade/ ++test-*/*.mls ++test-*/*.std diff --git a/SPECS/libsepol.spec b/SPECS/libsepol.spec index 675f7eb..403518d 100644 --- a/SPECS/libsepol.spec +++ b/SPECS/libsepol.spec @@ -1,13 +1,14 @@ Summary: SELinux binary policy manipulation library Name: libsepol -Version: 2.1.9 -Release: 3%{?dist} +Version: 2.5 +Release: 6%{?dist} License: LGPLv2+ Group: System Environment/Libraries -Source: http://www.nsa.gov/selinux/archives/libsepol-%{version}.tgz -Patch: libsepol-rhat.patch -URL: http://www.selinuxproject.org -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Source: https://raw.githubusercontent.com/wiki/SELinuxProject/selinux/files/releases/20160223/libsepol-2.5.tar.gz +# HEAD e7ab0f8b86a3f6234f264d3bf98ccfb070ebaca7 +Patch1: libsepol-rhel.patch +URL: https://github.com/SELinuxProject/selinux/wiki +BuildRequires: flex %description Security-enhanced Linux is a feature of the Linux® kernel and a number @@ -28,7 +29,7 @@ on binary policies such as customizing policy boolean settings. %package devel Summary: Header files and libraries used to build policy manipulation tools Group: Development/Libraries -Requires: %{name} = %{version}-%{release} +Requires: %{name}%{?_isa} = %{version}-%{release} %description devel The libsepol-devel package contains the libraries and header files @@ -37,15 +38,15 @@ needed for developing applications that manipulate binary policies. %package static Summary: static libraries used to build policy manipulation tools Group: Development/Libraries -Requires: %{name}-devel = %{version}-%{release} +Requires: %{name}-devel%{?_isa} = %{version}-%{release} %description static The libsepol-static package contains the static libraries and header files needed for developing applications that manipulate binary policies. %prep -%setup -q -%patch -p2 -b .rhat +%setup -q -n libsepol-2.5 +%patch1 -p1 -b .rhel # sparc64 is an -fPIC arch, so we need to fix it here %ifarch sparc64 @@ -54,7 +55,7 @@ sed -i 's/fpic/fPIC/g' src/Makefile %build make clean -make %{?_smp_mflags} CFLAGS="%{optflags}" +make %{?_smp_mflags} CFLAGS="%{optflags}" LDFLAGS="%{?__global_ldflags}" %install rm -rf ${RPM_BUILD_ROOT} @@ -64,7 +65,7 @@ mkdir -p ${RPM_BUILD_ROOT}%{_includedir} mkdir -p ${RPM_BUILD_ROOT}%{_bindir} mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man3 mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8 -make DESTDIR="${RPM_BUILD_ROOT}" LIBDIR="${RPM_BUILD_ROOT}%{_libdir}" SHLIBDIR="${RPM_BUILD_ROOT}/%{_lib}" install +make DESTDIR="${RPM_BUILD_ROOT}" LIBDIR="${RPM_BUILD_ROOT}%{_libdir}" SHLIBDIR="${RPM_BUILD_ROOT}/%{_libdir}" install rm -f ${RPM_BUILD_ROOT}%{_bindir}/genpolbools rm -f ${RPM_BUILD_ROOT}%{_bindir}/genpolusers rm -f ${RPM_BUILD_ROOT}%{_bindir}/chkcon @@ -93,12 +94,50 @@ exit 0 %dir %{_includedir}/sepol %dir %{_includedir}/sepol/policydb %{_includedir}/sepol/policydb/*.h +%dir %{_includedir}/sepol/cil +%{_includedir}/sepol/cil/*.h %files %defattr(-,root,root) -/%{_lib}/libsepol.so.1 +%{!?_licensedir:%global license %%doc} +%license COPYING +%{_libdir}/libsepol.so.1 %changelog +* Wed Aug 10 2016 Petr Lautrbach 2.5-6 +- Fix memory leak in expand.c +- Fix invalid read when policy file is corrupt +- Fix possible use of uninitialized variables + +* Tue Aug 02 2016 Petr Lautrbach 2.5-5 +- Warn instead of fail if permission is not resolved +- Ignore object_r when adding userrole mappings to policydb + +* Tue Jul 12 2016 Petr Lautrbach 2.5-4 +- Add missing return to sepol_node_query() + +* Mon Jun 27 2016 Petr Lautrbach - 2.5-3 +- Correctly detect unknown classes in sepol_string_to_security_class +- Sort object files for deterministic linking order +- Fix neverallowxperm checking on attributes +- Remove libsepol.map when cleaning +- Add high-level language line marking support to CIL +- Change logic of bounds checking to match change in kernel +- Fix multiple spelling errors +- Only apply bounds checking to source types in rules +- Fix CIL and not add an attribute as a type in the attr_type_map +- Build policy on systems not supporting DCCP protocol +- Fix extended permissions neverallow checking +- Fix CIL neverallow and bounds checking +- Android.mk: Add -D_GNU_SOURCE to common_cflags + +* Mon Apr 11 2016 Petr Lautrbach - 2.5-2.1 +- Fix bug in CIL when resetting classes +- Add support for portcon dccp protocol + +* Tue Feb 23 2016 Petr Lautrbach 2.5-1 +- Update to upstream release 2016-02-23 + * Fri Jan 24 2014 Daniel Mach - 2.1.9-3 - Mass rebuild 2014-01-24