#include "cil_internal.h"
#include "cil_log.h"
#include "cil_list.h"
#include "cil_symtab.h"
static inline void cil_reset_classperms_list(struct cil_list *cp_list);
static inline void cil_reset_level(struct cil_level *level);
static inline void cil_reset_levelrange(struct cil_levelrange *levelrange);
static inline void cil_reset_context(struct cil_context *context);
static int __class_reset_perm_values(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
{
struct cil_perm *perm = (struct cil_perm *)d;
perm->value -= *((int *)args);
return SEPOL_OK;
}
static void cil_reset_class(struct cil_class *class)
{
if (class->common != NULL) {
struct cil_class *common = class->common;
cil_symtab_map(&common->perms, __class_reset_perm_values, &common->num_perms);
/* during a re-resolve, we need to reset the common, so a classcommon
* statement isn't seen as a duplicate */
class->num_perms -= common->num_perms;
class->common = NULL; /* Must make this NULL or there will be an error when re-resolving */
}
class->ordered = CIL_FALSE;
}
static void cil_reset_perm(struct cil_perm *perm)
{
cil_reset_classperms_list(perm->classperms);
}
static inline void cil_reset_classperms(struct cil_classperms *cp)
{
if (cp == NULL) {
return;
}
cil_list_destroy(&cp->perms, CIL_FALSE);
}
static void cil_reset_classpermission(struct cil_classpermission *cp)
{
if (cp == NULL) {
return;
}
cil_reset_classperms_list(cp->classperms);
}
static void cil_reset_classperms_set(struct cil_classperms_set *cp_set)
{
cil_reset_classpermission(cp_set->set);
}
static inline void cil_reset_classperms_list(struct cil_list *cp_list)
{
struct cil_list_item *curr;
if (cp_list == NULL) {
return;
}
cil_list_for_each(curr, cp_list) {
if (curr->flavor == CIL_CLASSPERMS) { /* KERNEL or MAP */
cil_reset_classperms(curr->data);
} else if (curr->flavor == CIL_CLASSPERMS_SET) { /* SET */
cil_reset_classperms_set(curr->data);
}
}
}
static void cil_reset_classpermissionset(struct cil_classpermissionset *cps)
{
cil_reset_classperms_list(cps->classperms);
}
static void cil_reset_classmapping(struct cil_classmapping *cm)
{
cil_reset_classperms_list(cm->classperms);
}
static void cil_reset_alias(struct cil_alias *alias)
{
/* reset actual to NULL during a re-resolve */
alias->actual = NULL;
}
static void cil_reset_user(struct cil_user *user)
{
/* reset the bounds to NULL during a re-resolve */
user->bounds = NULL;
user->dftlevel = NULL;
user->range = NULL;
cil_list_destroy(&user->roles, CIL_FALSE);
}
static void cil_reset_selinuxuser(struct cil_selinuxuser *selinuxuser)
{
if (selinuxuser->range_str == NULL) {
cil_reset_levelrange(selinuxuser->range);
}
}
static void cil_reset_role(struct cil_role *role)
{
/* reset the bounds to NULL during a re-resolve */
role->bounds = NULL;
}
static void cil_reset_roleattr(struct cil_roleattribute *attr)
{
/* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a attributeroles statement */
if (attr->expr_list != NULL) {
/* we don't want to destroy the expression stacks (cil_list) inside
* this list cil_list_destroy destroys sublists, so we need to do it
* manually */
struct cil_list_item *expr = attr->expr_list->head;
while (expr != NULL) {
struct cil_list_item *next = expr->next;
cil_list_item_destroy(&expr, CIL_FALSE);
expr = next;
}
free(attr->expr_list);
attr->expr_list = NULL;
}
}
static void cil_reset_roleattributeset(struct cil_roleattributeset *ras)
{
cil_list_destroy(&ras->datum_expr, CIL_FALSE);
}
static void cil_reset_type(struct cil_type *type)
{
/* reset the bounds to NULL during a re-resolve */
type->bounds = NULL;
}
static void cil_reset_typeattr(struct cil_typeattribute *attr)
{
/* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a attributetypes statement */
if (attr->expr_list != NULL) {
/* we don't want to destroy the expression stacks (cil_list) inside
* this list cil_list_destroy destroys sublists, so we need to do it
* manually */
struct cil_list_item *expr = attr->expr_list->head;
while (expr != NULL) {
struct cil_list_item *next = expr->next;
cil_list_item_destroy(&expr, CIL_FALSE);
expr = next;
}
free(attr->expr_list);
attr->expr_list = NULL;
}
attr->used = CIL_FALSE;
}
static void cil_reset_typeattributeset(struct cil_typeattributeset *tas)
{
cil_list_destroy(&tas->datum_expr, CIL_FALSE);
}
static void cil_reset_avrule(struct cil_avrule *rule)
{
cil_reset_classperms_list(rule->classperms);
}
static void cil_reset_rangetransition(struct cil_rangetransition *rangetrans)
{
if (rangetrans->range_str == NULL) {
cil_reset_levelrange(rangetrans->range);
}
}
static void cil_reset_sens(struct cil_sens *sens)
{
/* during a re-resolve, we need to reset the categories associated with
* this sensitivity from a (sensitivitycategory) statement */
cil_list_destroy(&sens->cats_list, CIL_FALSE);
sens->ordered = CIL_FALSE;
}
static void cil_reset_cat(struct cil_cat *cat)
{
cat->ordered = CIL_FALSE;
}
static inline void cil_reset_cats(struct cil_cats *cats)
{
if (cats != NULL) {
cats->evaluated = CIL_FALSE;
cil_list_destroy(&cats->datum_expr, CIL_FALSE);
}
}
static void cil_reset_senscat(struct cil_senscat *senscat)
{
cil_reset_cats(senscat->cats);
}
static void cil_reset_catset(struct cil_catset *catset)
{
cil_reset_cats(catset->cats);
}
static inline void cil_reset_level(struct cil_level *level)
{
cil_reset_cats(level->cats);
}
static inline void cil_reset_levelrange(struct cil_levelrange *levelrange)
{
if (levelrange->low_str == NULL) {
cil_reset_level(levelrange->low);
}
if (levelrange->high_str == NULL) {
cil_reset_level(levelrange->high);
}
}
static inline void cil_reset_userlevel(struct cil_userlevel *userlevel)
{
if (userlevel->level_str == NULL) {
cil_reset_level(userlevel->level);
}
}
static inline void cil_reset_userrange(struct cil_userrange *userrange)
{
if (userrange->range_str == NULL) {
cil_reset_levelrange(userrange->range);
}
}
static inline void cil_reset_context(struct cil_context *context)
{
if (context->range_str == NULL) {
cil_reset_levelrange(context->range);
}
}
static void cil_reset_sidcontext(struct cil_sidcontext *sidcontext)
{
if (sidcontext->context_str == NULL) {
cil_reset_context(sidcontext->context);
}
}
static void cil_reset_filecon(struct cil_filecon *filecon)
{
if (filecon->context_str == NULL && filecon->context != NULL) {
cil_reset_context(filecon->context);
}
}
static void cil_reset_portcon(struct cil_portcon *portcon)
{
if (portcon->context_str == NULL) {
cil_reset_context(portcon->context);
}
}
static void cil_reset_nodecon(struct cil_nodecon *nodecon)
{
if (nodecon->context_str == NULL) {
cil_reset_context(nodecon->context);
}
}
static void cil_reset_genfscon(struct cil_genfscon *genfscon)
{
if (genfscon->context_str == NULL) {
cil_reset_context(genfscon->context);
}
}
static void cil_reset_netifcon(struct cil_netifcon *netifcon)
{
if (netifcon->if_context_str == NULL) {
cil_reset_context(netifcon->if_context);
}
if (netifcon->packet_context_str == NULL) {
cil_reset_context(netifcon->packet_context);
}
}
static void cil_reset_pirqcon(struct cil_pirqcon *pirqcon)
{
if (pirqcon->context_str == NULL) {
cil_reset_context(pirqcon->context);
}
}
static void cil_reset_iomemcon(struct cil_iomemcon *iomemcon)
{
if (iomemcon->context_str == NULL) {
cil_reset_context(iomemcon->context);
}
}
static void cil_reset_ioportcon(struct cil_ioportcon *ioportcon)
{
if (ioportcon->context_str == NULL) {
cil_reset_context(ioportcon->context);
}
}
static void cil_reset_pcidevicecon(struct cil_pcidevicecon *pcidevicecon)
{
if (pcidevicecon->context_str == NULL) {
cil_reset_context(pcidevicecon->context);
}
}
static void cil_reset_devicetreecon(struct cil_devicetreecon *devicetreecon)
{
if (devicetreecon->context_str == NULL) {
cil_reset_context(devicetreecon->context);
}
}
static void cil_reset_fsuse(struct cil_fsuse *fsuse)
{
if (fsuse->context_str == NULL) {
cil_reset_context(fsuse->context);
}
}
static void cil_reset_sid(struct cil_sid *sid)
{
/* reset the context to NULL during a re-resolve */
sid->context = NULL;
sid->ordered = CIL_FALSE;
}
static void cil_reset_constrain(struct cil_constrain *con)
{
cil_reset_classperms_list(con->classperms);
cil_list_destroy(&con->datum_expr, CIL_FALSE);
}
static void cil_reset_validatetrans(struct cil_validatetrans *vt)
{
cil_list_destroy(&vt->datum_expr, CIL_FALSE);
}
static void cil_reset_default(struct cil_default *def)
{
cil_list_destroy(&def->class_datums, CIL_FALSE);
}
static void cil_reset_defaultrange(struct cil_defaultrange *def)
{
cil_list_destroy(&def->class_datums, CIL_FALSE);
}
static void cil_reset_booleanif(struct cil_booleanif *bif)
{
cil_list_destroy(&bif->datum_expr, CIL_FALSE);
}
int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, __attribute__((unused)) void *extra_args)
{
switch (node->flavor) {
case CIL_CLASS:
cil_reset_class(node->data);
break;
case CIL_PERM:
case CIL_MAP_PERM:
cil_reset_perm(node->data);
break;
case CIL_CLASSPERMISSION:
cil_reset_classpermission(node->data);
break;
case CIL_CLASSPERMISSIONSET:
cil_reset_classpermissionset(node->data);
break;
case CIL_CLASSMAPPING:
cil_reset_classmapping(node->data);
break;
case CIL_TYPEALIAS:
case CIL_SENSALIAS:
case CIL_CATALIAS:
cil_reset_alias(node->data);
break;
case CIL_USERRANGE:
cil_reset_userrange(node->data);
break;
case CIL_USERLEVEL:
cil_reset_userlevel(node->data);
break;
case CIL_USER:
cil_reset_user(node->data);
break;
case CIL_SELINUXUSERDEFAULT:
case CIL_SELINUXUSER:
cil_reset_selinuxuser(node->data);
break;
case CIL_ROLE:
cil_reset_role(node->data);
break;
case CIL_ROLEATTRIBUTE:
cil_reset_roleattr(node->data);
break;
case CIL_ROLEATTRIBUTESET:
cil_reset_roleattributeset(node->data);
break;
case CIL_TYPE:
cil_reset_type(node->data);
break;
case CIL_TYPEATTRIBUTE:
cil_reset_typeattr(node->data);
break;
case CIL_TYPEATTRIBUTESET:
cil_reset_typeattributeset(node->data);
break;
case CIL_RANGETRANSITION:
cil_reset_rangetransition(node->data);
break;
case CIL_AVRULE:
cil_reset_avrule(node->data);
break;
case CIL_SENS:
cil_reset_sens(node->data);
break;
case CIL_CAT:
cil_reset_cat(node->data);
break;
case CIL_SENSCAT:
cil_reset_senscat(node->data);
break;
case CIL_CATSET:
cil_reset_catset(node->data);
break;
case CIL_LEVEL:
cil_reset_level(node->data);
break;
case CIL_LEVELRANGE:
cil_reset_levelrange(node->data);
break;
case CIL_CONTEXT:
cil_reset_context(node->data);
break;
case CIL_SIDCONTEXT:
cil_reset_sidcontext(node->data);
break;
case CIL_FILECON:
cil_reset_filecon(node->data);
break;
case CIL_PORTCON:
cil_reset_portcon(node->data);
break;
case CIL_NODECON:
cil_reset_nodecon(node->data);
break;
case CIL_GENFSCON:
cil_reset_genfscon(node->data);
break;
case CIL_NETIFCON:
cil_reset_netifcon(node->data);
break;
case CIL_PIRQCON:
cil_reset_pirqcon(node->data);
break;
case CIL_IOMEMCON:
cil_reset_iomemcon(node->data);
break;
case CIL_IOPORTCON:
cil_reset_ioportcon(node->data);
break;
case CIL_PCIDEVICECON:
cil_reset_pcidevicecon(node->data);
break;
case CIL_DEVICETREECON:
cil_reset_devicetreecon(node->data);
break;
case CIL_FSUSE:
cil_reset_fsuse(node->data);
break;
case CIL_SID:
cil_reset_sid(node->data);
break;
case CIL_CONSTRAIN:
case CIL_MLSCONSTRAIN:
cil_reset_constrain(node->data);
break;
case CIL_VALIDATETRANS:
case CIL_MLSVALIDATETRANS:
cil_reset_validatetrans(node->data);
break;
case CIL_DEFAULTUSER:
case CIL_DEFAULTROLE:
case CIL_DEFAULTTYPE:
cil_reset_default(node->data);
break;
case CIL_DEFAULTRANGE:
cil_reset_defaultrange(node->data);
break;
case CIL_BOOLEANIF:
cil_reset_booleanif(node->data);
break;
case CIL_TUNABLEIF:
case CIL_CALL:
break; /* Not effected by optional block disabling */
case CIL_MACRO:
case CIL_SIDORDER:
case CIL_CLASSORDER:
case CIL_CATORDER:
case CIL_SENSITIVITYORDER:
break; /* Nothing to reset */
default:
break;
}
return SEPOL_OK;
}
int cil_reset_ast(struct cil_tree_node *current)
{
int rc = SEPOL_ERR;
rc = cil_tree_walk(current, __cil_reset_node, NULL, NULL, NULL);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Failed to reset AST\n");
return SEPOL_ERR;
}
return SEPOL_OK;
}