diff --git a/libsepol-rhat.patch b/libsepol-rhat.patch index d9167f4..8fae03e 100644 --- a/libsepol-rhat.patch +++ b/libsepol-rhat.patch @@ -93,7 +93,7 @@ index 16c89f3..84cfaf8 100644 } } diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c -index 2003eb6..34e764b 100644 +index 2003eb6..0ca8448 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -49,6 +49,82 @@ typedef struct expand_state { @@ -179,24 +179,25 @@ index 2003eb6..34e764b 100644 static void expand_state_init(expand_state_t * state) { memset(state, 0, sizeof(expand_state_t)); -@@ -306,6 +382,16 @@ static int constraint_node_clone(constraint_node_t ** dst, +@@ -306,6 +382,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. -+ */ ++ /* ++ * 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"); ++ &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-> -@@ -377,6 +463,13 @@ static int class_copy_default_new_object(expand_state_t *state, +@@ -377,6 +464,13 @@ static int class_copy_default_new_object(expand_state_t *state, } newdatum->default_role = olddatum->default_role; } @@ -210,7 +211,7 @@ index 2003eb6..34e764b 100644 if (olddatum->default_range) { if (newdatum->default_range && olddatum->default_range != newdatum->default_range) { ERR(state->handle, "Found conflicting default range definitions"); -@@ -812,6 +905,7 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum, +@@ -812,6 +906,7 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum, new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); @@ -218,7 +219,7 @@ index 2003eb6..34e764b 100644 return -1; } -@@ -877,9 +971,13 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l, +@@ -877,9 +972,13 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l, l->sens = sl->sens; levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, @@ -235,7 +236,7 @@ index 2003eb6..34e764b 100644 for (cat = sl->cat; cat; cat = cat->next) { if (cat->low > cat->high) { ERR(h, "Category range is not valid %s.%s", -@@ -963,6 +1061,7 @@ static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum, +@@ -963,6 +1062,7 @@ static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum, new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); @@ -243,7 +244,7 @@ index 2003eb6..34e764b 100644 return -1; } ret = hashtab_insert(state->out->p_users.table, -@@ -1357,10 +1456,20 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) +@@ -1357,10 +1457,20 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) { unsigned int i, j; @@ -265,7 +266,7 @@ index 2003eb6..34e764b 100644 cur_rule = rules; while (cur_rule) { -@@ -1383,6 +1492,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r +@@ -1383,6 +1493,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r mapped_otype = state->typemap[cur_rule->otype - 1]; @@ -280,7 +281,7 @@ index 2003eb6..34e764b 100644 ebitmap_for_each_bit(&stypes, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; -@@ -1390,16 +1507,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r +@@ -1390,16 +1508,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r if (!ebitmap_node_get_bit(tnode, j)) continue; @@ -300,7 +301,7 @@ index 2003eb6..34e764b 100644 ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s", cur_trans->name, state->out->p_type_val_to_name[i], -@@ -1407,7 +1522,7 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r +@@ -1407,7 +1523,7 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r state->out->p_class_val_to_name[cur_trans->tclass - 1], state->out->p_type_val_to_name[cur_trans->otype - 1], state->out->p_type_val_to_name[mapped_otype - 1]); @@ -309,7 +310,7 @@ index 2003eb6..34e764b 100644 return -1; } cur_trans = cur_trans->next; -@@ -1422,8 +1537,6 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r +@@ -1422,8 +1538,6 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r return -1; } memset(new_trans, 0, sizeof(*new_trans)); @@ -318,7 +319,7 @@ index 2003eb6..34e764b 100644 new_trans->name = strdup(cur_rule->name); if (!new_trans->name) { -@@ -1434,9 +1547,16 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r +@@ -1434,9 +1548,16 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r new_trans->ttype = j + 1; new_trans->tclass = cur_rule->tclass; new_trans->otype = mapped_otype; @@ -335,7 +336,7 @@ index 2003eb6..34e764b 100644 ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); -@@ -1981,6 +2101,8 @@ static int cond_node_copy(expand_state_t * state, cond_node_t * cn) +@@ -1981,6 +2102,8 @@ static int cond_node_copy(expand_state_t * state, cond_node_t * cn) } if (cond_node_map_bools(state, tmp)) { @@ -344,7 +345,7 @@ index 2003eb6..34e764b 100644 ERR(state->handle, "Error mapping booleans"); return -1; } -@@ -2037,14 +2159,13 @@ static int ocontext_copy_xen(expand_state_t *state) +@@ -2037,14 +2160,13 @@ static int ocontext_copy_xen(expand_state_t *state) else state->out->ocontexts[i] = n; l = n; @@ -364,7 +365,7 @@ index 2003eb6..34e764b 100644 n->sid[0] = c->sid[0]; break; case OCON_XEN_PIRQ: -@@ -2067,11 +2188,6 @@ static int ocontext_copy_xen(expand_state_t *state) +@@ -2067,11 +2189,6 @@ static int ocontext_copy_xen(expand_state_t *state) ERR(state->handle, "Unknown ocontext"); return -1; } @@ -376,7 +377,7 @@ index 2003eb6..34e764b 100644 } } return 0; -@@ -2096,14 +2212,12 @@ static int ocontext_copy_selinux(expand_state_t *state) +@@ -2096,14 +2213,12 @@ static int ocontext_copy_selinux(expand_state_t *state) else state->out->ocontexts[i] = n; l = n; @@ -395,7 +396,7 @@ index 2003eb6..34e764b 100644 n->sid[0] = c->sid[0]; break; case OCON_FS: /* FALLTHROUGH */ -@@ -2147,10 +2261,6 @@ static int ocontext_copy_selinux(expand_state_t *state) +@@ -2147,10 +2262,6 @@ static int ocontext_copy_selinux(expand_state_t *state) ERR(state->handle, "Unknown ocontext"); return -1; } @@ -406,7 +407,7 @@ index 2003eb6..34e764b 100644 } } return 0; -@@ -2188,9 +2298,15 @@ static int genfs_copy(expand_state_t * state) +@@ -2188,9 +2299,15 @@ static int genfs_copy(expand_state_t * state) memset(newgenfs, 0, sizeof(genfs_t)); newgenfs->fstype = strdup(genfs->fstype); if (!newgenfs->fstype) { @@ -422,7 +423,7 @@ index 2003eb6..34e764b 100644 l = NULL; for (c = genfs->head; c; c = c->next) { -@@ -2203,6 +2319,7 @@ static int genfs_copy(expand_state_t * state) +@@ -2203,6 +2320,7 @@ static int genfs_copy(expand_state_t * state) newc->u.name = strdup(c->u.name); if (!newc->u.name) { ERR(state->handle, "Out of memory!"); @@ -430,7 +431,7 @@ index 2003eb6..34e764b 100644 return -1; } newc->v.sclass = c->v.sclass; -@@ -2213,12 +2330,6 @@ static int genfs_copy(expand_state_t * state) +@@ -2213,12 +2331,6 @@ static int genfs_copy(expand_state_t * state) newgenfs->head = newc; l = newc; } @@ -443,7 +444,7 @@ index 2003eb6..34e764b 100644 } return 0; } -@@ -3009,7 +3120,8 @@ int expand_module(sepol_handle_t * handle, +@@ -3009,7 +3121,8 @@ int expand_module(sepol_handle_t * handle, } cond_optimize_lists(state.out->cond_list); @@ -747,7 +748,7 @@ index b5b807e..1665ede 100644 ERR(file->handle, "offset greater than file size (at %u, " "offset %zu -> %zu", nsec, off[nsec - 1], diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c -index ff292f6..ef0252a 100644 +index ff292f6..00cf6a8 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -158,6 +158,20 @@ static struct policydb_compat_info policydb_compat[] = { @@ -849,21 +850,18 @@ index ff292f6..ef0252a 100644 hashtab_destroy(symtab[i].table); } } -@@ -1995,8 +2037,11 @@ static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep, - depth++; - if (ebitmap_read(&e->names, fp)) - return -1; -- if (p->policy_type != POLICY_KERN && -- type_set_read(e->type_names, fp)) -+ if ((p->policy_type != POLICY_KERN && -+ type_set_read(e->type_names, fp)) || -+ ((p->policy_type == POLICY_KERN && -+ p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) && -+ type_set_read(e->type_names, fp))) +@@ -1998,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: -@@ -2097,6 +2142,16 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp) + return -1; +@@ -2097,6 +2143,16 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp) cladatum->default_range = le32_to_cpu(buf[2]); } @@ -881,24 +879,22 @@ index ff292f6..ef0252a 100644 goto bad; diff --git a/libsepol/src/services.c b/libsepol/src/services.c -index 9c2920c..9b42d8d 100644 +index 9c2920c..e235ae4 100644 --- a/libsepol/src/services.c +++ b/libsepol/src/services.c -@@ -43,6 +43,13 @@ +@@ -43,6 +43,11 @@ * Implementation of the security services. */ -+/* The maximum size of the malloc'd sepol_compute_av_reason_buffer() */ -+#define REASON_BUF_SIZE 30000 -+/* The maximum size of each malloc'd expression buffer */ -+#define EXPR_BUF_SIZE 1000 -+/* Number expressions in a constraint - max seen in MLS policy is 21 */ -+#define EXPR_BUFFERS 30 ++/* 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 +61,7 @@ +@@ -54,6 +59,7 @@ #include #include #include @@ -906,88 +902,97 @@ index 9c2920c..9b42d8d 100644 #include "debug.h" #include "private.h" -@@ -70,6 +78,31 @@ static int selinux_enforcing = 1; +@@ -70,6 +76,50 @@ static int selinux_enforcing = 1; static sidtab_t mysidtab, *sidtab = &mysidtab; static policydb_t mypolicydb, *policydb = &mypolicydb; -+/* Stack services for RPN to infix conversion. Size is num of expr bufs */ -+char *stack[EXPR_BUFFERS]; -+int tos = 0; -+ -+void push(char * expr_ptr) ++/* 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 (tos >= EXPR_BUFFERS) { -+ ERR(NULL, "Stack is full"); -+ return; ++ 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[tos] = expr_ptr; -+ tos++; ++ stack[next_stack_entry] = expr_ptr; ++ next_stack_entry++; +} -+ -+char *pop() ++ ++static char *pop(void) +{ -+ tos--; -+ if (tos < 0) { -+ ERR(NULL, "Stack is Empty"); ++ next_stack_entry--; ++ if (next_stack_entry < 0) { ++ next_stack_entry = 0; ++ ERR(NULL, "pop called with no stack entries"); + return NULL; + } -+ return (char *)stack[tos]; ++ return stack[next_stack_entry]; +} +/* End Stack services */ + int hidden sepol_set_sidtab(sidtab_t * s) { sidtab = s; -@@ -112,20 +145,118 @@ int sepol_set_policydb_from_file(FILE * fp) +@@ -112,20 +162,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 -+ * This function will process policy version >= -+ * POLICYDB_VERSION_CONSTRAINT_NAMES as they contain a list -+ * of types and/or attributes defined in the policy source. ++ * 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. + */ -+int get_type_set_list(constraint_expr_t * e, char * e_buf) -+{ -+ ebitmap_t *types; -+ types = &e->type_names->types; ++static int expr_counter; ++static char **expr_list; ++static int expr_buf_used; ++static int expr_buf_len; + -+ int rc = 0; -+ unsigned int i; -+ char tmp_buf[100]; -+ /* if ->names is 0, then output string */ -+ int empty_set = 0; -+ -+ char *list_buf; -+ list_buf = malloc(EXPR_BUF_SIZE); -+ if (!list_buf) { -+ ERR(NULL, "malloc failed to allocate list buffer"); -+ return -ENOMEM; -+ } -+ memset(list_buf, '\0', EXPR_BUF_SIZE); -+ -+ /* -+ * Process list of names that have been defined in the 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]); -+ strncat(list_buf, tmp_buf, EXPR_BUF_SIZE); -+ empty_set++; -+ } -+ -+ strncat(e_buf, "{ POLICY_SOURCE: ", EXPR_BUF_SIZE); -+ if (empty_set == 0) -+ strncat(e_buf, " ", EXPR_BUF_SIZE); -+ else { -+ strncat(e_buf, list_buf, EXPR_BUF_SIZE); ++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; ++ } + } -+ strncat(e_buf, "} ", EXPR_BUF_SIZE); -+ free(list_buf); -+ return 0; +} + +/* @@ -999,33 +1004,120 @@ index 9c2920c..9b42d8d 100644 + * contain a list of types and attributes that were defined in the + * policy source. + */ -+int get_names_list(constraint_expr_t * e, int type, char * e_buf) ++static void get_names_list(constraint_expr_t *e, int type) +{ -+ /* If no buffer set then just return. */ -+ if (!e_buf) -+ return 0; ++ 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 */ -+ get_type_set_list(e, e_buf); -+ return 0; ++ /* ++ * 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 0; ++ return; +} + -+static void msgcat(char *e_buf, char *src, char *tgt, char *rel, int failed) { ++static void msgcat(char *src, char *tgt, char *rel, int failed) ++{ + char tmp_buf[1024]; -+ if (e_buf) { -+ 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); -+ strncat(e_buf, tmp_buf, EXPR_BUF_SIZE); ++ 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; +} + +/* @@ -1057,23 +1149,17 @@ index 9c2920c..9b42d8d 100644 - constraint_expr_t * cexpr) + sepol_security_class_t tclass, + constraint_node_t *constraint, -+ char ** r_buf, ++ char **r_buf, + unsigned int flags) { uint32_t val1, val2; context_struct_t *c; -@@ -135,56 +266,138 @@ static int constraint_expr_eval(context_struct_t * scontext, +@@ -135,56 +360,135 @@ 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[EXPR_BUF_SIZE]; -+ -+ /* The array of expression text buffer pointers and counter */ -+ char *expr_buf[EXPR_BUFFERS] = {NULL}; -+ int expr_counter = 0; -+ /* Hold class and perm list */ -+ char *class_buf; ++ char tmp_buf[128]; + +/* + * Define the s_t_x_num values that make up r1, t2 etc. in text strings @@ -1094,64 +1180,68 @@ index 9c2920c..9b42d8d 100644 + + int rc = 0, x; + -+ /* Buffer to hold class & perm list */ -+ class_buf = malloc(EXPR_BUF_SIZE); ++ char *class_buf = NULL; ++ ++ class_buf = get_class_info(tclass, constraint, xcontext); + if (!class_buf) { -+ ERR(NULL, "malloc failed to allocate class buffer"); ++ ERR(NULL, "failed to allocate class buffer"); + return -ENOMEM; + } -+ memset(class_buf, '\0', EXPR_BUF_SIZE); + -+ /* Get constraint statement type */ -+ strncpy(tmp_buf, "constrain ", sizeof(tmp_buf)); ++ /* 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) { -+ if (e->attr >= CEXPR_L1L2) { -+ strncpy(tmp_buf, "mlsconstrain ", sizeof(tmp_buf)); -+ break; -+ } -+ } -+ strncat(class_buf, tmp_buf, EXPR_BUF_SIZE); ++ /* 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; + -+ /* Get class entry */ -+ snprintf(tmp_buf, sizeof(tmp_buf), "%s ", policydb->p_class_val_to_name[tclass - 1]); -+ strncat(class_buf, tmp_buf, EXPR_BUF_SIZE); ++ if (expr_list_len == 0) ++ new_expr_list_len = STACK_LEN; ++ else ++ new_expr_list_len = expr_list_len * 2; + -+ /* Get permission entries from the constraint node. */ -+ snprintf(tmp_buf, sizeof(tmp_buf), "{%s } (", sepol_av_to_string(policydb, tclass, -+ constraint->permissions)); -+ strncat(class_buf, tmp_buf, EXPR_BUF_SIZE); ++ 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"); ++ return -ENOMEM; ++ } ++ expr_list_len = new_expr_list_len; ++ expr_list = new_expr_list; ++ } + -+ /* Original function but with buffer support */ -+ for (e = constraint->expr; e; e = e->next) { -+ /* malloc a buffer to store each expression text component */ -+ expr_buf[expr_counter] = malloc(EXPR_BUF_SIZE); -+ if (!expr_buf[expr_counter]) { -+ ERR(NULL, "malloc failed to allocate expr buffer"); ++ /* ++ * 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"); + return -ENOMEM; + } -+ memset(expr_buf[expr_counter], '\0', EXPR_BUF_SIZE); ++ 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]; -+ if (*r_buf) -+ strncat(expr_buf[expr_counter], "not", EXPR_BUF_SIZE); ++ cat_expr_buf(expr_list[expr_counter], "not"); break; case CEXPR_AND: BUG_ON(sp < 1); sp--; s[sp] &= s[sp + 1]; -+ if (*r_buf) -+ strncat(expr_buf[expr_counter], "and", EXPR_BUF_SIZE); ++ cat_expr_buf(expr_list[expr_counter], "and"); break; case CEXPR_OR: BUG_ON(sp < 1); sp--; s[sp] |= s[sp + 1]; -+ if (*r_buf) -+ strncat(expr_buf[expr_counter], "or", EXPR_BUF_SIZE); ++ cat_expr_buf(expr_list[expr_counter], "or"); break; case CEXPR_ATTR: if (sp == (CEXPR_MAXDEPTH - 1)) @@ -1176,30 +1266,29 @@ index 9c2920c..9b42d8d 100644 val2 = tcontext->role; r1 = policydb->role_val_to_struct[val1 - 1]; r2 = policydb->role_val_to_struct[val2 - 1]; -+ if (*r_buf) { -+ 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); -+ } ++ 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(expr_buf[expr_counter++], src, tgt, "dom", -+ s[sp] == 0); ++ 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(expr_buf[expr_counter++], src, tgt, -+ "domby", s[sp] == 0); ++ msgcat(src, tgt, "domby", s[sp] == 0); ++ expr_counter++; continue; case CEXPR_INCOMP: - s[++sp] = @@ -1209,12 +1298,12 @@ index 9c2920c..9b42d8d 100644 - val1 - 1)); + s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1) + && !ebitmap_get_bit(&r2->dominates, val1 - 1)); -+ msgcat(expr_buf[expr_counter++], src, tgt, -+ "incomp", s[sp] == 0); ++ msgcat(src, tgt, "incomp", s[sp] == 0); ++ expr_counter++; continue; default: break; -@@ -193,110 +406,286 @@ static int constraint_expr_eval(context_struct_t * scontext, +@@ -193,110 +497,325 @@ static int constraint_expr_eval(context_struct_t * scontext, case CEXPR_L1L2: l1 = &(scontext->range.level[0]); l2 = &(tcontext->range.level[0]); @@ -1256,28 +1345,28 @@ index 9c2920c..9b42d8d 100644 switch (e->op) { case CEXPR_EQ: s[++sp] = mls_level_eq(l1, l2); -+ msgcat(expr_buf[expr_counter++], src, tgt, -+ "eq", s[sp] == 0); ++ msgcat(src, tgt, "eq", s[sp] == 0); ++ expr_counter++; continue; case CEXPR_NEQ: s[++sp] = !mls_level_eq(l1, l2); -+ msgcat(expr_buf[expr_counter++], src, tgt, "neq", -+ s[sp] == 0); ++ msgcat(src, tgt, "neq", s[sp] == 0); ++ expr_counter++; continue; case CEXPR_DOM: s[++sp] = mls_level_dom(l1, l2); -+ msgcat(expr_buf[expr_counter++], src, tgt, "dom", -+ s[sp] == 0); ++ msgcat(src, tgt, "dom", s[sp] == 0); ++ expr_counter++; continue; case CEXPR_DOMBY: s[++sp] = mls_level_dom(l2, l1); -+ msgcat(expr_buf[expr_counter++], src, tgt, -+ "domby", s[sp] == 0); ++ msgcat(src, tgt, "domby", s[sp] == 0); ++ expr_counter++; continue; case CEXPR_INCOMP: s[++sp] = mls_level_incomp(l2, l1); -+ msgcat(expr_buf[expr_counter++], src, tgt, -+ "incomp", s[sp] == 0); ++ msgcat(src, tgt, "incomp", s[sp] == 0); ++ expr_counter++; continue; default: BUG(); @@ -1294,11 +1383,11 @@ index 9c2920c..9b42d8d 100644 switch (e->op) { case CEXPR_EQ: s[++sp] = (val1 == val2); -+ msgcat(expr_buf[expr_counter], src, tgt, "eq", s[sp] == 0); ++ msgcat(src, tgt, "eq", s[sp] == 0); break; case CEXPR_NEQ: s[++sp] = (val1 != val2); -+ msgcat(expr_buf[expr_counter], src, tgt, "neq", s[sp] == 0); ++ msgcat(src, tgt, "neq", s[sp] == 0); break; default: BUG(); @@ -1334,33 +1423,26 @@ index 9c2920c..9b42d8d 100644 + u_r_t = CEXPR_USER; val1 = c->user; - else if (e->attr & CEXPR_ROLE) -+ if (*r_buf) { -+ 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); -+ } ++ 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) -+ if (*r_buf) { -+ 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); -+ } ++ 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; -+ if (*r_buf) { -+ 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); -+ } ++ 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(); @@ -1386,9 +1468,9 @@ index 9c2920c..9b42d8d 100644 + } + s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); -+ msgcat(expr_buf[expr_counter], src, tgt, "eq", s[sp] == 0); ++ msgcat(src, tgt, "eq", s[sp] == 0); + if (s[sp] == 0) { -+ get_names_list(e, u_r_t, expr_buf[expr_counter]); ++ get_names_list(e, u_r_t); + } break; + @@ -1409,9 +1491,9 @@ index 9c2920c..9b42d8d 100644 + } + s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); -+ msgcat(expr_buf[expr_counter], src, tgt, "neq", s[sp] == 0); ++ msgcat(src, tgt, "neq", s[sp] == 0); + if (s[sp] == 0) { -+ get_names_list(e, u_r_t, expr_buf[expr_counter]); ++ get_names_list(e, u_r_t); + } break; default: @@ -1424,33 +1506,45 @@ index 9c2920c..9b42d8d 100644 BUG(); - return 0; + goto out; - } ++ } + expr_counter++; - } - ++ } ++ + /* + * At this point each expression of the constraint is in -+ * expr_buf[n+1] and in RPN format. Now convert to 'infix' ++ * expr_list[n+1] and in RPN format. Now convert to 'infix' + */ + + /* -+ * Zero expr_counter to detect if 'BUG(); goto out;' was called -+ * as we need to release any used expr_buf malloc's. Normally they -+ * are released by the RPN to infix code. ++ * 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 */ -+ char *answer_buf[EXPR_BUFFERS] = {NULL}; ++ /* ++ * 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; -+ /* pop operands */ ++ ++ answer_list = malloc(expr_count * sizeof(*answer_list)); ++ if (!answer_list) { ++ ERR(NULL, "failed to allocate answer stack"); ++ return -ENOMEM; ++ } ++ ++ /* The pop operands */ + char *a; + char *b; + int a_len, b_len; + + /* Convert constraint from RPN to infix notation. */ -+ for (x = 0; expr_buf[x] != NULL; x++) { -+ if (strncmp(expr_buf[x], "and", 3) == 0 || strncmp(expr_buf[x], ++ 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); @@ -1458,61 +1552,95 @@ index 9c2920c..9b42d8d 100644 + a_len = strlen(a); + + /* get a buffer to hold the answer */ -+ answer_buf[answer_counter] = malloc(a_len + b_len + 8); -+ if (!answer_buf[answer_counter]) { -+ ERR(NULL, "malloc failed to allocate answer buffer"); ++ answer_list[answer_counter] = malloc(a_len + b_len + 8); ++ if (!answer_list[answer_counter]) { ++ ERR(NULL, "failed to allocate answer buffer"); + return -ENOMEM; + } -+ memset(answer_buf[answer_counter], '\0', a_len + b_len + 8); ++ memset(answer_list[answer_counter], '\0', a_len + b_len + 8); + -+ sprintf(answer_buf[answer_counter], "%s %s %s", a, expr_buf[x], b); -+ push(answer_buf[answer_counter++]); ++ 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_buf[x], "not", 3) == 0) { ++ } else if (strncmp(expr_list[x], "not", 3) == 0) { + b = pop(); + b_len = strlen(b); + -+ answer_buf[answer_counter] = malloc(b_len + 8); -+ if (!answer_buf[answer_counter]) { -+ ERR(NULL, "malloc failed to allocate answer buffer"); ++ answer_list[answer_counter] = malloc(b_len + 8); ++ if (!answer_list[answer_counter]) { ++ ERR(NULL, "failed to allocate answer buffer"); + return -ENOMEM; + } -+ memset(answer_buf[answer_counter], '\0', b_len + 8); ++ memset(answer_list[answer_counter], '\0', b_len + 8); + + if (strncmp(b, "not", 3) == 0) -+ sprintf(answer_buf[answer_counter], "%s (%s)", expr_buf[x], b); ++ sprintf(answer_list[answer_counter], "%s (%s)", expr_list[x], b); + else -+ sprintf(answer_buf[answer_counter], "%s%s", expr_buf[x], b); -+ push(answer_buf[answer_counter++]); ++ sprintf(answer_list[answer_counter], "%s%s", expr_list[x], b); ++ push(answer_list[answer_counter++]); + free(b); + } else { -+ push(expr_buf[x]); -+ } -+ } ++ 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 }; + -+ if (*r_buf) { -+ if ((s[0] == 0) || ((s[0] == 1 && (flags & SHOW_GRANTED) == SHOW_GRANTED))) { -+ strncat(*r_buf, class_buf, REASON_BUF_SIZE); -+ strncat(*r_buf, a, REASON_BUF_SIZE); -+ strncat(*r_buf, "); ", REASON_BUF_SIZE); -+ /* Constraint calculation: rc = 0 is denied, rc = 1 is granted */ -+ sprintf(tmp_buf,"Constraint %s\n", s[0] ? "GRANTED" : "DENIED"); -+ strncat(*r_buf, tmp_buf, REASON_BUF_SIZE); -+ } ++ /* ++ * 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; ++ } ++ } ++ } + } -+ free(a); ++ ++out1: + rc = s[0]; ++ free(a); + +out: + free(class_buf); + free(src); + free(tgt); ++ + if (expr_counter) { -+ for (x = 0; expr_buf[x] != NULL; x++) -+ free(expr_buf[x]); ++ for (x = 0; expr_list[x] != NULL; x++) ++ free(expr_list[x]); + } BUG_ON(sp != 0); - return s[0]; @@ -1520,29 +1648,29 @@ index 9c2920c..9b42d8d 100644 } /* -@@ -308,7 +697,9 @@ static int context_struct_compute_av(context_struct_t * scontext, +@@ -308,7 +827,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, ++ char **r_buf, + unsigned int flags) { constraint_node_t *constraint; struct role_allow *ra; -@@ -383,8 +774,8 @@ static int context_struct_compute_av(context_struct_t * scontext, +@@ -383,8 +904,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)) { ++ tclass, constraint, r_buf, flags)) { avd->allowed = (avd->allowed) & ~(constraint->permissions); } -@@ -459,8 +850,8 @@ int hidden sepol_validate_transition(sepol_security_id_t oldsid, +@@ -459,8 +980,8 @@ int hidden sepol_validate_transition(sepol_security_id_t oldsid, constraint = tclass_datum->validatetrans; while (constraint) { @@ -1553,7 +1681,7 @@ index 9c2920c..9b42d8d 100644 return -EPERM; } constraint = constraint->next; -@@ -493,11 +884,58 @@ int hidden sepol_compute_av_reason(sepol_security_id_t ssid, +@@ -493,11 +1014,59 @@ int hidden sepol_compute_av_reason(sepol_security_id_t ssid, } rc = context_struct_compute_av(scontext, tcontext, tclass, @@ -1564,9 +1692,9 @@ index 9c2920c..9b42d8d 100644 } +/* -+ * sepol_compute_av_reason_buffer - the reason buffer is malloc'd -+ * to REASON_BUF_SIZE that seems okay for the Reference Policy. -+ * TODO manage size using realloc at some stage. ++ * 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, @@ -1577,14 +1705,17 @@ index 9c2920c..9b42d8d 100644 + char **reason_buf, + unsigned int flags) +{ -+ char *r_buf = NULL; -+ -+ r_buf = malloc(REASON_BUF_SIZE); -+ if (!r_buf) { -+ ERR(NULL, "malloc failed to allocate constraint reason buffer"); ++ *reason_buf = malloc(REASON_BUF_SIZE); ++ if (!*reason_buf) { ++ ERR(NULL, "failed to allocate reason buffer"); + return -ENOMEM; + } -+ memset(r_buf, '\0', REASON_BUF_SIZE); ++ /* ++ * 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; @@ -1603,17 +1734,15 @@ index 9c2920c..9b42d8d 100644 + } + + rc = context_struct_compute_av(scontext, tcontext, tclass, -+ requested, avd, reason, r_buf, flags); -+ *reason_buf = r_buf; -+ -+ out: ++ 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, -@@ -510,6 +948,66 @@ int hidden sepol_compute_av(sepol_security_id_t ssid, +@@ -510,6 +1079,70 @@ int hidden sepol_compute_av(sepol_security_id_t ssid, } /* @@ -1655,7 +1784,7 @@ index 9c2920c..9b42d8d 100644 + } + tclass_datum = policydb->class_val_to_struct[tclass - 1]; + -+ /* Check for unique perms then the common ones */ ++ /* 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); @@ -1664,14 +1793,18 @@ index 9c2920c..9b42d8d 100644 + 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; +} @@ -1680,7 +1813,7 @@ index 9c2920c..9b42d8d 100644 * Write the security context string representation of * the context associated with `sid' into a dynamically * allocated string of the correct size. Set `*scontext' -@@ -1337,7 +1835,7 @@ int hidden sepol_get_user_sids(sepol_security_id_t fromsid, +@@ -1337,7 +1970,7 @@ int hidden sepol_get_user_sids(sepol_security_id_t fromsid, rc = context_struct_compute_av(fromcon, &usercon, SECCLASS_PROCESS, PROCESS__TRANSITION, diff --git a/libsepol.spec b/libsepol.spec index 4e83c0f..28e8b6e 100644 --- a/libsepol.spec +++ b/libsepol.spec @@ -1,7 +1,7 @@ Summary: SELinux binary policy manipulation library Name: libsepol Version: 2.1.8 -Release: 6%{?dist} +Release: 7%{?dist} License: LGPLv2+ Group: System Environment/Libraries Source: http://www.nsa.gov/selinux/archives/libsepol-%{version}.tgz @@ -101,6 +101,9 @@ exit 0 /%{_lib}/libsepol.so.1 %changelog +* Fri Jan 25 2013 Dan Walsh - 2.1.8-7 +- Update to latest patches from eparis/Upstream + * Tue Jan 8 2013 Dan Walsh - 2.1.8-6 - Fix libsepol.stack messages in audit2allow/audit2why