Re: [PATCH 4/9 v4] libsepol/cil: Process deny rules

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 9, 2023 at 5:02 PM James Carter <jwcart2@xxxxxxxxx> wrote:
>
> A deny rule is like a neverallow rule, except that permissions are
> removed rather than an error reported.
>
> (allow S1 T1 P1)
> (deny  S2 T2 P2)
>
> First, write the allow rule with all of the permissions not in the deny rule
> P3 = P1 and not P2
> (allow S1 T1 P3)
>
> Obviously, the rule is only written if P3 is not an empty list. This goes
> for the rest of the rules as well--they are only written if the source and
> target exist.
>
> The remaining rules will only involve the common permissions
> P4 = P1 and P2
>
> Next, write the allow rule for any types in S1 that are not in S2
> S3 = S1 and not S2
> (allow S3 T1 P4)
>
> Finally, write the allow rules needed to cover the types in T1 that are
> not in T2. Since, T1 and T2 might be "self", "notself", or "other", this
> requires more complicated handling. Any rule with "self" will not match
> a rule with either "notself" or "other".
>
> if (T1 is self and T2 is self) or (T1 is notself and T2 is notself) then
>   Nothing more needs to be done.
>
> The rest of the rules will depend on the intersection of S1 and S2
> which cannot be the empty set since the allow and deny rules match.
> S4 = S1 and S2
>
> if T1 is notself or T1 is other or T2 is notself or T2 is other then
>   if T1 is notself then
>     if T2 is other then
>       T = ALL and not S2
>       (allow S4 T P4)
>     else [T2 is not self, notself, or other]
>       S5 = S4 and not T2
>       S6 = S4 and T2
>       TA = ALL and not T2
>       TB = TA and not S4
>       (allow S6 TA P4)
>       (allow S5 TB P4)
>       if cardinality(S5) > 1 then
>         (allow S5 other P4)
>   else if T1 is other then
>     (allow S3 S4 P4)
>     if T2 is notself then
>       [Nothing else is needed]
>     else if T2 is other then
>       (allow S4 S3 P4)
>     else [T2 is not self, notself, or other]
>       S5 = S4 and not T2
>       S6 = S4 and T2
>       TC = S1 and not T2
>       TD = S3 and not T2
>       (allow S6 TC P4)
>       (allow S5 TD P4)
>       if cardinality(S5) > 1 then
>         (allow S5 other P4)
>   else [T1 is not self, notself, or other]
>     S8 = S4 and T1
>     (allow S8 self P4)
>     if T2 is notself then
>       [Nothing else is needed]
>     else [T2 is other]
>       T = T1 and not S2
>       (allow S4 T P4)
> else [Neither T1 nor T2 are notself or other]
>   if T1 is self and T2 is not self then
>     S5 = S4 and not T2
>     (allow S5 self P4)
>   else if T1 is not self and T2 is self then
>     S7 = S4 and not T1
>     S8 = S4 and T1
>     T8 = T1 and not S4
>     (allow S7 T1 P4)
>     (allow S8 T8 P4)
>     if cardinality(S8) > 1 then
>       (allow S8 other P4)
>   else [Neither T1 nor T2 is self]
>     T3 = T1 and not T2
>     (allow S4 T3 P4)
>
> Signed-off-by: James Carter <jwcart2@xxxxxxxxx>
> ---
>  libsepol/cil/src/cil_deny.c | 1413 +++++++++++++++++++++++++++++++++++
>  libsepol/cil/src/cil_deny.h |   36 +
>  libsepol/cil/src/cil_post.c |    7 +
>  3 files changed, 1456 insertions(+)
>  create mode 100644 libsepol/cil/src/cil_deny.c
>  create mode 100644 libsepol/cil/src/cil_deny.h
>
> diff --git a/libsepol/cil/src/cil_deny.c b/libsepol/cil/src/cil_deny.c
> new file mode 100644
> index 00000000..8db6177d
> --- /dev/null
> +++ b/libsepol/cil/src/cil_deny.c
> @@ -0,0 +1,1413 @@
> +/*
> + * This file is public domain software, i.e. not copyrighted.
> + *
> + * Warranty Exclusion
> + * ------------------
> + * You agree that this software is a non-commercially developed program
> + * that may contain "bugs" (as that term is used in the industry) and
> + * that it may not function as intended. The software is licensed
> + * "as is". NSA makes no, and hereby expressly disclaims all, warranties,
> + * express, implied, statutory, or otherwise with respect to the software,
> + * including noninfringement and the implied warranties of merchantability
> + * and fitness for a particular purpose.
> + *
> + * Limitation of Liability
> + *-----------------------
> + * In no event will NSA be liable for any damages, including loss of data,
> + * lost profits, cost of cover, or other special, incidental, consequential,
> + * direct or indirect damages arising from the software or the use thereof,
> + * however caused and on any theory of liability. This limitation will apply
> + * even if NSA has been advised of the possibility of such damage. You
> + * acknowledge that this is a reasonable allocation of risk.
> + *
> + * Original author: James Carter
> + */
> +
> +#include <sepol/policydb/ebitmap.h>
> +
> +#include "cil_internal.h"
> +#include "cil_find.h"
> +#include "cil_flavor.h"
> +#include "cil_list.h"
> +#include "cil_strpool.h"
> +#include "cil_log.h"
> +#include "cil_symtab.h"
> +#include "cil_build_ast.h"
> +#include "cil_copy_ast.h"
> +#include "cil_deny.h"
> +
> +#define CIL_DENY_ATTR_PREFIX "deny_rule_attr"
> +
> +/*
> + * A deny rule is like a neverallow rule, except that permissions are
> + * removed rather than an error reported.
> + *
> + * (allow S1 T1 P1)
> + * (deny  S2 T2 P2)
> + *
> + * First, write the allow rule with all of the permissions not in the deny rule
> + * P3 = P1 and not P2
> + * (allow S1 T1 P3)
> + *
> + * Obviously, the rule is only written if P3 is not an empty list. This goes
> + * for the rest of the rules as well--they are only written if the source and
> + * target exist.
> + *
> + * The remaining rules will only involve the common permissions
> + * P4 = P1 and P2
> + *
> + * Next, write the allow rule for any types in S1 that are not in S2
> + * S3 = S1 and not S2
> + * (allow S3 T1 P4)
> + *
> + * Finally, write any allow rules needed to cover the types in T1 that are
> + * not in T2. Since, T1 and T2 might be "self", "notself", or "other", this
> + * requires more complicated handling. Any rule with "self" will not match
> + * a rule with either "notself" or "other".
> + *
> + * if (T1 is self and T2 is self) or (T1 is notself and T2 is notself) then
> + *   Nothing more needs to be done.
> + *
> + * The rest of the rules will depend on the intersection of S1 and S2
> + * which cannot be the empty set since the allow and deny rules match.
> + * S4 = S1 and S2
> + *
> + * if T1 is notself or T1 is other or T2 is notself or T2 is other then
> + *   if T1 is notself then
> + *     if T2 is other then
> + *       T = ALL and not S2
> + *       (allow S4 T P4)
> + *     else [T2 is not self, notself, or other]
> + *       S5 = S4 and not T2
> + *       S6 = S4 and T2
> + *       TA = ALL and not T2
> + *       TB = TA and not S4
> + *       (allow S6 TA P4)
> + *       (allow S5 TB P4)
> + *       if cardinality(S5) > 1 then
> + *         (allow S5 other P4)
> + *   else if T1 is other then
> + *     (allow S3 S4 P4)
> + *     if T2 is notself then
> + *       [Nothing else is needed]
> + *     else if T2 is other then
> + *       (allow S4 S3 P4)
> + *     else [T2 is not self, notself, or other]
> + *       S5 = S4 and not T2
> + *       S6 = S4 and T2
> + *       TC = S1 and not T2
> + *       TD = S3 and not T2
> + *       (allow S6 TC P4)
> + *       (allow S5 TD P4)
> + *       if cardinality(S5) > 1 then
> + *         (allow S5 other P4)
> + *   else [T1 is not self, notself, or other]
> + *     S8 = S4 and T1
> + *     (allow S8 self P4)
> + *     if T2 is notself then
> + *       [Nothing else is needed]
> + *     else [T2 is other]
> + *       T = T1 and not S2
> + *       (allow S4 T P4)
> + * else [Neither T1 nor T2 are notself or other]
> + *   if T1 is self and T2 is not self then
> + *     S5 = S4 and not T2
> + *     (allow S5 self P4)
> + *   else if T1 is not self and T2 is self then
> + *     S7 = S4 and not T1
> + *     S8 = S4 and T1
> + *     T8 = T1 and not S4
> + *     (allow S7 T1 P4)
> + *     (allow S8 T8 P4)
> + *     if cardinality(S8) > 1 then
> + *       (allow S8 other P4)
> + *   else [Neither T1 nor T2 is self]
> + *     T3 = T1 and not T2
> + *     (allow S4 T3 P4)
> + */
> +
> +static int cil_perm_match(const struct cil_perm *p1, const struct cil_list *pl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       cil_list_for_each(curr, pl2) {
> +               struct cil_perm *p = curr->data;
> +               if (p == p1) {
> +                       return CIL_TRUE;
> +               }
> +       }
> +       return CIL_FALSE;
> +}
> +
> +static int cil_class_perm_match(const struct cil_class *c1, const struct cil_perm *p1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       cil_list_for_each(curr, cpl2) {
> +               if (curr->flavor == CIL_CLASSPERMS) {
> +                       struct cil_classperms *cp = curr->data;
> +                       if (FLAVOR(cp->class) == CIL_CLASS) {
> +                               if (cp->class == c1) {
> +                                       if (cil_perm_match(p1, cp->perms)) {
> +                                               return CIL_TRUE;
> +                                       }
> +                               }
> +                       } else { /* MAP */
> +                               struct cil_list_item *p;
> +                               cil_list_for_each(p, cp->perms) {
> +                                       struct cil_perm *cmp = p->data;
> +                                       if (cil_class_perm_match(c1, p1, cmp->classperms)) {
> +                                               return CIL_TRUE;
> +                                       }
> +                               }
> +                       }
> +               } else { /* SET */
> +                       struct cil_classperms_set *cp_set = curr->data;
> +                       struct cil_classpermission *cp = cp_set->set;
> +                       if (cil_class_perm_match(c1, p1, cp->classperms)) {
> +                               return CIL_TRUE;
> +                       }
> +               }
> +       }
> +       return CIL_FALSE;
> +}
> +
> +static int cil_classperms_match_any(const struct cil_classperms *cp1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       cil_list_for_each(curr, cp1->perms) {
> +               struct cil_perm *perm = curr->data;
> +               if (cil_class_perm_match(cp1->class, perm, cpl2)) {
> +                       return CIL_TRUE;
> +               }
> +       }
> +       return CIL_FALSE;
> +}
> +
> +int cil_classperms_list_match_any(const struct cil_list *cpl1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       if (!cpl1 || !cpl2) {
> +               return (!cpl1 && !cpl2) ? CIL_TRUE : CIL_FALSE;
> +       }
> +
> +       cil_list_for_each(curr, cpl1) {
> +               if (curr->flavor == CIL_CLASSPERMS) {
> +                       struct cil_classperms *cp = curr->data;
> +                       if (FLAVOR(cp->class) == CIL_CLASS) {
> +                               if (cil_classperms_match_any(cp, cpl2)) {
> +                                       return CIL_TRUE;
> +                               }
> +                       } else { /* MAP */
> +                               struct cil_list_item *p;
> +                               cil_list_for_each(p, cp->perms) {
> +                                       struct cil_perm *cmp = p->data;
> +                                       if (cil_classperms_list_match_any(cmp->classperms, cpl2)) {
> +                                               return CIL_TRUE;
> +                                       }
> +                               }
> +                       }
> +               } else { /* SET */
> +                       struct cil_classperms_set *cp_set = curr->data;
> +                       struct cil_classpermission *cp = cp_set->set;
> +                       if (cil_classperms_list_match_any(cp->classperms, cpl2)) {
> +                               return CIL_TRUE;
> +                       }
> +               }
> +       }
> +       return CIL_FALSE;
> +}
> +
> +static int cil_classperms_match_all(const struct cil_classperms *cp1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       cil_list_for_each(curr, cp1->perms) {
> +               struct cil_perm *perm = curr->data;
> +               if (!cil_class_perm_match(cp1->class, perm, cpl2)) {
> +                       return CIL_FALSE;
> +               }
> +       }
> +       return CIL_TRUE;
> +}
> +
> +int cil_classperms_list_match_all(const struct cil_list *cpl1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       if (!cpl1 || !cpl2) {
> +               return (!cpl1 && !cpl2) ? CIL_TRUE : CIL_FALSE;
> +       }
> +
> +       cil_list_for_each(curr, cpl1) {
> +               if (curr->flavor == CIL_CLASSPERMS) {
> +                       struct cil_classperms *cp = curr->data;
> +                       if (FLAVOR(cp->class) == CIL_CLASS) {
> +                               if (!cil_classperms_match_all(cp, cpl2)) {
> +                                       return CIL_FALSE;
> +                               }
> +                       } else { /* MAP */
> +                               struct cil_list_item *p;
> +                               cil_list_for_each(p, cp->perms) {
> +                                       struct cil_perm *cmp = p->data;
> +                                       if (!cil_classperms_list_match_all(cmp->classperms, cpl2)) {
> +                                               return CIL_FALSE;
> +                                       }
> +                               }
> +                       }
> +               } else { /* SET */
> +                       struct cil_classperms_set *cp_set = curr->data;
> +                       struct cil_classpermission *cp = cp_set->set;
> +                       if (!cil_classperms_list_match_all(cp->classperms, cpl2)) {
> +                               return CIL_FALSE;
> +                       }
> +               }
> +       }
> +       return CIL_TRUE;
> +}
> +
> +static void cil_classperms_copy(struct cil_classperms **new, const struct cil_classperms *old)
> +{
> +       cil_classperms_init(new);
> +       (*new)->class_str = old->class_str;
> +       (*new)->class = old->class;
> +       cil_copy_list(old->perm_strs, &(*new)->perm_strs);
> +       cil_copy_list(old->perms, &(*new)->perms);
> +}
> +
> +static void cil_classperms_set_copy(struct cil_classperms_set **new, const struct cil_classperms_set *old)
> +{
> +       cil_classperms_set_init(new);
> +       (*new)->set_str = old->set_str;
> +       (*new)->set = old->set;
> +}
> +
> +void cil_classperms_list_copy(struct cil_list **new, const struct cil_list *old)
> +{
> +       struct cil_list_item *curr;
> +
> +       if (!new) {
> +               return;
> +       }
> +
> +       if (!old) {
> +               *new = NULL;
> +               return;
> +       }
> +
> +       cil_list_init(new, CIL_LIST);
> +
> +       cil_list_for_each(curr, old) {
> +               if (curr->flavor == CIL_CLASSPERMS) {
> +                       struct cil_classperms *new_cp;
> +                       cil_classperms_copy(&new_cp, curr->data);
> +                       cil_list_append(*new, CIL_CLASSPERMS, new_cp);
> +               } else { /* SET */
> +                       struct cil_classperms_set *new_cps;
> +                       cil_classperms_set_copy(&new_cps, curr->data);
> +                       cil_list_append(*new, CIL_CLASSPERMS_SET, new_cps);
> +               }
> +       }
> +
> +       if (cil_list_is_empty(*new)) {
> +               cil_list_destroy(new, CIL_FALSE);
> +       }
> +}
> +
> +/* Append cp1 and cpl2 to result */
> +static void cil_classperms_and(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2)
> +{
> +       struct cil_classperms *new_cp = NULL;
> +       struct cil_list_item *curr;
> +
> +       if (cil_classperms_match_all(cp1, cpl2)) {
> +               cil_classperms_copy(&new_cp, cp1);
> +               cil_list_append(*result, CIL_CLASSPERMS, new_cp);
> +               return;
> +       }
> +
> +       cil_list_for_each(curr, cp1->perms) {
> +               struct cil_perm *perm = curr->data;
> +               if (cil_class_perm_match(cp1->class, perm, cpl2)) {
> +                       if (new_cp == NULL) {
> +                               cil_classperms_init(&new_cp);
> +                               new_cp->class_str = cp1->class_str;
> +                               new_cp->class = cp1->class;
> +                               cil_list_init(&new_cp->perm_strs, CIL_PERM);
> +                               cil_list_init(&new_cp->perms, CIL_PERM);
> +                               cil_list_append(*result, CIL_CLASSPERMS, new_cp);
> +                       }
> +                       cil_list_append(new_cp->perm_strs, CIL_STRING, perm->datum.fqn);
> +                       cil_list_append(new_cp->perms, CIL_DATUM, perm);
> +               }
> +       }
> +}
> +
> +/* Append cp1 and cpl2 to result */
> +static void cil_classperms_map_and(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2)
> +{
> +       struct cil_classperms *new_cp = NULL;
> +       struct cil_list_item *p;
> +
> +       cil_list_for_each(p, cp1->perms) {
> +               struct cil_perm *map_perm = p->data;
> +               if (cil_classperms_list_match_all(map_perm->classperms, cpl2)) {
> +                       if (new_cp == NULL) {
> +                               cil_classperms_init(&new_cp);
> +                               new_cp->class_str = cp1->class_str;
> +                               new_cp->class = cp1->class;
> +                               cil_list_init(&new_cp->perm_strs, CIL_PERM);
> +                               cil_list_init(&new_cp->perms, CIL_PERM);
> +                               cil_list_append(*result, CIL_CLASSPERMS, new_cp);
> +                       }
> +                       cil_list_append(new_cp->perm_strs, CIL_STRING, map_perm->datum.fqn);
> +                       cil_list_append(new_cp->perms, CIL_DATUM, map_perm);
> +               } else {
> +                       struct cil_list *new_cpl = NULL;
> +                       cil_classperms_list_and(&new_cpl, map_perm->classperms, cpl2);
> +                       if (new_cpl) {
> +                               struct cil_list_item *i;
> +                               cil_list_for_each(i, new_cpl) {
> +                                       cil_list_append(*result, i->flavor, i->data);
> +                               }
> +                               cil_list_destroy(&new_cpl, CIL_FALSE);
> +                       }
> +               }
> +       }
> +}
> +
> +/* Append cps1 and cpl2 to result */
> +static void cil_classperms_set_and(struct cil_list **result, const struct cil_classperms_set *cps1, const struct cil_list *cpl2)
> +{
> +       struct cil_classpermission *cp = cps1->set;
> +
> +       if (cil_classperms_list_match_all(cp->classperms, cpl2)) {
> +               struct cil_classperms_set *new_cps;
> +               cil_classperms_set_copy(&new_cps, cps1);
> +               cil_list_append(*result, CIL_CLASSPERMS_SET, new_cps);
> +       } else {
> +               struct cil_list *new_cpl;
> +               cil_classperms_list_and(&new_cpl, cp->classperms, cpl2);
> +               if (new_cpl) {
> +                       struct cil_list_item *i;
> +                       cil_list_for_each(i, new_cpl) {
> +                               cil_list_append(*result, i->flavor, i->data);
> +                       }
> +                       cil_list_destroy(&new_cpl, CIL_FALSE);
> +               }
> +       }
> +}
> +
> +/* result = cpl1 and cpl2 */
> +void cil_classperms_list_and(struct cil_list **result, const struct cil_list *cpl1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       if (!result) {
> +               return;
> +       }
> +
> +       if (!cpl1 || !cpl2) {
> +               *result = NULL;
> +               return;
> +       }
> +
> +       if (cil_classperms_list_match_all(cpl1, cpl2)) {
> +               cil_classperms_list_copy(result, cpl1);
> +               return;
> +       }
> +
> +       cil_list_init(result, CIL_LIST);
> +
> +       cil_list_for_each(curr, cpl1) {
> +               if (curr->flavor == CIL_CLASSPERMS) {
> +                       struct cil_classperms *cp = curr->data;
> +                       if (FLAVOR(cp->class) == CIL_CLASS) {
> +                               cil_classperms_and(result, cp, cpl2);
> +                       } else { /* MAP */
> +                               cil_classperms_map_and(result, cp, cpl2);
> +                       }
> +               } else { /* SET */
> +                       struct cil_classperms_set *cps = curr->data;
> +                       cil_classperms_set_and(result, cps, cpl2);
> +               }
> +       }
> +
> +       if (cil_list_is_empty(*result)) {
> +               cil_list_destroy(result, CIL_FALSE);
> +       }
> +}
> +
> +/* Append cp1 and not cpl2 to result */
> +static void cil_classperms_andnot(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2)
> +{
> +       struct cil_classperms *new_cp = NULL;
> +       struct cil_list_item *curr;
> +
> +       if (!cil_classperms_match_any(cp1, cpl2)) {
> +               cil_classperms_copy(&new_cp, cp1);
> +               cil_list_append(*result, CIL_CLASSPERMS, new_cp);
> +               return;
> +       }
> +
> +       cil_list_for_each(curr, cp1->perms) {
> +               struct cil_perm *perm = curr->data;
> +               if (!cil_class_perm_match(cp1->class, perm, cpl2)) {
> +                       if (new_cp == NULL) {
> +                               cil_classperms_init(&new_cp);
> +                               new_cp->class_str = cp1->class_str;
> +                               new_cp->class = cp1->class;
> +                               cil_list_init(&new_cp->perm_strs, CIL_PERM);
> +                               cil_list_init(&new_cp->perms, CIL_PERM);
> +                               cil_list_append(*result, CIL_CLASSPERMS, new_cp);
> +                       }
> +                       cil_list_append(new_cp->perm_strs, CIL_STRING, perm->datum.fqn);
> +                       cil_list_append(new_cp->perms, CIL_DATUM, perm);
> +               }
> +       }
> +}
> +
> +/* Append cp1 and not cpl2 to result */
> +static void cil_classperms_map_andnot(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2)
> +{
> +       struct cil_classperms *new_cp = NULL;
> +       struct cil_list_item *p;
> +
> +       cil_list_for_each(p, cp1->perms) {
> +               struct cil_perm *map_perm = p->data;
> +               if (!cil_classperms_list_match_any(map_perm->classperms, cpl2)) {
> +                       if (new_cp == NULL) {
> +                               cil_classperms_init(&new_cp);
> +                               new_cp->class_str = cp1->class_str;
> +                               new_cp->class = cp1->class;
> +                               cil_list_init(&new_cp->perm_strs, CIL_PERM);
> +                               cil_list_init(&new_cp->perms, CIL_PERM);
> +                               cil_list_append(*result, CIL_CLASSPERMS, new_cp);
> +                       }
> +                       cil_list_append(new_cp->perm_strs, CIL_STRING, map_perm->datum.fqn);
> +                       cil_list_append(new_cp->perms, CIL_DATUM, map_perm);
> +               } else {
> +                       struct cil_list *new_cpl = NULL;
> +                       cil_classperms_list_andnot(&new_cpl, map_perm->classperms, cpl2);
> +                       if (new_cpl) {
> +                               struct cil_list_item *i;
> +                               cil_list_for_each(i, new_cpl) {
> +                                       cil_list_append(*result, i->flavor, i->data);
> +                               }
> +                               cil_list_destroy(&new_cpl, CIL_FALSE);
> +                       }
> +               }
> +       }
> +}
> +
> +/* Append cps1 and not cpl2 to result */
> +static void cil_classperms_set_andnot(struct cil_list **result, const struct cil_classperms_set *cps1, const struct cil_list *cpl2)
> +{
> +       struct cil_classpermission *cp = cps1->set;
> +
> +       if (!cil_classperms_list_match_any(cp->classperms, cpl2)) {
> +               struct cil_classperms_set *new_cps;
> +               cil_classperms_set_copy(&new_cps, cps1);
> +               cil_list_append(*result, CIL_CLASSPERMS_SET, new_cps);
> +       } else {
> +               struct cil_list *new_cpl;
> +               cil_classperms_list_andnot(&new_cpl, cp->classperms, cpl2);
> +               if (new_cpl) {
> +                       struct cil_list_item *i;
> +                       cil_list_for_each(i, new_cpl) {
> +                               cil_list_append(*result, i->flavor, i->data);
> +                       }
> +                       cil_list_destroy(&new_cpl, CIL_FALSE);
> +               }
> +       }
> +}
> +
> +/* result = cpl1 and not cpl2 */
> +void cil_classperms_list_andnot(struct cil_list **result, const struct cil_list *cpl1, const struct cil_list *cpl2)
> +{
> +       struct cil_list_item *curr;
> +
> +       if (!result) {
> +               return;
> +       }
> +
> +       if (!cpl1) {
> +               *result = NULL;
> +               return;
> +       }
> +
> +       if (!cpl2 || !cil_classperms_list_match_any(cpl1, cpl2)) {
> +               cil_classperms_list_copy(result, cpl1);
> +               return;
> +       }
> +
> +       cil_list_init(result, CIL_LIST);
> +
> +       cil_list_for_each(curr, cpl1) {
> +               if (curr->flavor == CIL_CLASSPERMS) {
> +                       struct cil_classperms *cp = curr->data;
> +                       if (FLAVOR(cp->class) == CIL_CLASS) {
> +                               cil_classperms_andnot(result, cp, cpl2);
> +                       } else { /* MAP */
> +                               cil_classperms_map_andnot(result, cp, cpl2);
> +                       }
> +               } else { /* SET */
> +                       struct cil_classperms_set *cps = curr->data;
> +                       cil_classperms_set_andnot(result, cps, cpl2);
> +               }
> +       }
> +
> +       if (cil_list_is_empty(*result)) {
> +               cil_list_destroy(result, CIL_FALSE);
> +       }
> +}
> +
> +static int cil_datum_cardinality(const struct cil_symtab_datum *d)
> +{
> +       if (!d) {
> +               return 0;
> +       }
> +       if (FLAVOR(d) != CIL_TYPEATTRIBUTE) {
> +               return 1;
> +       } else {
> +               struct cil_typeattribute *a = (struct cil_typeattribute *)d;
> +               return ebitmap_cardinality(a->types);
> +       }
> +}
> +
> +/* result = ALL and not d2 */
> +static int cil_datum_not(ebitmap_t *result, const struct cil_symtab_datum *d, int max)
> +{
> +       int rc = SEPOL_OK;
> +
> +       if (FLAVOR(d) != CIL_TYPEATTRIBUTE) {
> +               struct cil_type *t = (struct cil_type *)d;
> +               ebitmap_t e;
> +
> +               ebitmap_init(&e);
> +               rc = ebitmap_set_bit(&e, t->value, 1);
> +               if (rc != SEPOL_OK) {
> +                       ebitmap_destroy(&e);
> +                       goto exit;
> +               }
> +
> +               ebitmap_init(result);
> +               rc = ebitmap_not(result, &e, max);
> +               if (rc != SEPOL_OK) {
> +                       ebitmap_destroy(&e);
> +                       ebitmap_destroy(result);
> +                       goto exit;
> +               }
> +               ebitmap_destroy(&e);
> +       } else {
> +               struct cil_typeattribute *a = (struct cil_typeattribute *)d;
> +
> +               ebitmap_init(result);
> +               rc = ebitmap_not(result, a->types, max);
> +               if (rc != SEPOL_OK) {
> +                       ebitmap_destroy(result);
> +                       goto exit;
> +               }
> +       }
> +exit:
> +       return rc;
> +}
> +
> +/* result = d1 and d2 */
> +static int cil_datums_and(ebitmap_t *result, const struct cil_symtab_datum *d1, const struct cil_symtab_datum *d2)
> +{
> +       int rc = SEPOL_OK;
> +       enum cil_flavor f1 = FLAVOR(d1);
> +       enum cil_flavor f2 = FLAVOR(d2);
> +
> +       if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
> +               struct cil_type *t1 = (struct cil_type *)d1;
> +               struct cil_type *t2 = (struct cil_type *)d2;
> +               ebitmap_init(result);
> +               if (t1->value == t2->value) {
> +                       rc = ebitmap_set_bit(result, t1->value, 1);
> +                       if (rc != SEPOL_OK) {
> +                               ebitmap_destroy(result);
> +                               goto exit;
> +                       }
> +               }
> +       } else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
> +               struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
> +               struct cil_type *t2 = (struct cil_type *)d2;
> +               ebitmap_init(result);
> +               if (ebitmap_get_bit(a1->types, t2->value)) {
> +                       rc = ebitmap_set_bit(result, t2->value, 1);
> +                       if (rc != SEPOL_OK) {
> +                               ebitmap_destroy(result);
> +                               goto exit;
> +                       }
> +               }
> +       } else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
> +               struct cil_type *t1 = (struct cil_type *)d1;
> +               struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
> +               ebitmap_init(result);
> +               if (ebitmap_get_bit(a2->types, t1->value)) {
> +                       rc = ebitmap_set_bit(result, t1->value, 1);
> +                       if (rc != SEPOL_OK) {
> +                               ebitmap_destroy(result);
> +                               goto exit;
> +                       }
> +               }
> +       } else {
> +               /* Both are attributes */
> +               struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
> +               struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
> +               rc = ebitmap_and(result, a1->types, a2->types);
> +               if (rc != SEPOL_OK) {
> +                       ebitmap_destroy(result);
> +                       goto exit;
> +               }
> +       }
> +exit:
> +       return rc;
> +}
> +
> +/* result = d1 and not d2 */
> +static int cil_datums_andnot(ebitmap_t *result, const struct cil_symtab_datum *d1, const struct cil_symtab_datum *d2)
> +{
> +       int rc = SEPOL_OK;
> +       enum cil_flavor f1 = FLAVOR(d1);
> +       enum cil_flavor f2 = FLAVOR(d2);
> +
> +       if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
> +               struct cil_type *t1 = (struct cil_type *)d1;
> +               struct cil_type *t2 = (struct cil_type *)d2;
> +               ebitmap_init(result);
> +               if (t1->value != t2->value) {
> +                       rc = ebitmap_set_bit(result, t1->value, 1);
> +                       if (rc != SEPOL_OK) {
> +                               ebitmap_destroy(result);
> +                               goto exit;
> +                       }
> +               }
> +       } else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
> +               struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
> +               struct cil_type *t2 = (struct cil_type *)d2;
> +               rc = ebitmap_cpy(result, a1->types);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               rc = ebitmap_set_bit(result, t2->value, 0);
> +               if (rc != SEPOL_OK) {
> +                       ebitmap_destroy(result);
> +                       goto exit;
> +               }
> +       } else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
> +               struct cil_type *t1 = (struct cil_type *)d1;
> +               struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
> +               ebitmap_init(result);
> +               if (!ebitmap_get_bit(a2->types, t1->value)) {
> +                       rc = ebitmap_set_bit(result, t1->value, 1);
> +                       if (rc != SEPOL_OK) {
> +                               ebitmap_destroy(result);
> +                               goto exit;
> +                       }
> +               }
> +       } else {
> +               /* Both are attributes */
> +               struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
> +               struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
> +               rc = ebitmap_andnot(result, a1->types, a2->types, a1->types->highbit);
> +               if (rc != SEPOL_OK) {
> +                       ebitmap_destroy(result);
> +                       goto exit;
> +               }
> +       }
> +exit:
> +       return rc;
> +}
> +
> +static size_t num_digits(unsigned n)
> +{
> +       size_t num = 1;
> +       while (n >= 10) {
> +               n /= 10;
> +               num++;
> +       }
> +       return num;
> +}
> +
> +static char *cil_create_new_attribute_name(unsigned num)
> +{
> +       char *s1 = NULL;
> +       char *s2 = NULL;
> +       size_t len_num = num_digits(num);
> +       size_t len = strlen(CIL_DENY_ATTR_PREFIX) + 1 + len_num + 1;
> +       int rc;
> +
> +       if (len >= CIL_MAX_NAME_LENGTH) {
> +               cil_log(CIL_ERR, "Name length greater than max name length of %d",
> +                               CIL_MAX_NAME_LENGTH);
> +               goto exit;
> +       }
> +
> +       s1 = cil_malloc(len);
> +       rc = snprintf(s1, len, "%s_%u", CIL_DENY_ATTR_PREFIX, num);
> +       if (rc < 0 || (size_t)rc >= len) {
> +               cil_log(CIL_ERR, "Error creating new attribute name");
> +               free(s1);
> +               goto exit;
> +       }
> +
> +       s2 = cil_strpool_add(s1);
> +       free(s1);
> +
> +exit:
> +       return s2;
> +}
> +
> +static struct cil_list *cil_create_and_expr_list(enum cil_flavor f1, void *v1, enum cil_flavor f2, void *v2)
> +{
> +       struct cil_list *expr;
> +
> +       cil_list_init(&expr, CIL_TYPE);
> +       cil_list_append(expr, CIL_OP, (void *)CIL_AND);
> +       cil_list_append(expr, f1, v1);
> +       cil_list_append(expr, f2, v2);
> +
> +       return expr;
> +}
> +
> +static struct cil_list *cil_create_andnot_expr_list(enum cil_flavor f1, void *v1, enum cil_flavor f2, void *v2)
> +{
> +       struct cil_list *expr, *sub_expr;
> +
> +       cil_list_init(&expr, CIL_TYPE);
> +       cil_list_append(expr, CIL_OP, (void *)CIL_AND);
> +       cil_list_append(expr, f1, v1);
> +       cil_list_init(&sub_expr, CIL_TYPE);
> +       cil_list_append(sub_expr, CIL_OP, (void *)CIL_NOT);
> +       cil_list_append(sub_expr, f2, v2);
> +       cil_list_append(expr, CIL_LIST, sub_expr);
> +
> +       return expr;
> +}
> +
> +static struct cil_tree_node *cil_create_and_insert_node(struct cil_tree_node *prev, enum cil_flavor flavor, void *data)
> +{
> +       struct cil_tree_node *new;
> +
> +       cil_tree_node_init(&new);
> +       new->parent = prev->parent;
> +       new->line = prev->line;
> +       new->hll_offset = prev->hll_offset;
> +       new->flavor = flavor;
> +       new->data = data;
> +       new->next = prev->next;
> +       prev->next = new;
> +
> +       return new;
> +}
> +
> +static int cil_create_and_insert_attribute_and_set(struct cil_db *db, struct cil_tree_node *prev, struct cil_list *str_expr, struct cil_list *datum_expr, ebitmap_t *types, struct cil_symtab_datum **d)
> +{
> +       struct cil_tree_node *attr_node = NULL;
> +       char *name;
> +       struct cil_typeattribute *attr = NULL;
> +       struct cil_tree_node *attrset_node = NULL;
> +       struct cil_typeattributeset *attrset = NULL;
> +       symtab_t *symtab = NULL;
> +       int rc = SEPOL_ERR;
> +
> +       name = cil_create_new_attribute_name(db->num_types_and_attrs);
> +       if (!name) {
> +               goto exit;
> +       }
> +
> +       cil_typeattributeset_init(&attrset);
> +       attrset->attr_str = name;
> +       attrset->str_expr = str_expr;
> +       attrset->datum_expr = datum_expr;
> +
> +       cil_typeattribute_init(&attr);
> +       cil_list_init(&attr->expr_list, CIL_TYPE);
> +       cil_list_append(attr->expr_list, CIL_LIST, datum_expr);
> +       attr->types = types;
> +       attr->used = CIL_ATTR_AVRULE;
> +       attr->keep = (ebitmap_cardinality(types) < db->attrs_expand_size) ? CIL_FALSE : CIL_TRUE;
> +
> +       attr_node = cil_create_and_insert_node(prev, CIL_TYPEATTRIBUTE, attr);
> +       attrset_node = cil_create_and_insert_node(attr_node, CIL_TYPEATTRIBUTESET, attrset);
> +
> +       rc = cil_get_symtab(prev->parent, &symtab, CIL_SYM_TYPES);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       rc = cil_symtab_insert(symtab, name, &attr->datum, attr_node);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       db->num_types_and_attrs++;
> +
> +       *d = &attr->datum;
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       if (attr_node) {
> +               cil_destroy_typeattribute(attr_node->data); // This will not destroy datum_expr
> +               free(attr_node);
> +       }
> +       if (attrset_node) {
> +               prev->next = attrset_node->next;
> +               free(attrset_node);
> +       }
> +       return rc;
> +}
> +
> +struct attr_symtab_map_data {
> +       struct cil_symtab_datum *d;
> +       ebitmap_t *types;
> +};
> +
> +static int cil_check_attribute_in_symtab(__attribute__((unused))hashtab_key_t k, hashtab_datum_t d, void *args)
> +{
> +       struct attr_symtab_map_data *data = args;
> +
> +       if (FLAVOR(d) == CIL_TYPEATTRIBUTE) {
> +               struct cil_typeattribute *attr = (struct cil_typeattribute *)d;
> +               if (ebitmap_cmp(data->types, attr->types)) {
> +                       data->d = d;
> +               }
> +       }
> +       return SEPOL_OK;
> +}
> +
> +static struct cil_symtab_datum *cil_check_for_previously_defined_attribute(struct cil_db *db, ebitmap_t *types, struct cil_symtab_datum *d)
> +{
> +       symtab_t *local_symtab, *root_symtab;
> +       struct attr_symtab_map_data data;
> +       int rc;
> +
> +       data.d = NULL;
> +       data.types = types;
> +
> +       local_symtab = d->symtab;
> +       root_symtab = &((struct cil_root *)db->ast->root->data)->symtab[CIL_SYM_TYPES];
> +
> +       if (local_symtab != root_symtab) {
> +               rc = cil_symtab_map(local_symtab, cil_check_attribute_in_symtab, &data);
> +               if (rc != SEPOL_OK) {
> +                       return NULL;
> +               }
> +       }
> +
> +       if (!data.d) {
> +               rc = cil_symtab_map(root_symtab, cil_check_attribute_in_symtab, &data);
> +               if (rc != SEPOL_OK) {
> +                       return NULL;
> +               }
> +       }
> +
> +       return data.d;
> +}
> +
> +static int cil_create_attribute_all_and_not_d(struct cil_db *db, struct cil_symtab_datum *d, struct cil_symtab_datum **d3)
> +{
> +       struct cil_list *str_expr;
> +       struct cil_list *datum_expr;
> +       ebitmap_t *types;
> +       int rc;
> +
> +       *d3 = NULL;
> +
> +       if (!d) {
> +               return SEPOL_ERR;
> +       }
> +
> +       str_expr = cil_create_andnot_expr_list(CIL_OP, (void *)CIL_ALL, CIL_STRING, d->fqn);
> +       datum_expr = cil_create_andnot_expr_list(CIL_OP, (void *)CIL_ALL, CIL_DATUM, d);
> +
> +       types = cil_malloc(sizeof(*types));
> +       rc = cil_datum_not(types, d, db->num_types);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       if (ebitmap_is_empty(types)) {
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       if (ebitmap_cardinality(types) == 1) {
> +               unsigned i = ebitmap_highest_set_bit(types);
> +               *d3 = DATUM(db->val_to_type[i]);
> +               ebitmap_destroy(types);
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       *d3 = cil_check_for_previously_defined_attribute(db, types, d);
> +       if (*d3) {
> +               ebitmap_destroy(types);
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       rc = cil_create_and_insert_attribute_and_set(db, NODE(d), str_expr, datum_expr, types, d3);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       cil_list_destroy(&str_expr, CIL_FALSE);
> +       cil_list_destroy(&datum_expr, CIL_FALSE);
> +       free(types);
> +       return rc;
> +}
> +
> +static int cil_create_attribute_d1_and_not_d2(struct cil_db *db, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2, struct cil_symtab_datum **d3)
> +{
> +       struct cil_list *str_expr;
> +       struct cil_list *datum_expr;
> +       ebitmap_t *types;
> +       int rc;
> +
> +       if (!d2) {
> +               *d3 = d1;
> +               return SEPOL_OK;
> +       }
> +
> +       *d3 = NULL;
> +
> +       if (!d1 || d1 == d2) {
> +               return SEPOL_OK;
> +       }
> +
> +       str_expr = cil_create_andnot_expr_list(CIL_STRING, d1->fqn, CIL_STRING, d2->fqn);
> +       datum_expr = cil_create_andnot_expr_list(CIL_DATUM, d1, CIL_DATUM, d2);
> +
> +       types = cil_malloc(sizeof(*types));
> +       rc = cil_datums_andnot(types, d1, d2);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +       if (ebitmap_is_empty(types)) {
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       if (ebitmap_cardinality(types) == 1) {
> +               unsigned i = ebitmap_highest_set_bit(types);
> +               *d3 = DATUM(db->val_to_type[i]);
> +               ebitmap_destroy(types);
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       *d3 = cil_check_for_previously_defined_attribute(db, types, d1);
> +       if (*d3) {
> +               ebitmap_destroy(types);
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       rc = cil_create_and_insert_attribute_and_set(db, NODE(d1), str_expr, datum_expr, types, d3);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       cil_list_destroy(&str_expr, CIL_FALSE);
> +       cil_list_destroy(&datum_expr, CIL_FALSE);
> +       free(types);
> +       return rc;
> +}
> +
> +static int cil_create_attribute_d1_and_d2(struct cil_db *db, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2, struct cil_symtab_datum **d3)
> +{
> +       struct cil_list *str_expr;
> +       struct cil_list *datum_expr;
> +       ebitmap_t *types;
> +       int rc;
> +
> +       if (d1 == d2) {
> +               *d3 = d1;
> +               return SEPOL_OK;
> +       }
> +
> +       *d3 = NULL;
> +
> +       if (!d1 || !d2) {
> +               return SEPOL_OK;
> +       }
> +
> +       str_expr = cil_create_and_expr_list(CIL_STRING, d1->fqn, CIL_STRING, d2->fqn);
> +       datum_expr = cil_create_and_expr_list(CIL_DATUM, d1, CIL_DATUM, d2);
> +
> +       types = cil_malloc(sizeof(*types));
> +       rc = cil_datums_and(types, d1, d2);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +       if (ebitmap_is_empty(types)) {
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       if (ebitmap_cardinality(types) == 1) {
> +               unsigned i = ebitmap_highest_set_bit(types);
> +               *d3 = DATUM(db->val_to_type[i]);
> +               ebitmap_destroy(types);
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       *d3 = cil_check_for_previously_defined_attribute(db, types, d1);
> +       if (*d3) {
> +               ebitmap_destroy(types);
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       rc = cil_create_and_insert_attribute_and_set(db, NODE(d1), str_expr, datum_expr, types, d3);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       return SEPOL_OK;
> +
> +exit:
> +       cil_list_destroy(&str_expr, CIL_FALSE);
> +       cil_list_destroy(&datum_expr, CIL_FALSE);
> +       free(types);
> +       return rc;
> +}
> +
> +static struct cil_avrule *cil_create_avrule(struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms)
> +{
> +       struct cil_avrule *new;
> +
> +       cil_avrule_init(&new);
> +       new->is_extended = CIL_FALSE;
> +       new->rule_kind = CIL_AVRULE_ALLOWED;
> +       new->src_str = src->name;
> +       new->src = src;
> +       new->tgt_str = tgt->name;
> +       new->tgt = tgt;
> +       new->perms.classperms = classperms;
> +
> +       return new;
> +}
> +
> +static struct cil_tree_node *cil_create_and_add_avrule(struct cil_tree_node *curr, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms)
> +{
> +       struct cil_avrule *new_avrule;
> +       struct cil_list *new_cp_list;
> +
> +       if (!src || !tgt) {
> +               return curr;
> +       }
> +
> +       cil_classperms_list_copy(&new_cp_list, classperms);
> +       new_avrule = cil_create_avrule(src, tgt, new_cp_list);
> +       return cil_create_and_insert_node(curr, CIL_AVRULE, new_avrule);
> +}
> +
> +static int cil_remove_permissions_from_special_rule(struct cil_db *db, struct cil_tree_node *curr, struct cil_symtab_datum *s1, struct cil_symtab_datum *t1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2, struct cil_list *p4, struct cil_symtab_datum *s3, struct cil_symtab_datum *s4)
> +{
> +       int rc;
> +
> +       if (t1 == DATUM(db->notselftype)) {
> +               if (t2 == DATUM(db->othertype)) {
> +                       struct cil_symtab_datum *t;
> +                       rc = cil_create_attribute_all_and_not_d(db, s2, &t);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       curr = cil_create_and_add_avrule(curr, s4, t, p4);
> +               } else {
> +                       struct cil_symtab_datum *s5, *s6, *ta, *tb;
> +                       rc = cil_create_attribute_d1_and_not_d2(db, s4, t2, &s5);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       rc = cil_create_attribute_d1_and_d2(db, s4, t2, &s6);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       rc = cil_create_attribute_all_and_not_d(db, t2, &ta);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       rc = cil_create_attribute_d1_and_not_d2(db, ta, s4, &tb);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       curr = cil_create_and_add_avrule(curr, s6, ta, p4);
> +                       curr = cil_create_and_add_avrule(curr, s5, tb, p4);
> +                       if (cil_datum_cardinality(s5) > 1) {
> +                               curr = cil_create_and_add_avrule(curr, s5, DATUM(db->othertype), p4);
> +                       }
> +               }
> +       } else if (t1 == DATUM(db->othertype)) {
> +               curr = cil_create_and_add_avrule(curr, s3, s4, p4);
> +               if (t2 == DATUM(db->notselftype)) {
> +                       /* Nothing else is needed */
> +               } else if (t2 == DATUM(db->othertype)) {
> +                       curr = cil_create_and_add_avrule(curr, s4, s3, p4);
> +               } else {
> +                       struct cil_symtab_datum *s5, *s6, *tc, *td;
> +                       rc = cil_create_attribute_d1_and_not_d2(db, s4, t2, &s5);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       rc = cil_create_attribute_d1_and_d2(db, s4, t2, &s6);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       rc = cil_create_attribute_d1_and_not_d2(db, s1, t2, &tc);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       rc = cil_create_attribute_d1_and_not_d2(db, s3, t2, &td);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       curr = cil_create_and_add_avrule(curr, s6, tc, p4);
> +                       curr = cil_create_and_add_avrule(curr, s5, td, p4);
> +                       if (cil_datum_cardinality(s5) > 1) {
> +                               curr = cil_create_and_add_avrule(curr, s5, DATUM(db->othertype), p4);
> +                       }
> +               }
> +       } else {
> +               struct cil_symtab_datum *s8;
> +               rc = cil_create_attribute_d1_and_d2(db, s4, t1, &s8);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               curr = cil_create_and_add_avrule(curr, s8, DATUM(db->selftype), p4);
> +               if (t2 == DATUM(db->notselftype)) {
> +                       /* Nothing else is needed */
> +               } else { /* t2 == DATUM(db->othertype) */
> +                       struct cil_symtab_datum *t;
> +                       rc = cil_create_attribute_d1_and_not_d2(db, t1, s2, &t);
> +                       if (rc != SEPOL_OK) {
> +                               goto exit;
> +                       }
> +                       curr = cil_create_and_add_avrule(curr, s4, t, p4);
> +               }
> +       }
> +       return SEPOL_OK;
> +
> +exit:
> +       return rc;
> +}
> +
> +static int cil_remove_permissions_from_rule(struct cil_db *db, struct cil_tree_node *allow_node, const struct cil_tree_node *deny_node)
> +{
> +       struct cil_avrule *allow_rule = allow_node->data;
> +       struct cil_deny_rule *deny_rule = deny_node->data;
> +       struct cil_symtab_datum *s1 = allow_rule->src;
> +       struct cil_symtab_datum *t1 = allow_rule->tgt;
> +       struct cil_list *p1 = allow_rule->perms.classperms;
> +       struct cil_symtab_datum *s2 = deny_rule->src;
> +       struct cil_symtab_datum *t2 = deny_rule->tgt;
> +       struct cil_list *p2 = deny_rule->classperms;
> +       struct cil_list *p3 = NULL;
> +       struct cil_list *p4 = NULL;
> +       struct cil_symtab_datum *s3, *s4;
> +       struct cil_tree_node *curr = allow_node;
> +       int rc;
> +
> +       cil_classperms_list_andnot(&p3, p1, p2);
> +       if (!cil_list_is_empty(p3)) {;
> +               curr = cil_create_and_add_avrule(curr, s1, t1, p3);
> +       }
> +       cil_destroy_classperms_list(&p3);
> +       p3 = NULL;
> +
> +       cil_classperms_list_and(&p4, p1, p2);
> +       if (cil_list_is_empty(p4)) {
> +               cil_tree_log(allow_node, CIL_ERR, "Allow rule did not match deny rule: No matching class and permissions");
> +               cil_tree_log((struct cil_tree_node *)deny_node, CIL_ERR, "Deny rule");
> +               rc = SEPOL_ERR;
> +               goto exit;
> +       }
> +
> +       rc = cil_create_attribute_d1_and_not_d2(db, s1, s2, &s3);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +       curr = cil_create_and_add_avrule(curr, s3, t1, p4);
> +
> +       if ((t1 == DATUM(db->selftype) && t2 == DATUM(db->selftype)) ||
> +               (t1 == DATUM(db->notselftype) && t2 == DATUM(db->notselftype))) {
> +               /* Nothing more needs to be done */
> +               rc = SEPOL_OK;
> +               goto exit;
> +       }
> +
> +       rc = cil_create_attribute_d1_and_d2(db, s1, s2, &s4);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       if (t1 == DATUM(db->notselftype) || t1 == DATUM(db->othertype) ||
> +               t2 == DATUM(db->notselftype) || t2 == DATUM(db->othertype)) {
> +               rc = cil_remove_permissions_from_special_rule(db, curr, s1, t1, s2, t2, p4, s3, s4);
> +               goto exit;
> +       }
> +
> +       if (t1 == DATUM(db->selftype) && t2 != DATUM(db->selftype)) {
> +               struct cil_symtab_datum *s5;
> +               rc = cil_create_attribute_d1_and_not_d2(db, s4, t2, &s5);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               curr = cil_create_and_add_avrule(curr, s5, DATUM(db->selftype), p4);
> +       } else if (t1 != DATUM(db->selftype) && t2 == DATUM(db->selftype)) {
> +               struct cil_symtab_datum *s7, *s8, *t8;
> +               rc = cil_create_attribute_d1_and_not_d2(db, s4, t1, &s7);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               rc = cil_create_attribute_d1_and_d2(db, s4, t1, &s8);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               rc = cil_create_attribute_d1_and_not_d2(db, t1, s4, &t8);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               curr = cil_create_and_add_avrule(curr, s7, t1, p4);
> +               curr = cil_create_and_add_avrule(curr, s8, t8, p4);
> +               if (cil_datum_cardinality(s8) > 1) {
> +                       curr = cil_create_and_add_avrule(curr, s8, DATUM(db->othertype), p4);
> +               }
> +       } else {
> +               struct cil_symtab_datum *t3;
> +               rc = cil_create_attribute_d1_and_not_d2(db, t1, t2, &t3);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               curr = cil_create_and_add_avrule(curr, s4, t3, p4);
> +       }
> +
> +exit:
> +       if (p4) {
> +               cil_destroy_classperms_list(&p4);
> +       }
> +       return rc;
> +}
> +
> +static int cil_find_matching_allow_rules(struct cil_list *matching, struct cil_tree_node *start, struct cil_tree_node *deny_node)
> +{
> +       struct cil_deny_rule *deny_rule = deny_node->data;
> +       struct cil_avrule target;
> +
> +       target.rule_kind = CIL_AVRULE_ALLOWED;
> +       target.is_extended = CIL_FALSE;
> +       target.src = deny_rule->src;
> +       target.tgt = deny_rule->tgt;
> +       target.perms.classperms = deny_rule->classperms;
> +
> +       return cil_find_matching_avrule_in_ast(start, CIL_AVRULE, &target, matching, CIL_FALSE);
> +}
> +
> +static int cil_process_deny_rule(struct cil_db *db, struct cil_tree_node *start, struct cil_tree_node *deny_node)
> +{
> +       struct cil_list *matching;
> +       struct cil_list_item *item;
> +       int rc;
> +
> +       cil_list_init(&matching, CIL_NODE);
> +
> +       rc = cil_find_matching_allow_rules(matching, start, deny_node);
> +       if (rc != SEPOL_OK) {
> +               goto exit;
> +       }
> +
> +       cil_list_for_each(item, matching) {
> +               struct cil_tree_node *allow_node = item->data;
> +               rc = cil_remove_permissions_from_rule(db, allow_node, deny_node);
> +               cil_tree_node_remove(allow_node);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +
> +       }
> +
> +exit:
> +       cil_list_destroy(&matching, CIL_FALSE);
> +       return rc;
> +}
> +
> +static int cil_process_deny_rules(struct cil_db *db, struct cil_tree_node *start, struct cil_list *deny_rules)
> +{
> +       struct cil_list_item *item;
> +       int rc;

-    int rc;
+    int rc = SEPOL_OK;

Otherwise, if the list of deny rules is empty, rc is returned unitialized.
I am not sure how all my testing didn't find this, but the CI testing
did when I pushed the merge branch to my github.
Jim

> +
> +       cil_list_for_each(item, deny_rules) {
> +               struct cil_tree_node *deny_node = item->data;
> +               rc = cil_process_deny_rule(db, start, deny_node);
> +               if (rc != SEPOL_OK) {
> +                       goto exit;
> +               }
> +               cil_tree_node_remove(deny_node);
> +       }
> +
> +exit:
> +       return rc;
> +}
> +
> +static int __cil_find_deny_rules(struct cil_tree_node *node,  uint32_t *finished, void *extra_args)
> +{
> +       struct cil_list *deny_rules = extra_args;
> +
> +       if (node->flavor == CIL_BLOCK) {
> +               struct cil_block *block = node->data;
> +               if (block->is_abstract == CIL_TRUE) {
> +                       *finished = CIL_TREE_SKIP_HEAD;
> +               }
> +       } else if (node->flavor == CIL_MACRO) {
> +               *finished = CIL_TREE_SKIP_HEAD;
> +       } else if (node->flavor == CIL_DENY_RULE) {
> +               cil_list_append(deny_rules, CIL_DENY_RULE, node);
> +       }
> +       return SEPOL_OK;
> +}
> +
> +int cil_process_deny_rules_in_ast(struct cil_db *db)
> +{
> +       struct cil_tree_node *start;
> +       struct cil_list *deny_rules;
> +       int rc = SEPOL_ERR;
> +
> +       cil_list_init(&deny_rules, CIL_DENY_RULE);
> +
> +       if (!db) {
> +               cil_log(CIL_ERR, "No CIL db provided to process deny rules\n");
> +               goto exit;
> +       }
> +
> +       start = db->ast->root;
> +       rc = cil_tree_walk(start, __cil_find_deny_rules, NULL, NULL, deny_rules);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "An error occurred while getting deny rules\n");
> +               goto exit;
> +       }
> +
> +       rc = cil_process_deny_rules(db, start, deny_rules);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "An error occurred while processing deny rules\n");
> +               goto exit;
> +       }
> +
> +exit:
> +       cil_list_destroy(&deny_rules, CIL_FALSE);
> +       return rc;
> +}
> diff --git a/libsepol/cil/src/cil_deny.h b/libsepol/cil/src/cil_deny.h
> new file mode 100644
> index 00000000..f22e8bf1
> --- /dev/null
> +++ b/libsepol/cil/src/cil_deny.h
> @@ -0,0 +1,36 @@
> +/*
> + * This file is public domain software, i.e. not copyrighted.
> + *
> + * Warranty Exclusion
> + * ------------------
> + * You agree that this software is a non-commercially developed program
> + * that may contain "bugs" (as that term is used in the industry) and
> + * that it may not function as intended. The software is licensed
> + * "as is". NSA makes no, and hereby expressly disclaims all, warranties,
> + * express, implied, statutory, or otherwise with respect to the software,
> + * including noninfringement and the implied warranties of merchantability
> + * and fitness for a particular purpose.
> + *
> + * Limitation of Liability
> + *-----------------------
> + * In no event will NSA be liable for any damages, including loss of data,
> + * lost profits, cost of cover, or other special, incidental, consequential,
> + * direct or indirect damages arising from the software or the use thereof,
> + * however caused and on any theory of liability. This limitation will apply
> + * even if NSA has been advised of the possibility of such damage. You
> + * acknowledge that this is a reasonable allocation of risk.
> + *
> + * Original author: James Carter
> + */
> +
> +#ifndef CIL_DENY_H_
> +#define CIL_DENY_H_
> +
> +int cil_classperms_list_match_any(const struct cil_list *cpl1, const struct cil_list *cpl2);
> +int cil_classperms_list_match_all(const struct cil_list *cpl1, const struct cil_list *cpl2);
> +void cil_classperms_list_copy(struct cil_list **new, const struct cil_list *old);
> +void cil_classperms_list_and(struct cil_list **result, const struct cil_list *cpl1, const struct cil_list *cpl2);
> +void cil_classperms_list_andnot(struct cil_list **result, const struct cil_list *cpl1, const struct cil_list *cpl2);
> +int cil_process_deny_rules_in_ast(struct cil_db *db);
> +
> +#endif /* CIL_DENY_H_ */
> diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
> index a7c66ead..da97a392 100644
> --- a/libsepol/cil/src/cil_post.c
> +++ b/libsepol/cil/src/cil_post.c
> @@ -47,6 +47,7 @@
>  #include "cil_policy.h"
>  #include "cil_verify.h"
>  #include "cil_symtab.h"
> +#include "cil_deny.h"
>
>  #define GEN_REQUIRE_ATTR "cil_gen_require" /* Also in libsepol/src/module_to_cil.c */
>  #define TYPEATTR_INFIX "_typeattr_"        /* Also in libsepol/src/module_to_cil.c */
> @@ -2551,6 +2552,12 @@ int cil_post_process(struct cil_db *db)
>                 goto exit;
>         }
>
> +       rc = cil_process_deny_rules_in_ast(db);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Failed to process deny rules\n");
> +               goto exit;
> +       }
> +
>         rc = cil_post_verify(db);
>         if (rc != SEPOL_OK) {
>                 cil_log(CIL_ERR, "Failed to verify cil database\n");
> --
> 2.41.0
>




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux