* [PATCH 1/3 v3] libsepol, policycoreutils: Move functions to convert a module package to CIL
2015-03-31 17:17 [PATCH 0/3 v3] libsepol, policycoreutils, and checkpolicy: Add support for generating CIL to libsepol and checkpolicy James Carter
@ 2015-03-31 17:17 ` James Carter
2015-03-31 17:18 ` [PATCH 2/3 v3] libsepol: add function to generate CIL from a module policydb James Carter
` (2 subsequent siblings)
3 siblings, 0 replies; 11+ messages in thread
From: James Carter @ 2015-03-31 17:17 UTC (permalink / raw)
To: selinux
Move code to convert a policy module to CIL from the policy package to
CIL conversion tool, pp, in policycoreutils to libsepol. The only changes
to the code are the additions of the prefix "sepol_" to the functions
sepol_module_package_to_cil() and sepol_ppfile_to_module_package(). This
code is being changed from GPL to LGPL with permission from Tresys.
Convert pp to use the renamed functions in libsepol.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
---
libsepol/include/sepol/module_to_cil.h | 6 +
libsepol/src/module_to_cil.c | 3873 ++++++++++++++++++++++++++++++++
policycoreutils/hll/pp/pp.c | 3830 +------------------------------
3 files changed, 3882 insertions(+), 3827 deletions(-)
create mode 100644 libsepol/include/sepol/module_to_cil.h
create mode 100644 libsepol/src/module_to_cil.c
diff --git a/libsepol/include/sepol/module_to_cil.h b/libsepol/include/sepol/module_to_cil.h
new file mode 100644
index 0000000..1d0225c
--- /dev/null
+++ b/libsepol/include/sepol/module_to_cil.h
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+#include <sepol/module.h>
+
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg);
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg);
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
new file mode 100644
index 0000000..8326826
--- /dev/null
+++ b/libsepol/src/module_to_cil.c
@@ -0,0 +1,3873 @@
+/* Authors: Steve Lawrence <slawrence@tresys.com>
+ *
+ * Functions to convert policy module to CIL
+ *
+ * Copyright (C) 2015 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sepol/module.h>
+#include <sepol/module_to_cil.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/util.h>
+
+#ifdef __GNUC__
+# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+# define UNUSED(x) UNUSED_ ## x
+#endif
+
+FILE *out_file;
+
+#define STACK_SIZE 16
+#define DEFAULT_LEVEL "systemlow"
+#define DEFAULT_OBJECT "object_r"
+#define GEN_REQUIRE_ATTR "cil_gen_require"
+
+__attribute__ ((format(printf, 1, 2)))
+static void log_err(const char *fmt, ...)
+{
+ va_list argptr;
+ va_start(argptr, fmt);
+ if (vfprintf(stderr, fmt, argptr) < 0) {
+ _exit(EXIT_FAILURE);
+ }
+ va_end(argptr);
+ if (fprintf(stderr, "\n") < 0) {
+ _exit(EXIT_FAILURE);
+ }
+}
+
+static void cil_indent(int indent)
+{
+ if (fprintf(out_file, "%*s", indent * 4, "") < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+}
+
+__attribute__ ((format(printf, 1, 2)))
+static void cil_printf(const char *fmt, ...) {
+ va_list argptr;
+ va_start(argptr, fmt);
+ if (vfprintf(out_file, fmt, argptr) < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+ va_end(argptr);
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static void cil_println(int indent, const char *fmt, ...)
+{
+ cil_indent(indent);
+ va_list argptr;
+ va_start(argptr, fmt);
+ if (vfprintf(out_file, fmt, argptr) < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+ va_end(argptr);
+ if (fprintf(out_file, "\n") < 0) {
+ log_err("Failed to write to output");
+ _exit(EXIT_FAILURE);
+ }
+}
+
+struct map_args {
+ struct policydb *pdb;
+ struct avrule_block *block;
+ struct stack *decl_stack;
+ int scope;
+ int indent;
+ int sym_index;
+};
+
+struct stack {
+ void **stack;
+ int pos;
+ int size;
+};
+
+struct role_list_node {
+ char *role_name;
+ role_datum_t *role;
+};
+
+struct attr_list_node {
+ char *attribute;
+ int is_type;
+ union {
+ struct type_set *ts;
+ struct role_set *rs;
+ } set;
+};
+
+struct list_node {
+ void *data;
+ struct list_node *next;
+};
+
+struct list {
+ struct list_node *head;
+};
+
+/* A linked list of all roles stored in the pdb
+ * which is iterated to determine types associated
+ * with each role when printing role_type statements
+ */
+static struct list *role_list;
+
+static void list_destroy(struct list **list)
+{
+ struct list_node *curr = (*list)->head;
+ struct list_node *tmp;
+
+ while (curr != NULL) {
+ tmp = curr->next;
+ free(curr);
+ curr = tmp;
+ }
+
+ free(*list);
+ *list = NULL;
+}
+
+static void role_list_destroy(void)
+{
+ struct list_node *curr = role_list->head;
+
+ while (curr != NULL) {
+ free(curr->data);
+ curr->data = NULL;
+ curr = curr->next;
+ }
+
+ list_destroy(&role_list);
+}
+
+static void attr_list_destroy(struct list **attr_list)
+{
+ if (attr_list == NULL || *attr_list == NULL) {
+ return;
+ }
+
+ struct list_node *curr = (*attr_list)->head;
+ struct attr_list_node *attr;
+
+ while (curr != NULL) {
+ attr = curr->data;
+ if (attr != NULL) {
+ free(attr->attribute);
+ }
+
+ free(curr->data);
+ curr->data = NULL;
+ curr = curr->next;
+ }
+
+ list_destroy(attr_list);
+}
+
+static int list_init(struct list **list)
+{
+ int rc = -1;
+ struct list *l = calloc(1, sizeof(*l));
+ if (l == NULL) {
+ goto exit;
+ }
+
+ *list = l;
+
+ return 0;
+
+exit:
+ list_destroy(&l);
+ return rc;
+}
+
+static int list_prepend(struct list *list, void *data)
+{
+ int rc = -1;
+ struct list_node *node = calloc(1, sizeof(*node));
+ if (node == NULL) {
+ goto exit;
+ }
+
+ node->data = data;
+ node->next = list->head;
+ list->head = node;
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int roles_gather_map(char *key, void *data, void *args)
+{
+ struct role_list_node *role_node;
+ role_datum_t *role = data;
+ int rc = -1;
+
+ role_node = calloc(1, sizeof(*role_node));
+ if (role_node == NULL) {
+ return rc;
+ }
+
+ role_node->role_name = key;
+ role_node->role = role;
+
+ rc = list_prepend((struct list *)args, role_node);
+ return rc;
+}
+
+static int role_list_create(hashtab_t roles_tab)
+{
+ int rc = -1;
+
+ rc = list_init(&role_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = hashtab_map(roles_tab, roles_gather_map, role_list);
+
+exit:
+ return rc;
+}
+
+// array of lists, where each list contains all the aliases defined in the scope at index i
+static struct list **typealias_lists;
+static uint32_t typealias_lists_len;
+
+static int typealiases_gather_map(char *key, void *data, void *arg)
+{
+ int rc = -1;
+ struct type_datum *type = data;
+ struct policydb *pdb = arg;
+ struct scope_datum *scope;
+ uint32_t i;
+ uint32_t scope_id;
+
+ if (type->primary != 1) {
+ scope = hashtab_search(pdb->scope[SYM_TYPES].table, key);
+ if (scope == NULL) {
+ return -1;
+ }
+
+ for (i = 0; i < scope->decl_ids_len; i++) {
+ scope_id = scope->decl_ids[i];
+ if (typealias_lists[scope_id] == NULL) {
+ rc = list_init(&typealias_lists[scope_id]);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ list_prepend(typealias_lists[scope_id], key);
+ }
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static void typealias_list_destroy(void)
+{
+ uint32_t i;
+ for (i = 0; i < typealias_lists_len; i++) {
+ if (typealias_lists[i] != NULL) {
+ list_destroy(&typealias_lists[i]);
+ }
+ }
+ typealias_lists_len = 0;
+ free(typealias_lists);
+ typealias_lists = NULL;
+}
+
+static int typealias_list_create(struct policydb *pdb)
+{
+ uint32_t max_decl_id = 0;
+ struct avrule_decl *decl;
+ struct avrule_block *block;
+ uint32_t rc = -1;
+
+ for (block = pdb->global; block != NULL; block = block->next) {
+ decl = block->branch_list;
+ if (decl->decl_id > max_decl_id) {
+ max_decl_id = decl->decl_id;
+ }
+ }
+
+ typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists));
+ typealias_lists_len = max_decl_id + 1;
+
+ rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ typealias_list_destroy();
+
+ return rc;
+}
+
+
+static int stack_destroy(struct stack **stack)
+{
+ if (stack == NULL || *stack == NULL) {
+ return 0;
+ }
+
+ free((*stack)->stack);
+ free(*stack);
+ *stack = NULL;
+
+ return 0;
+}
+
+static int stack_init(struct stack **stack)
+{
+ int rc = -1;
+ struct stack *s = calloc(1, sizeof(*s));
+ if (s == NULL) {
+ goto exit;
+ }
+
+ s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
+ if (s->stack == NULL) {
+ goto exit;
+ }
+
+ s->pos = -1;
+ s->size = STACK_SIZE;
+
+ *stack = s;
+
+ return 0;
+
+exit:
+ stack_destroy(&s);
+ return rc;
+}
+
+static int stack_push(struct stack *stack, void *ptr)
+{
+ int rc = -1;
+ void *new_stack;
+
+ if (stack->pos + 1 == stack->size) {
+ new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
+ if (new_stack == NULL) {
+ goto exit;
+ }
+ stack->stack = new_stack;
+ stack->size *= 2;
+ }
+
+ stack->pos++;
+ stack->stack[stack->pos] = ptr;
+
+ rc = 0;
+exit:
+ return rc;
+}
+
+static void *stack_pop(struct stack *stack)
+{
+ if (stack->pos == -1) {
+ return NULL;
+ }
+
+ stack->pos--;
+ return stack->stack[stack->pos + 1];
+}
+
+static void *stack_peek(struct stack *stack)
+{
+ if (stack->pos == -1) {
+ return NULL;
+ }
+
+ return stack->stack[stack->pos];
+}
+
+static int is_id_in_scope_with_start(struct policydb *pdb, struct stack *decl_stack, int start, uint32_t symbol_type, char *id)
+{
+ int i;
+ uint32_t j;
+ struct avrule_decl *decl;
+ struct scope_datum *scope;
+
+ scope = hashtab_search(pdb->scope[symbol_type].table, id);
+ if (scope == NULL) {
+ return 0;
+ }
+
+ for (i = start; i >= 0; i--) {
+ decl = decl_stack->stack[i];
+
+ for (j = 0; j < scope->decl_ids_len; j++) {
+ if (scope->decl_ids[j] == decl->decl_id) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int is_id_in_ancestor_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+ int start = decl_stack->pos - 1;
+
+ return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int is_id_in_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+ int start = decl_stack->pos;
+
+ return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct mls_semantic_level *level)
+{
+ struct mls_semantic_cat *cat;
+
+ cil_printf("(%s ", pdb->p_sens_val_to_name[level->sens - sens_offset]);
+
+ if (level->cat != NULL) {
+ cil_printf("(");
+ }
+
+ for (cat = level->cat; cat != NULL; cat = cat->next) {
+ if (cat->low == cat->high) {
+ cil_printf("%s", pdb->p_cat_val_to_name[cat->low - 1]);
+ } else {
+ cil_printf("range %s %s", pdb->p_cat_val_to_name[cat->low - 1], pdb->p_cat_val_to_name[cat->high - 1]);
+ }
+
+ if (cat->next != NULL) {
+ cil_printf(" ");
+ }
+ }
+
+ if (level->cat != NULL) {
+ cil_printf(")");
+ }
+
+ cil_printf(")");
+
+ return 0;
+}
+
+static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms)
+{
+ int rc = -1;
+ const char *rule;
+ const struct class_perm_node *classperm;
+ char *perms;
+
+ switch (type) {
+ case AVRULE_ALLOWED:
+ rule = "allow";
+ break;
+ case AVRULE_AUDITALLOW:
+ rule = "auditallow";
+ break;
+ case AVRULE_AUDITDENY:
+ rule = "auditdenty";
+ break;
+ case AVRULE_DONTAUDIT:
+ rule = "dontaudit";
+ break;
+ case AVRULE_NEVERALLOW:
+ rule = "neverallow";
+ break;
+ case AVRULE_TRANSITION:
+ rule = "typetransition";
+ break;
+ case AVRULE_MEMBER:
+ rule = "typemember";
+ break;
+ case AVRULE_CHANGE:
+ rule = "typechange";
+ break;
+ default:
+ log_err("Unknown avrule type: %i", type);
+ rc = -1;
+ goto exit;
+ }
+
+ for (classperm = classperms; classperm != NULL; classperm = classperm->next) {
+ if (type & AVRULE_AV) {
+ perms = sepol_av_to_string(pdb, classperm->tclass, classperm->data);
+ if (perms == NULL) {
+ log_err("Failed to generate permission string");
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(%s %s %s (%s (%s)))",
+ rule, src, tgt,
+ pdb->p_class_val_to_name[classperm->tclass - 1],
+ perms + 1);
+ } else {
+ cil_println(indent, "(%s %s %s %s %s)",
+ rule, src, tgt,
+ pdb->p_class_val_to_name[classperm->tclass - 1],
+ pdb->p_type_val_to_name[classperm->data - 1]);
+ }
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int num_digits(int n)
+{
+ int num = 1;
+ while (n >= 10) {
+ n /= 10;
+ num++;
+ }
+ return num;
+}
+
+static int set_to_cil_attr(struct policydb *pdb, int is_type, char ***names, uint32_t *num_names)
+{
+ static unsigned int num_attrs = 0;
+ int rc = -1;
+ int len, rlen;
+ const char *attr_infix;
+ char *attr;
+
+ num_attrs++;
+
+ if (is_type) {
+ attr_infix = "_typeattr_";
+ } else {
+ attr_infix = "_roleattr_";
+ }
+
+ len = strlen(pdb->name) + strlen(attr_infix) + num_digits(num_attrs) + 1;
+ attr = malloc(len);
+ if (attr == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(attr, len, "%s%s%i", pdb->name, attr_infix, num_attrs);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate attribute name");
+ rc = -1;
+ goto exit;
+ }
+
+ *names = malloc(sizeof(**names));
+ if (*names == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+
+ *names[0] = attr;
+ *num_names = 1;
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int cil_print_attr_strs(int indent, struct policydb *pdb, int is_type, struct ebitmap *pos, struct ebitmap *neg, uint32_t flags, char *attr)
+{
+ // CIL doesn't support anonymous positive/negative/complemented sets. So
+ // instead we create a CIL type/roleattributeset that matches the set. If
+ // the set has a negative set, then convert it to is (P & !N), where P is
+ // the list of members in the positive set , and N is the list of members
+ // in the negative set. Additonally, if the set is complemented, then wrap
+ // the whole thing with a negation.
+
+ int rc = 0;
+ struct ebitmap_node *node;
+ unsigned int i;
+ char *statement;
+ int has_positive = pos && (ebitmap_cardinality(pos) > 0);
+ int has_negative = neg && (ebitmap_cardinality(neg) > 0);
+ char **val_to_name;
+
+ if (is_type) {
+ statement = "type";
+ val_to_name = pdb->p_type_val_to_name;
+ } else {
+ statement = "role";
+ val_to_name = pdb->p_role_val_to_name;
+ }
+
+ cil_println(indent, "(%sattribute %s)", statement, attr);
+ cil_indent(indent);
+ cil_printf("(%sattributeset %s ", statement, attr);
+
+ if (flags & TYPE_STAR) {
+ cil_printf("(all)");
+ }
+
+ if (flags & TYPE_COMP) {
+ cil_printf("(not ");
+ }
+
+ if (has_positive && has_negative) {
+ cil_printf("(and ");
+ }
+
+ if (has_positive) {
+ cil_printf("(");
+ ebitmap_for_each_bit(pos, node, i) {
+ if (!ebitmap_get_bit(pos, i)) {
+ continue;
+ }
+ cil_printf("%s ", val_to_name[i]);
+ }
+ cil_printf(") ");
+ }
+
+ if (has_negative) {
+ cil_printf("(not (");
+
+ ebitmap_for_each_bit(neg, node, i) {
+ if (!ebitmap_get_bit(neg, i)) {
+ continue;
+ }
+ cil_printf("%s ", val_to_name[i]);
+ }
+
+ cil_printf("))");
+ }
+
+ if (has_positive && has_negative) {
+ cil_printf(")");
+ }
+
+ if (flags & TYPE_COMP) {
+ cil_printf(")");
+ }
+
+ cil_printf(")\n");
+
+ return rc;
+}
+
+static int ebitmap_to_cil(struct policydb *pdb, struct ebitmap *map, int type)
+{
+ struct ebitmap_node *node;
+ uint32_t i;
+ char **val_to_name = pdb->sym_val_to_name[type];
+
+ ebitmap_for_each_bit(map, node, i) {
+ if (!ebitmap_get_bit(map, i)) {
+ continue;
+ }
+ cil_printf("%s ", val_to_name[i]);
+ }
+
+ return 0;
+}
+
+static int ebitmap_to_names(char** vals_to_names, struct ebitmap map, char ***names, uint32_t *num_names)
+{
+ int rc = -1;
+ struct ebitmap_node *node;
+ uint32_t i;
+ uint32_t num = 0;
+ uint32_t max = 8;
+ char **name_arr = NULL;
+
+ name_arr = malloc(sizeof(*name_arr) * max);
+ if (name_arr == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ ebitmap_for_each_bit(&map, node, i) {
+ if (!ebitmap_get_bit(&map, i)) {
+ continue;
+ }
+
+ if (num + 1 == max) {
+ max *= 2;
+ name_arr = realloc(name_arr, sizeof(*name_arr) * max);
+ if (name_arr == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ }
+
+ name_arr[num] = strdup(vals_to_names[i]);
+ if (name_arr[num] == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ num++;
+ }
+
+ *names = name_arr;
+ *num_names = num;
+
+ return 0;
+
+exit:
+ for (i = 0; i < num; i++) {
+ free(name_arr[i]);
+ }
+ free(name_arr);
+ return rc;
+}
+
+static int cil_add_attr_to_list(struct list *attr_list, char *attribute, int is_type, void *set)
+{
+ struct attr_list_node *attr_list_node = NULL;
+ int rc = -1;
+
+ attr_list_node = calloc(1, sizeof(*attr_list_node));
+ if (attr_list_node == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = list_prepend(attr_list, attr_list_node);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ attr_list_node->attribute = strdup(attribute);
+ if (attr_list_node->attribute == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ attr_list_node->is_type = is_type;
+ if (is_type) {
+ attr_list_node->set.ts = set;
+ } else {
+ attr_list_node->set.rs = set;
+ }
+
+ return rc;
+
+exit:
+ if (attr_list_node != NULL) {
+ free(attr_list_node->attribute);
+ }
+ free(attr_list_node);
+ return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int typeset_to_names(struct policydb *pdb, struct type_set *ts, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+ int rc = -1;
+ if (ebitmap_cardinality(&ts->negset) > 0 || ts->flags != 0) {
+ rc = set_to_cil_attr(pdb, 1, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ *generated_attribute = *names[0];
+ } else {
+ rc = ebitmap_to_names(pdb->p_type_val_to_name, ts->types, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int roleset_to_names(struct policydb *pdb, struct role_set *rs, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+ int rc = -1;
+ if (rs->flags != 0) {
+ rc = set_to_cil_attr(pdb, 0, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ *generated_attribute = *names[0];
+ } else {
+ rc = ebitmap_to_names(pdb->p_role_val_to_name, rs->roles, names, num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int process_roleset(int indent, struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+ int rc = -1;
+ char *generated_attribute = NULL;
+ *num_type_names = 0;
+
+ rc = roleset_to_names(pdb, rs, type_names, num_type_names, &generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (generated_attribute == NULL) {
+ goto exit;
+ }
+
+ if (attr_list == NULL) {
+ rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else {
+ rc = cil_add_attr_to_list(attr_list, generated_attribute, 0, rs);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static int process_typeset(int indent, struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+ int rc = -1;
+ char *generated_attribute = NULL;
+ *num_type_names = 0;
+
+ rc = typeset_to_names(pdb, ts, type_names, num_type_names, &generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (generated_attribute == NULL) {
+ rc = 0;
+ goto exit;
+ }
+
+ if (attr_list == NULL) {
+ rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else {
+ rc = cil_add_attr_to_list(attr_list, generated_attribute, 1, ts);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
+
+static void names_destroy(char ***names, uint32_t *num_names)
+{
+ char **arr = *names;
+ uint32_t num = *num_names;
+ uint32_t i;
+
+ for (i = 0; i < num; i++) {
+ free(arr[i]);
+ arr[i] = NULL;
+ }
+ free(arr);
+
+ *names = NULL;
+ *num_names = 0;
+}
+
+static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *decl_stack, char *type_name, int indent)
+{
+ struct list_node *curr;
+ char **tnames = NULL;
+ uint32_t num_tnames, i;
+ struct role_list_node *role_node = NULL;
+ int rc;
+ struct type_set *ts;
+
+ curr = role_list->head;
+ for (curr = role_list->head; curr != NULL; curr = curr->next) {
+ role_node = curr->data;
+ if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
+ continue;
+ }
+
+ ts = &role_node->role->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &tnames, &num_tnames);
+ if (rc != 0) {
+ goto exit;
+ }
+ for (i = 0; i < num_tnames; i++) {
+ if (!strcmp(type_name, tnames[i])) {
+ cil_println(indent, "(roletype %s %s)", role_node->role_name, type_name);
+ }
+ }
+ names_destroy(&tnames, &num_tnames);
+ }
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+
+static int name_list_to_string(char **names, int num_names, char **string)
+{
+ // create a space separated string of the names
+ int rc = -1;
+ int len = 0;
+ int i;
+ char *str;
+ char *strpos;
+ int name_len;
+ int rlen;
+
+ for (i = 0; i < num_names; i++) {
+ len += strlen(names[i]);
+ }
+
+ // add spaces + null terminator
+ len += (num_names - 1) + 1;
+
+ str = malloc(len);
+ if (str == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ strpos = str;
+
+ for (i = 0; i < num_names; i++) {
+ name_len = strlen(names[i]);
+ rlen = snprintf(strpos, len - (strpos - str), "%s", names[i]);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate name list");
+ rc = -1;
+ goto exit;
+ }
+
+ if (i < num_names - 1) {
+ strpos[name_len] = ' ';
+ }
+ strpos += name_len + 1;
+ }
+
+ *string = str;
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *avrule_list, struct list *attr_list)
+{
+ int rc = -1;
+ struct avrule *avrule;
+ char **snames = NULL;
+ char **tnames = NULL;
+ uint32_t num_snames;
+ uint32_t num_tnames;
+ uint32_t s;
+ uint32_t t;
+ struct type_set *ts;
+
+ for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) {
+ ts = &avrule->stypes;
+ rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &avrule->ttypes;
+ rc = process_typeset(indent, pdb, ts, attr_list, &tnames, &num_tnames);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (s = 0; s < num_snames; s++) {
+ for (t = 0; t < num_tnames; t++) {
+ rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (avrule->flags & RULE_SELF) {
+ rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ names_destroy(&snames, &num_snames);
+ names_destroy(&tnames, &num_tnames);
+ }
+
+ return 0;
+
+exit:
+ names_destroy(&snames, &num_snames);
+ names_destroy(&tnames, &num_tnames);
+
+ return rc;
+}
+
+static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *cond_expr, uint32_t flags)
+{
+ int rc = -1;
+ struct cond_expr *curr;
+ struct stack *stack = NULL;
+ int len = 0;
+ int rlen;
+ char *new_val = NULL;
+ char *val1 = NULL;
+ char *val2 = NULL;
+ int num_params;
+ const char *op;
+ const char *fmt_str;
+ const char *type;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ log_err("Out of memory");
+ goto exit;
+ }
+
+ for (curr = cond_expr; curr != NULL; curr = curr->next) {
+ if (curr->expr_type == COND_BOOL) {
+ val1 = pdb->p_bool_val_to_name[curr->bool - 1];
+ // length of boolean + 2 parens + null terminator
+ len = strlen(val1) + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(new_val, len, "(%s)", val1);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate conditional expression");
+ rc = -1;
+ goto exit;
+ }
+ num_params = 0;
+ } else {
+ switch(curr->expr_type) {
+ case COND_NOT: op = "not"; break;
+ case COND_OR: op = "or"; break;
+ case COND_AND: op = "and"; break;
+ case COND_XOR: op = "xor"; break;
+ case COND_EQ: op = "eq"; break;
+ case COND_NEQ: op = "neq"; break;
+ default:
+ rc = -1;
+ goto exit;
+ }
+
+ num_params = curr->expr_type == COND_NOT ? 1 : 2;
+
+ if (num_params == 1) {
+ val1 = stack_pop(stack);
+ val2 = strdup("");
+ if (val2 == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ fmt_str = "(%s %s)";
+ } else {
+ val2 = stack_pop(stack);
+ val1 = stack_pop(stack);
+ fmt_str = "(%s %s %s)";
+ }
+
+ if (val1 == NULL || val2 == NULL) {
+ log_err("Invalid conditional expression");
+ rc = -1;
+ goto exit;
+ }
+
+ // length = length of parameters +
+ // length of operator +
+ // 1 space preceeding each parameter +
+ // 2 parens around the whole expression
+ // + null terminator
+ len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ // although we always supply val2 and there isn't always a 2nd
+ // value, it should only be used when there are actually two values
+ // in the format strings
+ rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate conditional expression");
+ rc = -1;
+ goto exit;
+ }
+
+ free(val1);
+ free(val2);
+ val1 = NULL;
+ val2 = NULL;
+ }
+
+ rc = stack_push(stack, new_val);
+ if (rc != 0) {
+ log_err("Out of memory");
+ goto exit;
+ }
+ new_val = NULL;
+ }
+
+ if (flags & COND_NODE_FLAGS_TUNABLE) {
+ type = "tunableif";
+ } else {
+ type = "booleanif";
+ }
+
+ val1 = stack_pop(stack);
+ if (val1 == NULL || stack_peek(stack) != NULL) {
+ log_err("Invalid conditional expression");
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(indent, "(%s %s", type, val1);
+ free(val1);
+ val1 = NULL;
+
+ rc = 0;
+
+exit:
+ free(new_val);
+ free(val1);
+ free(val2);
+ while ((val1 = stack_pop(stack)) != NULL) {
+ free(val1);
+ }
+ stack_destroy(&stack);
+
+ return rc;
+}
+
+static int cil_print_attr_list(int indent, struct policydb *pdb, struct list *attr_list)
+{
+ struct list_node *curr;
+ struct attr_list_node *attr_list_node;
+ int rc = 0;
+ struct type_set *ts;
+ struct role_set *rs;
+ char *generated_attribute;
+
+ for (curr = attr_list->head; curr != NULL; curr = curr->next) {
+ attr_list_node = curr->data;
+ generated_attribute = attr_list_node->attribute;
+ if (generated_attribute == NULL) {
+ return -1;
+ }
+
+ if (attr_list_node->is_type) {
+ ts = attr_list_node->set.ts;
+ rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+ if (rc != 0) {
+ return rc;
+ }
+ } else {
+ rs = attr_list_node->set.rs;
+ rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node *cond_list)
+{
+ int rc = -1;
+ struct cond_node *cond;
+ struct list *attr_list;
+
+ rc = list_init(&attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (cond = cond_list; cond != NULL; cond = cond->next) {
+
+ rc = cond_expr_to_cil(indent, pdb, cond->expr, cond->flags);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (cond->avtrue_list != NULL) {
+ cil_println(indent + 1, "(true");
+ rc = avrule_list_to_cil(indent + 2, pdb, cond->avtrue_list, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+ cil_println(indent + 1, ")");
+ }
+
+ if (cond->avfalse_list != NULL) {
+ cil_println(indent + 1, "(false");
+ rc = avrule_list_to_cil(indent + 2, pdb, cond->avfalse_list, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+ cil_println(indent + 1, ")");
+ }
+
+ cil_println(indent, ")");
+ }
+
+ rc = cil_print_attr_list(indent, pdb, attr_list);
+
+exit:
+ attr_list_destroy(&attr_list);
+ return rc;
+}
+
+static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans_rule *rules)
+{
+ int rc = -1;
+ struct role_trans_rule *rule;
+ char **role_names = NULL;
+ uint32_t num_role_names = 0;
+ char **type_names = NULL;
+ uint32_t num_type_names = 0;
+ uint32_t type;
+ uint32_t role;
+ uint32_t i;
+ struct ebitmap_node *node;
+ struct type_set *ts;
+ struct role_set *rs;
+
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ rs = &rule->roles;
+ rc = process_roleset(indent, pdb, rs, NULL, &role_names, &num_role_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &rule->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &type_names, &num_type_names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (role = 0; role < num_role_names; role++) {
+ for (type = 0; type < num_type_names; type++) {
+ ebitmap_for_each_bit(&rule->classes, node, i) {
+ if (!ebitmap_get_bit(&rule->classes, i)) {
+ continue;
+ }
+ cil_println(indent, "(roletransition %s %s %s %s)", role_names[role],
+ type_names[type],
+ pdb->p_class_val_to_name[i],
+ pdb->p_role_val_to_name[rule->new_role - 1]);
+ }
+ }
+ }
+
+ names_destroy(&role_names, &num_role_names);
+ names_destroy(&type_names, &num_type_names);
+ }
+
+ rc = 0;
+
+exit:
+ names_destroy(&role_names, &num_role_names);
+ names_destroy(&type_names, &num_type_names);
+
+ return rc;
+}
+
+static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allow_rule *rules)
+{
+ int rc = -1;
+ struct role_allow_rule *rule;
+ char **roles = NULL;
+ uint32_t num_roles = 0;
+ char **new_roles = NULL;
+ uint32_t num_new_roles = 0;
+ uint32_t i;
+ uint32_t j;
+ struct role_set *rs;
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ rs = &rule->roles;
+ rc = process_roleset(indent, pdb, rs, NULL, &roles, &num_roles);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rs = &rule->new_roles;
+ rc = process_roleset(indent, pdb, rs, NULL, &new_roles, &num_new_roles);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < num_roles; i++) {
+ for (j = 0; j < num_new_roles; j++) {
+ cil_println(indent, "(roleallow %s %s)", roles[i], new_roles[j]);
+ }
+ }
+
+ names_destroy(&roles, &num_roles);
+ names_destroy(&new_roles, &num_new_roles);
+ }
+
+ rc = 0;
+
+exit:
+ names_destroy(&roles, &num_roles);
+ names_destroy(&new_roles, &num_new_roles);
+
+ return rc;
+}
+
+static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_trans_rule *rules)
+{
+ int rc = -1;
+ struct range_trans_rule *rule;
+ char **stypes = NULL;
+ uint32_t num_stypes = 0;
+ char **ttypes = NULL;
+ uint32_t num_ttypes = 0;
+ struct ebitmap_node *node;
+ uint32_t i;
+ uint32_t stype;
+ uint32_t ttype;
+ struct type_set *ts;
+
+ if (!pdb->mls) {
+ return 0;
+ }
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ ts = &rule->stypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &rule->ttypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (stype = 0; stype < num_stypes; stype++) {
+ for (ttype = 0; ttype < num_ttypes; ttype++) {
+ ebitmap_for_each_bit(&rule->tclasses, node, i) {
+ if (!ebitmap_get_bit(&rule->tclasses, i)) {
+ continue;
+ }
+
+ cil_indent(indent);
+ cil_printf("(rangetransition %s %s %s ", stypes[stype], ttypes[ttype], pdb->p_class_val_to_name[i]);
+
+ cil_printf("(");
+
+ rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[0]);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ cil_printf(" ");
+
+ rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[1]);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ cil_printf("))\n");
+ }
+
+ }
+ }
+
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+ }
+
+ rc = 0;
+
+exit:
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+
+ return rc;
+}
+
+static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules)
+{
+ int rc = -1;
+ char **stypes = NULL;
+ uint32_t num_stypes = 0;
+ char **ttypes = NULL;
+ uint32_t num_ttypes = 0;
+ uint32_t stype;
+ uint32_t ttype;
+ struct type_set *ts;
+
+ struct filename_trans_rule *rule;
+
+ for (rule = rules; rule != NULL; rule = rule->next) {
+ ts = &rule->stypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ ts = &rule->ttypes;
+ rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (stype = 0; stype < num_stypes; stype++) {
+ for (ttype = 0; ttype < num_ttypes; ttype++) {
+ cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", stypes[stype],
+ ttypes[ttype],
+ pdb->p_class_val_to_name[rule->tclass - 1],
+ rule->name,
+ pdb->p_type_val_to_name[rule->otype - 1]);
+ }
+ }
+
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+ }
+
+ rc = 0;
+exit:
+ names_destroy(&stypes, &num_stypes);
+ names_destroy(&ttypes, &num_ttypes);
+
+ return rc;
+}
+
+struct class_perm_datum {
+ char *name;
+ uint32_t val;
+};
+
+struct class_perm_array {
+ struct class_perm_datum *perms;
+ uint32_t count;
+};
+
+static int class_perm_to_array(char *key, void *data, void *args)
+{
+ struct class_perm_array *arr = args;
+ struct perm_datum *datum = data;
+ arr->perms[arr->count].name = key;
+ arr->perms[arr->count].val = datum->s.value;
+ arr->count++;
+
+ return 0;
+}
+
+static int class_perm_cmp(const void *a, const void *b)
+{
+ const struct class_perm_datum *aa = a;
+ const struct class_perm_datum *bb = b;
+
+ return aa->val - bb->val;
+}
+
+static int common_to_cil(char *key, void *data, void *UNUSED(arg))
+{
+ int rc = -1;
+ struct common_datum *common = data;
+ struct class_perm_array arr;
+ uint32_t i;
+
+ arr.count = 0;
+ arr.perms = calloc(common->permissions.nprim, sizeof(*arr.perms));
+ rc = hashtab_map(common->permissions.table, class_perm_to_array, &arr);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+ cil_printf("(common %s (", key);
+ for (i = 0; i < arr.count; i++) {
+ cil_printf("%s ", arr.perms[i].name);
+ }
+ cil_printf("))\n");
+
+ rc = 0;
+
+exit:
+ free(arr.perms);
+ return rc;
+}
+
+
+static int constraint_expr_to_string(int indent, struct policydb *pdb, struct constraint_expr *exprs, char **expr_string)
+{
+ int rc = -1;
+ struct constraint_expr *expr;
+ struct stack *stack = NULL;
+ int len = 0;
+ int rlen;
+ char *new_val = NULL;
+ char *val1 = NULL;
+ char *val2 = NULL;
+ uint32_t num_params;
+ const char *op;
+ const char *fmt_str;
+ const char *attr1;
+ const char *attr2;
+ char *names;
+ char **name_list = NULL;
+ uint32_t num_names = 0;
+ struct type_set *ts;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (expr = exprs; expr != NULL; expr = expr->next) {
+ if (expr->expr_type == CEXPR_ATTR || expr->expr_type == CEXPR_NAMES) {
+ switch (expr->op) {
+ case CEXPR_EQ: op = "eq"; break;
+ case CEXPR_NEQ: op = "neq"; break;
+ case CEXPR_DOM: op = "dom"; break;
+ case CEXPR_DOMBY: op = "domby"; break;
+ case CEXPR_INCOMP: op = "incomp"; break;
+ default:
+ log_err("Unknown constraint operator type: %i", expr->op);
+ rc = -1;
+ goto exit;
+ }
+
+ switch (expr->attr) {
+ case CEXPR_USER: attr1 = "u1"; attr2 = "u2"; break;
+ case CEXPR_USER | CEXPR_TARGET: attr1 = "u2"; attr2 = ""; break;
+ case CEXPR_USER | CEXPR_XTARGET: attr1 = "u3"; attr2 = ""; break;
+ case CEXPR_ROLE: attr1 = "r1"; attr2 = "r2"; break;
+ case CEXPR_ROLE | CEXPR_TARGET: attr1 = "r2"; attr2 = ""; break;
+ case CEXPR_ROLE | CEXPR_XTARGET: attr1 = "r3"; attr2 = ""; break;
+ case CEXPR_TYPE: attr1 = "t1"; attr2 = ""; break;
+ case CEXPR_TYPE | CEXPR_TARGET: attr1 = "t2"; attr2 = ""; break;
+ case CEXPR_TYPE | CEXPR_XTARGET: attr1 = "t3"; attr2 = ""; break;
+ case CEXPR_L1L2: attr1 = "l1"; attr2 = "l2"; break;
+ case CEXPR_L1H2: attr1 = "l1"; attr2 = "h2"; break;
+ case CEXPR_H1L2: attr1 = "h1"; attr2 = "l2"; break;
+ case CEXPR_H1H2: attr1 = "h1"; attr2 = "h2"; break;
+ case CEXPR_L1H1: attr1 = "l1"; attr2 = "h1"; break;
+ case CEXPR_L2H2: attr1 = "l2"; attr2 = "h2"; break;
+ default:
+ log_err("Unknown expression attribute type: %i", expr->attr);
+ rc = -1;
+ goto exit;
+ }
+
+ if (expr->expr_type == CEXPR_ATTR) {
+ // length of values/attrs + 2 separating spaces + 2 parens + null terminator
+ len = strlen(op) + strlen(attr1) + strlen(attr2) + 2 + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, attr2);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate constraint expression");
+ rc = -1;
+ goto exit;
+ }
+ } else {
+ if (expr->attr & CEXPR_TYPE) {
+ ts = expr->type_names;
+ rc = process_typeset(indent, pdb, ts, NULL, &name_list, &num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else if (expr->attr & CEXPR_USER) {
+ rc = ebitmap_to_names(pdb->p_user_val_to_name, expr->names, &name_list, &num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ } else if (expr->attr & CEXPR_ROLE) {
+ rc = ebitmap_to_names(pdb->p_role_val_to_name, expr->names, &name_list, &num_names);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ rc = name_list_to_string(name_list, num_names, &names);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // length of values/oper + 2 spaces + 2 parens + null terminator
+ len = strlen(op) + strlen(attr1) + strlen(names) + 2 + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ names_destroy(&name_list, &num_names);
+ free(names);
+ }
+
+ num_params = 0;
+ } else {
+ switch (expr->expr_type) {
+ case CEXPR_NOT: op = "not"; break;
+ case CEXPR_AND: op = "and"; break;
+ case CEXPR_OR: op = "or"; break;
+ default:
+ log_err("Unknown constraint expression type: %i", expr->expr_type);
+ rc = -1;
+ goto exit;
+ }
+
+ num_params = expr->expr_type == CEXPR_NOT ? 1 : 2;
+
+ if (num_params == 1) {
+ val1 = stack_pop(stack);
+ val2 = strdup("");
+ if (val2 == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ fmt_str = "(%s %s)";
+ } else {
+ val2 = stack_pop(stack);
+ val1 = stack_pop(stack);
+ fmt_str = "(%s %s %s)";
+ }
+
+ if (val1 == NULL || val2 == NULL) {
+ log_err("Invalid constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ // length = length of parameters +
+ // length of operator +
+ // 1 space preceeding each parameter +
+ // 2 parens around the whole expression
+ // + null terminator
+ len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+ new_val = malloc(len);
+ if (new_val == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ // although we always supply val2 and there isn't always a 2nd
+ // value, it should only be used when there are actually two values
+ // in the format strings
+ rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+ if (rlen < 0 || rlen >= len) {
+ log_err("Failed to generate constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ free(val1);
+ free(val2);
+ val1 = NULL;
+ val2 = NULL;
+ }
+
+ rc = stack_push(stack, new_val);
+ if (rc != 0) {
+ log_err("Out of memory");
+ goto exit;
+ }
+
+ new_val = NULL;
+ }
+
+ new_val = stack_pop(stack);
+ if (new_val == NULL || stack_peek(stack) != NULL) {
+ log_err("Invalid constraint expression");
+ rc = -1;
+ goto exit;
+ }
+
+ *expr_string = new_val;
+ new_val = NULL;
+
+ rc = 0;
+
+exit:
+ names_destroy(&name_list, &num_names);
+
+ free(new_val);
+ free(val1);
+ free(val2);
+ while ((val1 = stack_pop(stack)) != NULL) {
+ free(val1);
+ }
+ stack_destroy(&stack);
+
+ return rc;
+}
+
+
+static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey, struct class_datum *class, struct constraint_node *constraints, int is_constraint)
+{
+ int rc = -1;
+ struct constraint_node *node;
+ char *expr = NULL;
+ const char *mls;
+ char *perms;
+
+ mls = pdb->mls ? "mls" : "";
+
+ for (node = constraints; node != NULL; node = node->next) {
+
+ rc = constraint_expr_to_string(indent, pdb, node->expr, &expr);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (is_constraint) {
+ perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
+ cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
+ } else {
+ cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
+ }
+
+ free(expr);
+ expr = NULL;
+ }
+
+ rc = 0;
+
+exit:
+ free(expr);
+ return rc;
+}
+
+static int class_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ int rc = -1;
+ struct class_datum *class = datum;
+ const char *dflt;
+ struct class_perm_array arr;
+ uint32_t i;
+
+ if (scope == SCOPE_REQ) {
+ return 0;
+ }
+
+ arr.count = 0;
+ arr.perms = calloc(class->permissions.nprim, sizeof(*arr.perms));
+ rc = hashtab_map(class->permissions.table, class_perm_to_array, &arr);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+ cil_indent(indent);
+ cil_printf("(class %s (", key);
+ for (i = 0; i < arr.count; i++) {
+ cil_printf("%s ", arr.perms[i].name);
+ }
+ cil_printf("))\n");
+
+ if (class->comkey != NULL) {
+ cil_println(indent, "(classcommon %s %s)", key, class->comkey);
+ }
+
+ if (class->default_user != 0) {
+ switch (class->default_user) {
+ case DEFAULT_SOURCE: dflt = "source"; break;
+ case DEFAULT_TARGET: dflt = "target"; break;
+ default:
+ log_err("Unknown default user value: %i", class->default_user);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaultuser %s %s)", key, dflt);
+ }
+
+ if (class->default_role != 0) {
+ switch (class->default_role) {
+ case DEFAULT_SOURCE: dflt = "source"; break;
+ case DEFAULT_TARGET: dflt = "target"; break;
+ default:
+ log_err("Unknown default role value: %i", class->default_role);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaultrole %s %s)", key, dflt);
+ }
+
+ if (class->default_type != 0) {
+ switch (class->default_type) {
+ case DEFAULT_SOURCE: dflt = "source"; break;
+ case DEFAULT_TARGET: dflt = "target"; break;
+ default:
+ log_err("Unknown default type value: %i", class->default_type);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaulttype %s %s)", key, dflt);
+ }
+
+ if (class->default_range != 0) {
+ switch (class->default_range) {
+ case DEFAULT_SOURCE_LOW: dflt = "source low"; break;
+ case DEFAULT_SOURCE_HIGH: dflt = "source high"; break;
+ case DEFAULT_SOURCE_LOW_HIGH: dflt = "source low-high"; break;
+ case DEFAULT_TARGET_LOW: dflt = "target low"; break;
+ case DEFAULT_TARGET_HIGH: dflt = "target high"; break;
+ case DEFAULT_TARGET_LOW_HIGH: dflt = "target low-high"; break;
+ default:
+ log_err("Unknown default range value: %i", class->default_range);
+ rc = -1;
+ goto exit;
+ }
+ cil_println(indent, "(defaultrange %s %s)", key, dflt);
+
+ }
+
+ if (class->constraints != NULL) {
+ rc = constraints_to_cil(indent, pdb, key, class, class->constraints, 1);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (class->validatetrans != NULL) {
+ rc = constraints_to_cil(indent, pdb, key, class, class->validatetrans, 0);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ rc = 0;
+
+exit:
+ free(arr.perms);
+ return rc;
+}
+
+static int class_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+ struct ebitmap_node *node;
+ uint32_t i;
+
+ if (ebitmap_cardinality(&order) == 0) {
+ return 0;
+ }
+
+ cil_indent(indent);
+ cil_printf("(classorder (");
+
+ ebitmap_for_each_bit(&order, node, i) {
+ if (!ebitmap_get_bit(&order, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->sym_val_to_name[SYM_CLASSES][i]);
+ }
+
+ cil_printf("))\n");
+
+ return 0;
+}
+
+static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+ int rc = -1;
+ struct ebitmap_node *node;
+ uint32_t i;
+ char **types = NULL;
+ uint32_t num_types = 0;
+ struct role_datum *role = datum;
+ struct type_set *ts;
+
+ if (scope == SCOPE_REQ) {
+ // if a role/roleattr is in the REQ scope, then it could cause an
+ // optional block to fail, even if it is never used. However in CIL,
+ // symbols must be used in order to cause an optional block to fail. So
+ // for symbols in the REQ scope, add them to a roleattribute as a way
+ // to 'use' them in the optional without affecting the resulting policy.
+ cil_println(indent, "(roleattributeset " GEN_REQUIRE_ATTR " %s)", key);
+ }
+
+ switch (role->flavor) {
+ case ROLE_ROLE:
+ if (scope == SCOPE_DECL) {
+ // Only declare certain roles if we are reading a base module.
+ // These roles are defined in the base module and sometimes in
+ // other non-base modules. If we generated the roles regardless of
+ // the policy type, it would result in duplicate declarations,
+ // which isn't allowed in CIL. Patches have been made to refpolicy
+ // to remove these duplicate role declarations, but we need to be
+ // backwards compatable and support older policies. Since we know
+ // these roles are always declared in base, only print them when we
+ // see them in the base module. If the declarations appear in a
+ // non-base module, ignore their declarations.
+ //
+ // Note that this is a hack, and if a policy author does not define
+ // one of these roles in base, the declaration will not appeaer in
+ // the resulting policy, likely resulting in a compilation error in
+ // CIL.
+ int is_base_role = (!strcmp(key, "user_r") ||
+ !strcmp(key, "staff_r") ||
+ !strcmp(key, "sysadm_r") ||
+ !strcmp(key, "system_r") ||
+ !strcmp(key, "unconfined_r"));
+ if ((is_base_role && pdb->policy_type == SEPOL_POLICY_BASE) || !is_base_role) {
+ cil_println(indent, "(role %s)", key);
+ }
+ }
+
+ if (ebitmap_cardinality(&role->dominates) > 1) {
+ log_err("Warning: role 'dominance' statement unsupported in CIL. Dropping from output.");
+ }
+
+ ts = &role->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < num_types; i++) {
+ if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
+ cil_println(indent, "(roletype %s %s)", key, types[i]);
+ }
+ }
+
+ if (role->bounds > 0) {
+ cil_println(indent, "(rolebounds %s %s)", key, pdb->p_role_val_to_name[role->bounds - 1]);
+ }
+ break;
+
+ case ROLE_ATTRIB:
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(roleattribute %s)", key);
+ }
+
+ if (ebitmap_cardinality(&role->roles) > 0) {
+ cil_indent(indent);
+ cil_printf("(roleattributeset %s (", key);
+ ebitmap_for_each_bit(&role->roles, node, i) {
+ if (!ebitmap_get_bit(&role->roles, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->p_role_val_to_name[i]);
+ }
+ cil_printf("))\n");
+ }
+
+ ts = &role->types;
+ rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+ if (rc != 0) {
+ goto exit;
+ }
+
+
+ for (i = 0; i < num_types; i++) {
+ cil_println(indent, "(roletype %s %s)", key, types[i]);
+ }
+
+ break;
+
+ default:
+ log_err("Unknown role type: %i", role->flavor);
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ names_destroy(&types, &num_types);
+
+ return rc;
+}
+
+static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+ int rc = -1;
+ struct type_datum *type = datum;
+
+ if (scope == SCOPE_REQ) {
+ // if a type/typeattr is in the REQ scope, then it could cause an
+ // optional block to fail, even if it is never used. However in CIL,
+ // symbols must be used in order to cause an optional block to fail. So
+ // for symbols in the REQ scope, add them to a typeattribute as a way
+ // to 'use' them in the optional without affecting the resulting policy.
+ cil_println(indent, "(typeattributeset " GEN_REQUIRE_ATTR " %s)", key);
+ }
+
+ rc = roletype_role_in_ancestor_to_cil(pdb, decl_stack, key, indent);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ switch(type->flavor) {
+ case TYPE_TYPE:
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(type %s)", key);
+ // object_r is implicit in checkmodule, but not with CIL,
+ // create it as part of base
+ cil_println(indent, "(roletype " DEFAULT_OBJECT " %s)", key);
+ }
+
+ if (type->flags & TYPE_FLAGS_PERMISSIVE) {
+ cil_println(indent, "(typepermissive %s)", key);
+ }
+
+ if (type->bounds > 0) {
+ cil_println(indent, "(typebounds %s %s)", pdb->p_type_val_to_name[type->bounds - 1], key);
+ }
+ break;
+ case TYPE_ATTRIB:
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(typeattribute %s)", key);
+ }
+
+ if (ebitmap_cardinality(&type->types) > 0) {
+ cil_indent(indent);
+ cil_printf("(typeattributeset %s (", key);
+ ebitmap_to_cil(pdb, &type->types, SYM_TYPES);
+ cil_printf("))\n");
+ }
+ break;
+ default:
+ log_err("Unknown flavor (%i) of type %s", type->flavor, key);
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+
+exit:
+ return rc;
+}
+
+static int user_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct user_datum *user = datum;
+ struct ebitmap roles = user->roles.roles;
+ struct mls_semantic_level level = user->dfltlevel;
+ struct mls_semantic_range range = user->range;
+ struct ebitmap_node *node;
+ uint32_t i;
+ int sens_offset = 1;
+
+ if (scope == SCOPE_DECL) {
+ cil_println(indent, "(user %s)", key);
+ // object_r is implicit in checkmodule, but not with CIL, create it
+ // as part of base
+ cil_println(indent, "(userrole %s " DEFAULT_OBJECT ")", key);
+ }
+
+ ebitmap_for_each_bit(&roles, node, i) {
+ if (!ebitmap_get_bit(&roles, i)) {
+ continue;
+ }
+ cil_println(indent, "(userrole %s %s)", key, pdb->p_role_val_to_name[i]);
+ }
+
+ if (block->flags & AVRULE_OPTIONAL) {
+ // sensitivites in user statements in optionals do not have the
+ // standard -1 offest
+ sens_offset = 0;
+ }
+
+ cil_indent(indent);
+ cil_printf("(userlevel %s ", key);
+ if (pdb->mls) {
+ semantic_level_to_cil(pdb, sens_offset, &level);
+ } else {
+ cil_printf(DEFAULT_LEVEL);
+ }
+ cil_printf(")\n");
+
+ cil_indent(indent);
+ cil_printf("(userrange %s (", key);
+ if (pdb->mls) {
+ semantic_level_to_cil(pdb, sens_offset, &range.level[0]);
+ cil_printf(" ");
+ semantic_level_to_cil(pdb, sens_offset, &range.level[1]);
+ } else {
+ cil_printf(DEFAULT_LEVEL " " DEFAULT_LEVEL);
+ }
+ cil_printf("))\n");
+
+
+ return 0;
+}
+
+static int boolean_to_cil(int indent, struct policydb *UNUSED(pdb), struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct cond_bool_datum *boolean = datum;
+ const char *type;
+
+ if (scope == SCOPE_DECL) {
+ if (boolean->flags & COND_BOOL_FLAGS_TUNABLE) {
+ type = "tunable";
+ } else {
+ type = "boolean";
+ }
+
+ cil_println(indent, "(%s %s %s)", type, key, boolean->state ? "true" : "false");
+ }
+
+ return 0;
+}
+
+static int sens_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct level_datum *level = datum;
+
+ if (scope == SCOPE_DECL) {
+ if (!level->isalias) {
+ cil_println(indent, "(sensitivity %s)", key);
+ } else {
+ cil_println(indent, "(sensitivityalias %s)", key);
+ cil_println(indent, "(sensitivityaliasactual %s %s)", key, pdb->p_sens_val_to_name[level->level->sens - 1]);
+ }
+ }
+
+ if (ebitmap_cardinality(&level->level->cat) > 0) {
+ cil_indent(indent);
+ cil_printf("(sensitivitycategory %s (", key);
+ ebitmap_to_cil(pdb, &level->level->cat, SYM_CATS);
+ cil_printf("))\n");
+ }
+
+ return 0;
+}
+
+static int sens_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+ struct ebitmap_node *node;
+ uint32_t i;
+
+ if (ebitmap_cardinality(&order) == 0) {
+ return 0;
+ }
+
+ cil_indent(indent);
+ cil_printf("(sensitivityorder (");
+
+ ebitmap_for_each_bit(&order, node, i) {
+ if (!ebitmap_get_bit(&order, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->p_sens_val_to_name[i]);
+ }
+
+ cil_printf("))\n");
+
+ return 0;
+}
+
+static int cat_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+ struct cat_datum *cat = datum;
+
+ if (scope == SCOPE_REQ) {
+ return 0;
+ }
+
+ if (!cat->isalias) {
+ cil_println(indent, "(category %s)", key);
+ } else {
+ cil_println(indent, "(categoryalias %s)", key);
+ cil_println(indent, "(categoryaliasactual %s %s)", key, pdb->p_cat_val_to_name[cat->s.value - 1]);
+ }
+
+ return 0;
+}
+
+static int cat_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+ int rc = -1;
+ struct ebitmap_node *node;
+ uint32_t i;
+
+ if (ebitmap_cardinality(&order) == 0) {
+ rc = 0;
+ goto exit;
+ }
+
+ cil_indent(indent);
+ cil_printf("(categoryorder (");
+
+ ebitmap_for_each_bit(&order, node, i) {
+ if (!ebitmap_get_bit(&order, i)) {
+ continue;
+ }
+ cil_printf("%s ", pdb->p_cat_val_to_name[i]);
+ }
+
+ cil_printf("))\n");
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int polcaps_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ struct ebitmap *map;
+ struct ebitmap_node *node;
+ uint32_t i;
+ const char *name;
+
+ map = &pdb->policycaps;
+
+ ebitmap_for_each_bit(map, node, i) {
+ if (!ebitmap_get_bit(map, i)) {
+ continue;
+ }
+ name = sepol_polcap_getname(i);
+ if (name == NULL) {
+ log_err("Unknown policy capability id: %i", i);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(0, "(policycap %s)", name);
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int level_to_cil(struct policydb *pdb, struct mls_level *level)
+{
+ struct ebitmap *map = &level->cat;
+
+ cil_printf("(%s", pdb->p_sens_val_to_name[level->sens - 1]);
+
+ if (ebitmap_cardinality(map) > 0) {
+ cil_printf("(");
+ ebitmap_to_cil(pdb, map, SYM_CATS);
+ cil_printf(")");
+ }
+
+ cil_printf(")");
+
+ return 0;
+}
+
+static int context_to_cil(struct policydb *pdb, struct context_struct *con)
+{
+ cil_printf("(%s %s %s (",
+ pdb->p_user_val_to_name[con->user - 1],
+ pdb->p_role_val_to_name[con->role - 1],
+ pdb->p_type_val_to_name[con->type - 1]);
+
+ if (pdb->mls) {
+ level_to_cil(pdb, &con->range.level[0]);
+ cil_printf(" ");
+ level_to_cil(pdb, &con->range.level[1]);
+ } else {
+ cil_printf(DEFAULT_LEVEL);
+ cil_printf(" ");
+ cil_printf(DEFAULT_LEVEL);
+ }
+
+ cil_printf("))");
+
+ return 0;
+}
+
+static int ocontext_isid_to_cil(struct policydb *pdb, const char **sid_to_string, struct ocontext *isids)
+{
+ int rc = -1;
+
+ struct ocontext *isid;
+
+ struct sid_item {
+ const char *sid_key;
+ struct sid_item *next;
+ };
+
+ struct sid_item *head = NULL;
+ struct sid_item *item = NULL;
+
+ for (isid = isids; isid != NULL; isid = isid->next) {
+ cil_println(0, "(sid %s)", sid_to_string[isid->sid[0]]);
+ cil_printf("(sidcontext %s ", sid_to_string[isid->sid[0]]);
+ context_to_cil(pdb, &isid->context[0]);
+ cil_printf(")\n");
+
+ // get the sid names in the correct order (reverse from the isids
+ // ocontext) for sidorder statement
+ item = malloc(sizeof(*item));
+ if (item == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ item->sid_key = sid_to_string[isid->sid[0]];
+ item->next = head;
+ head = item;
+ }
+
+ if (head != NULL) {
+ cil_printf("(sidorder (");
+ for (item = head; item != NULL; item = item->next) {
+ cil_printf("%s ", item->sid_key);
+ }
+ cil_printf("))\n");
+ }
+
+ rc = 0;
+
+exit:
+ while(head) {
+ item = head;
+ head = item->next;
+ free(item);
+ }
+ return rc;
+}
+
+static int ocontext_selinux_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+ int rc = -1;
+
+ // initial sid names aren't actually stored in the pp files, need to a have
+ // a mapping, taken from the linux kernel
+ static const char *selinux_sid_to_string[] = {
+ "null",
+ "kernel",
+ "security",
+ "unlabeled",
+ "fs",
+ "file",
+ "file_labels",
+ "init",
+ "any_socket",
+ "port",
+ "netif",
+ "netmsg",
+ "node",
+ "igmp_packet",
+ "icmp_socket",
+ "tcp_socket",
+ "sysctl_modprobe",
+ "sysctl",
+ "sysctl_fs",
+ "sysctl_kernel",
+ "sysctl_net",
+ "sysctl_net_unix",
+ "sysctl_vm",
+ "sysctl_dev",
+ "kmod",
+ "policy",
+ "scmp_packet",
+ "devnull",
+ NULL
+ };
+
+ rc = ocontext_isid_to_cil(pdb, selinux_sid_to_string, isids);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int ocontext_selinux_fs_to_cil(struct policydb *UNUSED(pdb), struct ocontext *fss)
+{
+ if (fss != NULL) {
+ log_err("Warning: 'fscon' statement unsupported in CIL. Dropping from output.");
+ }
+
+ return 0;
+}
+
+static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *portcons)
+{
+ int rc = -1;
+ struct ocontext *portcon;
+ const char *protocol;
+ uint16_t high;
+ uint16_t low;
+
+ for (portcon = portcons; portcon != NULL; portcon = portcon->next) {
+
+ switch (portcon->u.port.protocol) {
+ case IPPROTO_TCP: protocol = "tcp"; break;
+ case IPPROTO_UDP: protocol = "udp"; break;
+ default:
+ log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
+ rc = -1;
+ goto exit;
+ }
+
+ low = portcon->u.port.low_port;
+ high = portcon->u.port.high_port;
+
+ if (low == high) {
+ cil_printf("(portcon %s %i ", protocol, low);
+ } else {
+ cil_printf("(portcon %s (%i %i) ", protocol, low, high);
+ }
+
+ context_to_cil(pdb, &portcon->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
+{
+ struct ocontext *netif;
+
+ for (netif = netifs; netif != NULL; netif = netif->next) {
+ cil_printf("(netifcon %s ", netif->u.name);
+ context_to_cil(pdb, &netif->context[0]);
+
+ cil_printf(" ");
+ context_to_cil(pdb, &netif->context[1]);
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_selinux_node_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+ int rc = -1;
+ struct ocontext *node;
+ char addr[INET_ADDRSTRLEN];
+ char mask[INET_ADDRSTRLEN];
+
+ for (node = nodes; node != NULL; node = node->next) {
+ if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon address is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon mask is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(nodecon %s %s ", addr, mask);
+
+ context_to_cil(pdb, &node->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int ocontext_selinux_node6_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+ int rc = -1;
+ struct ocontext *node;
+ char addr[INET6_ADDRSTRLEN];
+ char mask[INET6_ADDRSTRLEN];
+
+ for (node = nodes; node != NULL; node = node->next) {
+ if (inet_ntop(AF_INET6, &node->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon address is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ if (inet_ntop(AF_INET6, &node->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
+ log_err("Nodecon mask is invalid: %s", strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(nodecon %s %s ", addr, mask);
+
+ context_to_cil(pdb, &node->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+
+static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
+{
+ int rc = -1;
+ struct ocontext *fsuse;
+ const char *behavior;
+
+
+ for (fsuse = fsuses; fsuse != NULL; fsuse = fsuse->next) {
+ switch (fsuse->v.behavior) {
+ case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
+ case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
+ case SECURITY_FS_USE_TASK: behavior = "task"; break;
+ default:
+ log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(fsuse %s %s ", behavior, fsuse->u.name);
+
+ context_to_cil(pdb, &fsuse->context[0]);
+
+ cil_printf(")\n");
+
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+
+static int ocontext_xen_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+ int rc = -1;
+
+ // initial sid names aren't actually stored in the pp files, need to a have
+ // a mapping, taken from the xen kernel
+ static const char *xen_sid_to_string[] = {
+ "null",
+ "xen",
+ "dom0",
+ "domio",
+ "domxen",
+ "unlabeled",
+ "security",
+ "ioport",
+ "iomem",
+ "irq",
+ "device",
+ NULL,
+ };
+
+ rc = ocontext_isid_to_cil(pdb, xen_sid_to_string, isids);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int ocontext_xen_pirq_to_cil(struct policydb *pdb, struct ocontext *pirqs)
+{
+ struct ocontext *pirq;
+
+ for (pirq = pirqs; pirq != NULL; pirq = pirq->next) {
+ cil_printf("(pirqcon %i ", pirq->u.pirq);
+ context_to_cil(pdb, &pirq->context[0]);
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_xen_ioport_to_cil(struct policydb *pdb, struct ocontext *ioports)
+{
+ struct ocontext *ioport;
+ uint32_t low;
+ uint32_t high;
+
+ for (ioport = ioports; ioport != NULL; ioport = ioport->next) {
+ low = ioport->u.ioport.low_ioport;
+ high = ioport->u.ioport.high_ioport;
+
+ if (low == high) {
+ cil_printf("(ioportcon %i ", low);
+ } else {
+ cil_printf("(ioportcon (%i %i) ", low, high);
+ }
+
+ context_to_cil(pdb, &ioport->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_xen_iomem_to_cil(struct policydb *pdb, struct ocontext *iomems)
+{
+ struct ocontext *iomem;
+ uint64_t low;
+ uint64_t high;
+
+ for (iomem = iomems; iomem != NULL; iomem = iomem->next) {
+ low = iomem->u.iomem.low_iomem;
+ high = iomem->u.iomem.high_iomem;
+
+ if (low == high) {
+ cil_printf("(iomemcon %#lX ", (unsigned long)low);
+ } else {
+ cil_printf("(iomemcon (%#lX %#lX) ", (unsigned long)low, (unsigned long)high);
+ }
+
+ context_to_cil(pdb, &iomem->context[0]);
+
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontext_xen_pcidevice_to_cil(struct policydb *pdb, struct ocontext *pcids)
+{
+ struct ocontext *pcid;
+
+ for (pcid = pcids; pcid != NULL; pcid = pcid->next) {
+ cil_printf("(pcidevicecon %#lx ", (unsigned long)pcid->u.device);
+ context_to_cil(pdb, &pcid->context[0]);
+ cil_printf(")\n");
+ }
+
+ return 0;
+}
+
+static int ocontexts_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ int ocon;
+
+ static int (**ocon_funcs)(struct policydb *pdb, struct ocontext *ocon);
+ static int (*ocon_selinux_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+ ocontext_selinux_isid_to_cil,
+ ocontext_selinux_fs_to_cil,
+ ocontext_selinux_port_to_cil,
+ ocontext_selinux_netif_to_cil,
+ ocontext_selinux_node_to_cil,
+ ocontext_selinux_fsuse_to_cil,
+ ocontext_selinux_node6_to_cil,
+ };
+ static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+ ocontext_xen_isid_to_cil,
+ ocontext_xen_pirq_to_cil,
+ ocontext_xen_ioport_to_cil,
+ ocontext_xen_iomem_to_cil,
+ ocontext_xen_pcidevice_to_cil,
+ NULL,
+ NULL,
+ };
+
+ switch (pdb->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ ocon_funcs = ocon_selinux_funcs;
+ break;
+ case SEPOL_TARGET_XEN:
+ ocon_funcs = ocon_xen_funcs;
+ break;
+ default:
+ log_err("Unknown target platform: %i", pdb->target_platform);
+ rc = -1;
+ goto exit;
+ }
+
+ for (ocon = 0; ocon < OCON_NUM; ocon++) {
+ if (ocon_funcs[ocon] != NULL) {
+ rc = ocon_funcs[ocon](pdb, pdb->ocontexts[ocon]);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int genfscon_to_cil(struct policydb *pdb)
+{
+ struct genfs *genfs;
+ struct ocontext *ocon;
+
+ for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
+ for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
+ cil_printf("(genfscon %s %s ", genfs->fstype, ocon->u.name);
+ context_to_cil(pdb, &ocon->context[0]);
+ cil_printf(")\n");
+ }
+ }
+
+ return 0;
+}
+
+static int level_string_to_cil(char *levelstr)
+{
+ int rc = -1;
+ char *sens = NULL;
+ char *cats = NULL;
+ int matched;
+ char *saveptr = NULL;
+ char *token = NULL;
+ char *ranged = NULL;
+
+ matched = sscanf(levelstr, "%m[^:]:%ms", &sens, &cats);
+ if (matched < 1 || matched > 2) {
+ log_err("Invalid level: %s", levelstr);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(%s", sens);
+
+ if (matched == 2) {
+ cil_printf("(");
+ token = strtok_r(cats, ",", &saveptr);
+ while (token != NULL) {
+ ranged = strchr(token, '.');
+ if (ranged == NULL) {
+ cil_printf("%s ", token);
+ } else {
+ *ranged = '\0';
+ cil_printf("(range %s %s) ", token, ranged + 1);
+ }
+ token = strtok_r(NULL, ",", &saveptr);
+ }
+ cil_printf(")");
+ }
+
+ cil_printf(")");
+
+ rc = 0;
+exit:
+ free(sens);
+ free(cats);
+ return rc;
+}
+
+static int level_range_string_to_cil(char *levelrangestr)
+{
+ char *ranged = NULL;
+ char *low;
+ char *high;
+
+ ranged = strchr(levelrangestr, '-');
+ if (ranged == NULL) {
+ low = high = levelrangestr;
+ } else {
+ *ranged = '\0';
+ low = levelrangestr;
+ high = ranged + 1;
+ }
+
+ level_string_to_cil(low);
+ cil_printf(" ");
+ level_string_to_cil(high);
+
+ return 0;
+}
+
+static int context_string_to_cil(char *contextstr)
+{
+ int rc = -1;
+ int matched;
+ char *user = NULL;
+ char *role = NULL;
+ char *type = NULL;
+ char *level = NULL;
+
+ matched = sscanf(contextstr, "%m[^:]:%m[^:]:%m[^:]:%ms", &user, &role, &type, &level);
+ if (matched < 3 || matched > 4) {
+ log_err("Invalid context: %s", contextstr);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_printf("(%s %s %s (", user, role, type);
+
+ if (matched == 3) {
+ cil_printf(DEFAULT_LEVEL);
+ cil_printf(" ");
+ cil_printf(DEFAULT_LEVEL);
+ } else {
+ level_range_string_to_cil(level);
+ }
+
+ cil_printf("))");
+
+ rc = 0;
+
+exit:
+ free(user);
+ free(role);
+ free(type);
+ free(level);
+
+ return rc;
+}
+
+static int seusers_to_cil(struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ FILE *fp = NULL;
+ char *seusers = sepol_module_package_get_seusers(mod_pkg);
+ size_t seusers_len = sepol_module_package_get_seusers_len(mod_pkg);
+ size_t len = 0;
+ char *line = NULL;
+ ssize_t line_len = 0;
+ char *buf = NULL;
+
+ char *user = NULL;
+ char *seuser = NULL;
+ char *level = NULL;
+ int matched;
+
+ if (seusers_len == 0) {
+ return 0;
+ }
+
+ fp = fmemopen(seusers, seusers_len, "r");
+
+ while ((line_len = getline(&line, &len, fp)) != -1) {
+ buf = line;
+ buf[line_len - 1] = '\0';
+ while (*buf && isspace(buf[0])) {
+ buf++;
+ }
+ if (buf[0] == '#' || buf[0] == '\0') {
+ continue;
+ }
+
+ matched = sscanf(buf, "%m[^:]:%m[^:]:%ms", &user, &seuser, &level);
+
+ if (matched < 2 || matched > 3) {
+ log_err("Invalid seuser line: %s", line);
+ rc = -1;
+ goto exit;
+ }
+
+ if (!strcmp(user, "__default__")) {
+ cil_printf("(selinuxuserdefault %s (", seuser);
+ } else {
+ cil_printf("(selinuxuser %s %s (", user, seuser);
+ }
+
+ switch (matched) {
+ case 2:
+ cil_printf("systemlow systemlow");
+ break;
+ case 3:
+ level_range_string_to_cil(level);
+ break;
+ }
+
+ cil_printf("))\n");
+
+ free(user);
+ free(seuser);
+ free(level);
+ user = seuser = level = NULL;
+ }
+ if (ferror(fp)) {
+ cil_printf("Failed to read seusers\n");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+
+exit:
+ if (fp != NULL) {
+ fclose(fp);
+ }
+ free(line);
+ free(user);
+ free(seuser);
+ free(level);
+
+ return rc;
+}
+
+static int netfilter_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+ size_t netcons_len = sepol_module_package_get_netfilter_contexts_len(mod_pkg);
+
+ if (netcons_len > 0) {
+ log_err("Warning: netfilter_contexts are unsupported in CIL. Dropping from output.");
+ }
+
+ return 0;
+}
+
+static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ char *userx = sepol_module_package_get_user_extra(mod_pkg);
+ size_t userx_len = sepol_module_package_get_user_extra_len(mod_pkg);
+ FILE *fp = NULL;
+ size_t len = 0;
+ char *line = NULL;
+ ssize_t line_len = 0;
+ int matched;
+ char *user = NULL;
+ char *prefix = NULL;
+
+ if (userx_len == 0) {
+ return 0;
+ }
+
+ fp = fmemopen(userx, userx_len, "r");
+
+ while ((line_len = getline(&line, &len, fp)) != -1) {
+ line[line_len - 1] = '\0';
+
+ matched = sscanf(line, "user %ms prefix %m[^;];", &user, &prefix);
+ if (matched != 2) {
+ rc = -1;
+ log_err("Invalid file context line: %s", line);
+ goto exit;
+ }
+
+ cil_println(0, "(userprefix %s %s)", user, prefix);
+ free(user);
+ free(prefix);
+ user = prefix = NULL;
+ }
+
+ if (ferror(fp)) {
+ cil_printf("Failed to read user_extra\n");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ if (fp != NULL) {
+ fclose(fp);
+ }
+ free(line);
+ free(user);
+ free(prefix);
+
+ return rc;
+}
+
+static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ char *fc = sepol_module_package_get_file_contexts(mod_pkg);
+ size_t fc_len = sepol_module_package_get_file_contexts_len(mod_pkg);
+ FILE *fp = NULL;
+ size_t len = 0;
+ char *line = NULL;
+ char *buf = NULL;
+ ssize_t line_len = 0;
+ int matched;
+ char *regex = NULL;
+ char *mode = NULL;
+ char *context = NULL;
+ const char *cilmode;
+
+ if (fc_len == 0) {
+ return 0;
+ }
+
+ fp = fmemopen(fc, fc_len, "r");
+ while ((line_len = getline(&line, &len, fp)) != -1) {
+ buf = line;
+ if (buf[line_len - 1] == '\n') {
+ buf[line_len - 1] = '\0';
+ }
+ while (*buf && isspace(buf[0])) {
+ buf++;
+ }
+ if (buf[0] == '#' || buf[0] == '\0') {
+ continue;
+ }
+
+ matched = sscanf(buf, "%ms %ms %ms", ®ex, &mode, &context);
+ if (matched < 2 || matched > 3) {
+ rc = -1;
+ log_err("Invalid file context line: %s", line);
+ goto exit;
+ }
+
+ if (matched == 2) {
+ context = mode;
+ mode = NULL;
+ }
+
+ if (mode == NULL) {
+ cilmode = "any";
+ } else if (!strcmp(mode, "--")) {
+ cilmode = "file";
+ } else if (!strcmp(mode, "-d")) {
+ cilmode = "dir";
+ } else if (!strcmp(mode, "-c")) {
+ cilmode = "char";
+ } else if (!strcmp(mode, "-b")) {
+ cilmode = "block";
+ } else if (!strcmp(mode, "-s")) {
+ cilmode = "socket";
+ } else if (!strcmp(mode, "-p")) {
+ cilmode = "pipe";
+ } else if (!strcmp(mode, "-l")) {
+ cilmode = "symlink";
+ } else {
+ rc = -1;
+ log_err("Invalid mode in file context line: %s", line);
+ goto exit;
+ }
+
+ cil_printf("(filecon \"%s\" %s ", regex, cilmode);
+
+ if (!strcmp(context, "<<none>>")) {
+ cil_printf("()");
+ } else {
+ context_string_to_cil(context);
+ }
+
+ cil_printf(")\n");
+
+ free(regex);
+ free(mode);
+ free(context);
+ regex = mode = context = NULL;
+ }
+
+ if (ferror(fp)) {
+ cil_printf("Failed to read user_extra\n");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = 0;
+exit:
+ free(line);
+ free(regex);
+ free(mode);
+ free(context);
+ if (fp != NULL) {
+ fclose(fp);
+ }
+
+ return rc;
+}
+
+
+static int (*func_to_cil[SYM_NUM])(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack, char *key, void *datum, int scope) = {
+ NULL, // commons, only stored in the global symtab, handled elsewhere
+ class_to_cil,
+ role_to_cil,
+ type_to_cil,
+ user_to_cil,
+ boolean_to_cil,
+ sens_to_cil,
+ cat_to_cil
+};
+
+static int typealiases_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack)
+{
+ struct type_datum *alias_datum;
+ char *alias_name;
+ struct list_node *curr;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+ struct list *alias_list = typealias_lists[decl->decl_id];
+ int rc = -1;
+
+ if (alias_list == NULL) {
+ return 0;
+ }
+
+ for (curr = alias_list->head; curr != NULL; curr = curr->next) {
+ alias_name = curr->data;
+ alias_datum = hashtab_search(pdb->p_types.table, alias_name);
+ if (alias_datum == NULL) {
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(indent, "(typealias %s)", alias_name);
+ cil_println(indent, "(typealiasactual %s %s)", alias_name, pdb->p_type_val_to_name[alias_datum->s.value - 1]);
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int declared_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+ int rc = -1;
+ struct ebitmap map;
+ struct ebitmap_node *node;
+ unsigned int i;
+ char * key;
+ struct scope_datum *scope;
+ int sym;
+ void *datum;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+
+ for (sym = 0; sym < SYM_NUM; sym++) {
+ if (func_to_cil[sym] == NULL) {
+ continue;
+ }
+
+ map = decl->declared.scope[sym];
+ ebitmap_for_each_bit(&map, node, i) {
+ if (!ebitmap_get_bit(&map, i)) {
+ continue;
+ }
+ key = pdb->sym_val_to_name[sym][i];
+ datum = hashtab_search(pdb->symtab[sym].table, key);
+ if (datum == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ scope = hashtab_search(pdb->scope[sym].table, key);
+ if (scope == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, scope->scope);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (sym == SYM_CATS) {
+ rc = cat_order_to_cil(indent, pdb, map);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (sym == SYM_LEVELS) {
+ rc = sens_order_to_cil(indent, pdb, map);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (sym == SYM_CLASSES) {
+ rc = class_order_to_cil(indent, pdb, map);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+static int required_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+ int rc = -1;
+ struct ebitmap map;
+ struct ebitmap_node *node;
+ unsigned int i;
+ unsigned int j;
+ char * key;
+ int sym;
+ void *datum;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+ struct scope_datum *scope_datum;
+
+ for (sym = 0; sym < SYM_NUM; sym++) {
+ if (func_to_cil[sym] == NULL) {
+ continue;
+ }
+
+ map = decl->required.scope[sym];
+ ebitmap_for_each_bit(&map, node, i) {
+ if (!ebitmap_get_bit(&map, i)) {
+ continue;
+ }
+ key = pdb->sym_val_to_name[sym][i];
+
+ scope_datum = hashtab_search(pdb->scope[sym].table, key);
+ for (j = 0; j < scope_datum->decl_ids_len; j++) {
+ if (scope_datum->decl_ids[j] == decl->decl_id) {
+ break;
+ }
+ }
+ if (j >= scope_datum->decl_ids_len) {
+ // Symbols required in the global scope are also in the
+ // required scope ebitmap of all avrule decls (i.e. required
+ // in all optionals). So we need to look at the scopes of each
+ // symbol in this avrule_decl to determine if it actually is
+ // required in this decl, or if it's just required in the
+ // global scope. If we got here, then this symbol is not
+ // actually required in this scope, so skip it.
+ continue;
+ }
+
+ datum = hashtab_search(pdb->symtab[sym].table, key);
+ if (datum == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, SCOPE_REQ);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+
+static int additive_scopes_to_cil_map(char *key, void *data, void *arg)
+{
+ int rc = -1;
+ struct map_args *args = arg;
+
+ rc = func_to_cil[args->sym_index](args->indent, args->pdb, args->block, args->decl_stack, key, data, SCOPE_REQ);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+ int rc = -1;
+ struct map_args args;
+ args.pdb = pdb;
+ args.block = block;
+ args.decl_stack = decl_stack;
+ args.indent = indent;
+ struct avrule_decl *decl = stack_peek(decl_stack);
+
+ for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) {
+ rc = hashtab_map(decl->symtab[args.sym_index].table, additive_scopes_to_cil_map, &args);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int is_scope_superset(struct scope_index *sup, struct scope_index *sub)
+{
+ // returns 1 if sup is a superset of sub, returns 0 otherwise
+
+ int rc = 0;
+
+ uint32_t i;
+ struct ebitmap sup_map;
+ struct ebitmap sub_map;
+ struct ebitmap res;
+
+ ebitmap_init(&res);
+
+ for (i = 0; i < SYM_NUM; i++) {
+ sup_map = sup->scope[i];
+ sub_map = sub->scope[i];
+
+ ebitmap_and(&res, &sup_map, &sub_map);
+ if (!ebitmap_cmp(&res, &sub_map)) {
+ goto exit;
+ }
+ ebitmap_destroy(&res);
+ }
+
+ if (sup->class_perms_len < sub->class_perms_len) {
+ goto exit;
+ }
+
+ for (i = 0; i < sub->class_perms_len; i++) {
+ sup_map = sup->class_perms_map[i];
+ sub_map = sub->class_perms_map[i];
+
+ ebitmap_and(&res, &sup_map, &sub_map);
+ if (!ebitmap_cmp(&res, &sub_map)) {
+ goto exit;
+ }
+ ebitmap_destroy(&res);
+ }
+
+ rc = 1;
+
+exit:
+
+ ebitmap_destroy(&res);
+ return rc;
+}
+
+static int blocks_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ struct avrule_block *block;
+ struct avrule_decl *decl;
+ struct avrule_decl *decl_tmp;
+ int indent = 0;
+ struct stack *stack;
+ struct list *attr_list;
+
+ rc = stack_init(&stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ for (block = pdb->global; block != NULL; block = block->next) {
+ rc = list_init(&attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ decl = block->branch_list;
+ if (decl == NULL) {
+ continue;
+ }
+
+ if (decl->next != NULL) {
+ log_err("Warning: 'else' blocks in optional statements are unsupported in CIL. Dropping from output.");
+ }
+
+ if (block->flags & AVRULE_OPTIONAL) {
+ while (stack->pos > 0) {
+ decl_tmp = stack_peek(stack);
+ if (is_scope_superset(&decl->required, &decl_tmp->required)) {
+ break;
+ }
+
+ stack_pop(stack);
+ indent--;
+ cil_println(indent, ")");
+ }
+
+ cil_println(indent, "(optional %s_optional_%i", pdb->name, decl->decl_id);
+ indent++;
+ }
+
+ stack_push(stack, decl);
+
+ if (stack->pos == 0) {
+ // type aliases and commons are only stored in the global symtab.
+ // However, to get scoping correct, we assume they are in the
+ // global block
+ struct map_args args;
+ args.pdb = pdb;
+ args.block = block;
+ args.decl_stack = stack;
+ args.indent = 0;
+ args.scope = SCOPE_DECL;
+
+ rc = hashtab_map(pdb->p_commons.table, common_to_cil, &args);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ rc = typealiases_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = declared_scopes_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = required_scopes_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = additive_scopes_to_cil(indent, pdb, block, stack);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = avrule_list_to_cil(indent, pdb, decl->avrules, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = role_trans_to_cil(indent, pdb, decl->role_tr_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = role_allows_to_cil(indent, pdb, decl->role_allow_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = range_trans_to_cil(indent, pdb, decl->range_tr_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = cond_list_to_cil(indent, pdb, decl->cond_list);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = cil_print_attr_list(indent, pdb, attr_list);
+ if (rc != 0) {
+ goto exit;
+ }
+ attr_list_destroy(&attr_list);
+ }
+
+ while (indent > 0) {
+ indent--;
+ cil_println(indent, ")");
+ }
+
+ rc = 0;
+
+exit:
+ stack_destroy(&stack);
+ attr_list_destroy(&attr_list);
+
+ return rc;
+}
+
+static int handle_unknown_to_cil(struct policydb *pdb)
+{
+ int rc = -1;
+ const char *hu;
+
+ switch (pdb->handle_unknown) {
+ case SEPOL_DENY_UNKNOWN:
+ hu = "deny";
+ break;
+ case SEPOL_REJECT_UNKNOWN:
+ hu = "reject";
+ break;
+ case SEPOL_ALLOW_UNKNOWN:
+ hu = "allow";
+ break;
+ default:
+ log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
+ rc = -1;
+ goto exit;
+ }
+
+ cil_println(0, "(handleunknown %s)", hu);
+
+ return 0;
+
+exit:
+ return rc;
+}
+
+static int generate_mls(struct policydb *pdb)
+{
+ const char *mls_str = pdb->mls ? "true" : "false";
+ cil_println(0, "(mls %s)", mls_str);
+
+ return 0;
+}
+
+static int generate_default_level(void)
+{
+ cil_println(0, "(sensitivity s0)");
+ cil_println(0, "(sensitivityorder (s0))");
+ cil_println(0, "(level " DEFAULT_LEVEL " (s0))");
+
+ return 0;
+}
+
+static int generate_default_object(void)
+{
+ cil_println(0, "(role " DEFAULT_OBJECT ")");
+
+ return 0;
+}
+
+static int generate_gen_require_attribute(void)
+{
+ cil_println(0, "(typeattribute " GEN_REQUIRE_ATTR ")");
+ cil_println(0, "(roleattribute " GEN_REQUIRE_ATTR ")");
+
+ return 0;
+}
+
+static int fix_module_name(struct policydb *pdb)
+{
+ char *letter;
+ int rc = -1;
+
+ // The base module doesn't have its name set, but we use that for some
+ // autogenerated names, like optionals and attributes, to prevent naming
+ // collisions. However, they sometimes need to be fixed up.
+
+ // the base module isn't given a name, so just call it "base"
+ if (pdb->policy_type == POLICY_BASE) {
+ pdb->name = strdup("base");
+ if (pdb->name == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ }
+
+ // CIL is more restrictive in module names than checkmodule. Convert bad
+ // characters to underscores
+ for (letter = pdb->name; *letter != '\0'; letter++) {
+ if (isalnum(*letter)) {
+ continue;
+ }
+
+ *letter = '_';
+ }
+
+ return 0;
+exit:
+ return rc;
+}
+
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg)
+{
+ int rc = -1;
+ struct sepol_policydb *pdb;
+
+ out_file = fp;
+
+ pdb = sepol_module_package_get_policy(mod_pkg);
+ if (pdb == NULL) {
+ log_err("Failed to get policydb");
+ rc = -1;
+ goto exit;
+ }
+
+ if (pdb->p.policy_type != SEPOL_POLICY_BASE &&
+ pdb->p.policy_type != SEPOL_POLICY_MOD) {
+ log_err("Policy pakcage is not a base or module");
+ rc = -1;
+ goto exit;
+ }
+
+ rc = fix_module_name(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ if (pdb->p.policy_type == SEPOL_POLICY_BASE && !pdb->p.mls) {
+ // If this is a base non-mls policy, we need to define a default level
+ // range that can be used for contexts by other non-mls modules, since
+ // CIL requires that all contexts have a range, even if they are
+ // ignored as in non-mls policies
+ rc = generate_default_level();
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ if (pdb->p.policy_type == SEPOL_POLICY_BASE) {
+ // object_r is implicit in checkmodule, but not with CIL, create it
+ // as part of base
+ rc = generate_default_object();
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // default attribute to be used to mimic gen_require in CIL
+ rc = generate_gen_require_attribute();
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // handle_unknown is used from only the base module
+ rc = handle_unknown_to_cil(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // mls is used from only the base module
+ rc = generate_mls(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+ }
+
+ rc = role_list_create(pdb->p.p_roles.table);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = typealias_list_create(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = polcaps_to_cil(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = ocontexts_to_cil(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = genfscon_to_cil(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = seusers_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = netfilter_contexts_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = user_extra_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = file_contexts_to_cil(mod_pkg);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ // now print everything that is scoped
+ rc = blocks_to_cil(&pdb->p);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ rc = 0;
+
+exit:
+ role_list_destroy();
+ typealias_list_destroy();
+
+ return rc;
+}
+
+static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
+{
+ int rc = -1;
+ char *d = NULL;
+ size_t d_len = 0;
+ size_t read_len = 0;
+ size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
+
+ d = malloc(max_len);
+ if (d == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+
+ while ((read_len = fread(d + d_len, 1, max_len - d_len, fp)) > 0) {
+ d_len += read_len;
+ if (d_len == max_len) {
+ max_len *= 2;
+ d = realloc(d, max_len);
+ if (d == NULL) {
+ log_err("Out of memory");
+ rc = -1;
+ goto exit;
+ }
+ }
+ }
+
+ if (ferror(fp) != 0) {
+ log_err("Failed to read pp file");
+ rc = -1;
+ goto exit;
+ }
+
+ *data = d;
+ *data_len = d_len;
+
+ return 0;
+
+exit:
+ free(d);
+ return rc;
+}
+
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
+{
+ int rc = -1;
+ FILE *f = NULL;
+ struct sepol_policy_file *pf = NULL;
+ struct sepol_module_package *pkg = NULL;
+ char *data = NULL;
+ size_t data_len;
+ int fd;
+ struct stat sb;
+
+ rc = sepol_policy_file_create(&pf);
+ if (rc != 0) {
+ log_err("Failed to create policy file");
+ goto exit;
+ }
+
+ fd = fileno(fp);
+ if (fstat(fd, &sb) == -1) {
+ rc = -1;
+ goto exit;
+ }
+
+ if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
+ // libsepol fails when trying to read a policy package from a pipe or a
+ // socket due its use of lseek. In this case, read the data into a
+ // buffer and provide that to libsepol
+ rc = fp_to_buffer(fp, &data, &data_len);
+ if (rc != 0) {
+ goto exit;
+ }
+
+ sepol_policy_file_set_mem(pf, data, data_len);
+ } else {
+ sepol_policy_file_set_fp(pf, fp);
+ }
+
+ rc = sepol_module_package_create(&pkg);
+ if (rc != 0) {
+ log_err("Failed to create module package");
+ goto exit;
+ }
+
+ rc = sepol_module_package_read(pkg, pf, 0);
+ if (rc != 0) {
+ log_err("Failed to read policy package");
+ goto exit;
+ }
+
+ *mod_pkg = pkg;
+
+exit:
+ free(data);
+
+ sepol_policy_file_free(pf);
+ if (f != NULL) {
+ fclose(f);
+ }
+
+ if (rc != 0) {
+ sepol_module_package_free(pkg);
+ }
+
+ return rc;
+}
diff --git a/policycoreutils/hll/pp/pp.c b/policycoreutils/hll/pp/pp.c
index 60c493d..866734f 100644
--- a/policycoreutils/hll/pp/pp.c
+++ b/policycoreutils/hll/pp/pp.c
@@ -17,43 +17,19 @@
* 02110-1301, USA.
*/
-#include <arpa/inet.h>
-#include <ctype.h>
#include <errno.h>
-#include <fcntl.h>
#include <getopt.h>
#include <libgen.h>
-#include <netinet/in.h>
#include <signal.h>
#include <stdarg.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
#include <sepol/module.h>
-#include <sepol/policydb/conditional.h>
-#include <sepol/policydb/hashtab.h>
-#include <sepol/policydb/polcaps.h>
-#include <sepol/policydb/policydb.h>
-#include <sepol/policydb/services.h>
-#include <sepol/policydb/util.h>
-
-#ifdef __GNUC__
-# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
-#else
-# define UNUSED(x) UNUSED_ ## x
-#endif
+#include <sepol/module_to_cil.h>
char *progname;
-FILE *out_file;
-
-#define STACK_SIZE 16
-#define DEFAULT_LEVEL "systemlow"
-#define DEFAULT_OBJECT "object_r"
-#define GEN_REQUIRE_ATTR "cil_gen_require"
__attribute__ ((format(printf, 1, 2)))
static void log_err(const char *fmt, ...)
@@ -69,3805 +45,6 @@ static void log_err(const char *fmt, ...)
}
}
-static void cil_indent(int indent)
-{
- if (fprintf(out_file, "%*s", indent * 4, "") < 0) {
- log_err("Failed to write to output");
- _exit(EXIT_FAILURE);
- }
-}
-
-__attribute__ ((format(printf, 1, 2)))
-static void cil_printf(const char *fmt, ...) {
- va_list argptr;
- va_start(argptr, fmt);
- if (vfprintf(out_file, fmt, argptr) < 0) {
- log_err("Failed to write to output");
- _exit(EXIT_FAILURE);
- }
- va_end(argptr);
-}
-
-__attribute__ ((format(printf, 2, 3)))
-static void cil_println(int indent, const char *fmt, ...)
-{
- cil_indent(indent);
- va_list argptr;
- va_start(argptr, fmt);
- if (vfprintf(out_file, fmt, argptr) < 0) {
- log_err("Failed to write to output");
- _exit(EXIT_FAILURE);
- }
- va_end(argptr);
- if (fprintf(out_file, "\n") < 0) {
- log_err("Failed to write to output");
- _exit(EXIT_FAILURE);
- }
-}
-
-struct map_args {
- struct policydb *pdb;
- struct avrule_block *block;
- struct stack *decl_stack;
- int scope;
- int indent;
- int sym_index;
-};
-
-struct stack {
- void **stack;
- int pos;
- int size;
-};
-
-struct role_list_node {
- char *role_name;
- role_datum_t *role;
-};
-
-struct attr_list_node {
- char *attribute;
- int is_type;
- union {
- struct type_set *ts;
- struct role_set *rs;
- } set;
-};
-
-struct list_node {
- void *data;
- struct list_node *next;
-};
-
-struct list {
- struct list_node *head;
-};
-
-/* A linked list of all roles stored in the pdb
- * which is iterated to determine types associated
- * with each role when printing role_type statements
- */
-static struct list *role_list;
-
-static void list_destroy(struct list **list)
-{
- struct list_node *curr = (*list)->head;
- struct list_node *tmp;
-
- while (curr != NULL) {
- tmp = curr->next;
- free(curr);
- curr = tmp;
- }
-
- free(*list);
- *list = NULL;
-}
-
-static void role_list_destroy(void)
-{
- struct list_node *curr = role_list->head;
-
- while (curr != NULL) {
- free(curr->data);
- curr->data = NULL;
- curr = curr->next;
- }
-
- list_destroy(&role_list);
-}
-
-static void attr_list_destroy(struct list **attr_list)
-{
- if (attr_list == NULL || *attr_list == NULL) {
- return;
- }
-
- struct list_node *curr = (*attr_list)->head;
- struct attr_list_node *attr;
-
- while (curr != NULL) {
- attr = curr->data;
- if (attr != NULL) {
- free(attr->attribute);
- }
-
- free(curr->data);
- curr->data = NULL;
- curr = curr->next;
- }
-
- list_destroy(attr_list);
-}
-
-static int list_init(struct list **list)
-{
- int rc = -1;
- struct list *l = calloc(1, sizeof(*l));
- if (l == NULL) {
- goto exit;
- }
-
- *list = l;
-
- return 0;
-
-exit:
- list_destroy(&l);
- return rc;
-}
-
-static int list_prepend(struct list *list, void *data)
-{
- int rc = -1;
- struct list_node *node = calloc(1, sizeof(*node));
- if (node == NULL) {
- goto exit;
- }
-
- node->data = data;
- node->next = list->head;
- list->head = node;
-
- rc = 0;
-
-exit:
- return rc;
-}
-
-static int roles_gather_map(char *key, void *data, void *args)
-{
- struct role_list_node *role_node;
- role_datum_t *role = data;
- int rc = -1;
-
- role_node = calloc(1, sizeof(*role_node));
- if (role_node == NULL) {
- return rc;
- }
-
- role_node->role_name = key;
- role_node->role = role;
-
- rc = list_prepend((struct list *)args, role_node);
- return rc;
-}
-
-static int role_list_create(hashtab_t roles_tab)
-{
- int rc = -1;
-
- rc = list_init(&role_list);
- if (rc != 0) {
- goto exit;
- }
-
- rc = hashtab_map(roles_tab, roles_gather_map, role_list);
-
-exit:
- return rc;
-}
-
-// array of lists, where each list contains all the aliases defined in the scope at index i
-static struct list **typealias_lists;
-static uint32_t typealias_lists_len;
-
-static int typealiases_gather_map(char *key, void *data, void *arg)
-{
- int rc = -1;
- struct type_datum *type = data;
- struct policydb *pdb = arg;
- struct scope_datum *scope;
- uint32_t i;
- uint32_t scope_id;
-
- if (type->primary != 1) {
- scope = hashtab_search(pdb->scope[SYM_TYPES].table, key);
- if (scope == NULL) {
- return -1;
- }
-
- for (i = 0; i < scope->decl_ids_len; i++) {
- scope_id = scope->decl_ids[i];
- if (typealias_lists[scope_id] == NULL) {
- rc = list_init(&typealias_lists[scope_id]);
- if (rc != 0) {
- goto exit;
- }
- }
- list_prepend(typealias_lists[scope_id], key);
- }
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static void typealias_list_destroy(void)
-{
- uint32_t i;
- for (i = 0; i < typealias_lists_len; i++) {
- if (typealias_lists[i] != NULL) {
- list_destroy(&typealias_lists[i]);
- }
- }
- typealias_lists_len = 0;
- free(typealias_lists);
- typealias_lists = NULL;
-}
-
-static int typealias_list_create(struct policydb *pdb)
-{
- uint32_t max_decl_id = 0;
- struct avrule_decl *decl;
- struct avrule_block *block;
- uint32_t rc = -1;
-
- for (block = pdb->global; block != NULL; block = block->next) {
- decl = block->branch_list;
- if (decl->decl_id > max_decl_id) {
- max_decl_id = decl->decl_id;
- }
- }
-
- typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists));
- typealias_lists_len = max_decl_id + 1;
-
- rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb);
- if (rc != 0) {
- goto exit;
- }
-
- return 0;
-
-exit:
- typealias_list_destroy();
-
- return rc;
-}
-
-
-static int stack_destroy(struct stack **stack)
-{
- if (stack == NULL || *stack == NULL) {
- return 0;
- }
-
- free((*stack)->stack);
- free(*stack);
- *stack = NULL;
-
- return 0;
-}
-
-static int stack_init(struct stack **stack)
-{
- int rc = -1;
- struct stack *s = calloc(1, sizeof(*s));
- if (s == NULL) {
- goto exit;
- }
-
- s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
- if (s->stack == NULL) {
- goto exit;
- }
-
- s->pos = -1;
- s->size = STACK_SIZE;
-
- *stack = s;
-
- return 0;
-
-exit:
- stack_destroy(&s);
- return rc;
-}
-
-static int stack_push(struct stack *stack, void *ptr)
-{
- int rc = -1;
- void *new_stack;
-
- if (stack->pos + 1 == stack->size) {
- new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
- if (new_stack == NULL) {
- goto exit;
- }
- stack->stack = new_stack;
- stack->size *= 2;
- }
-
- stack->pos++;
- stack->stack[stack->pos] = ptr;
-
- rc = 0;
-exit:
- return rc;
-}
-
-static void *stack_pop(struct stack *stack)
-{
- if (stack->pos == -1) {
- return NULL;
- }
-
- stack->pos--;
- return stack->stack[stack->pos + 1];
-}
-
-static void *stack_peek(struct stack *stack)
-{
- if (stack->pos == -1) {
- return NULL;
- }
-
- return stack->stack[stack->pos];
-}
-
-static int is_id_in_scope_with_start(struct policydb *pdb, struct stack *decl_stack, int start, uint32_t symbol_type, char *id)
-{
- int i;
- uint32_t j;
- struct avrule_decl *decl;
- struct scope_datum *scope;
-
- scope = hashtab_search(pdb->scope[symbol_type].table, id);
- if (scope == NULL) {
- return 0;
- }
-
- for (i = start; i >= 0; i--) {
- decl = decl_stack->stack[i];
-
- for (j = 0; j < scope->decl_ids_len; j++) {
- if (scope->decl_ids[j] == decl->decl_id) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static int is_id_in_ancestor_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
-{
- int start = decl_stack->pos - 1;
-
- return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
-}
-
-static int is_id_in_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
-{
- int start = decl_stack->pos;
-
- return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
-}
-
-static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct mls_semantic_level *level)
-{
- struct mls_semantic_cat *cat;
-
- cil_printf("(%s ", pdb->p_sens_val_to_name[level->sens - sens_offset]);
-
- if (level->cat != NULL) {
- cil_printf("(");
- }
-
- for (cat = level->cat; cat != NULL; cat = cat->next) {
- if (cat->low == cat->high) {
- cil_printf("%s", pdb->p_cat_val_to_name[cat->low - 1]);
- } else {
- cil_printf("range %s %s", pdb->p_cat_val_to_name[cat->low - 1], pdb->p_cat_val_to_name[cat->high - 1]);
- }
-
- if (cat->next != NULL) {
- cil_printf(" ");
- }
- }
-
- if (level->cat != NULL) {
- cil_printf(")");
- }
-
- cil_printf(")");
-
- return 0;
-}
-
-static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms)
-{
- int rc = -1;
- const char *rule;
- const struct class_perm_node *classperm;
- char *perms;
-
- switch (type) {
- case AVRULE_ALLOWED:
- rule = "allow";
- break;
- case AVRULE_AUDITALLOW:
- rule = "auditallow";
- break;
- case AVRULE_AUDITDENY:
- rule = "auditdenty";
- break;
- case AVRULE_DONTAUDIT:
- rule = "dontaudit";
- break;
- case AVRULE_NEVERALLOW:
- rule = "neverallow";
- break;
- case AVRULE_TRANSITION:
- rule = "typetransition";
- break;
- case AVRULE_MEMBER:
- rule = "typemember";
- break;
- case AVRULE_CHANGE:
- rule = "typechange";
- break;
- default:
- log_err("Unknown avrule type: %i", type);
- rc = -1;
- goto exit;
- }
-
- for (classperm = classperms; classperm != NULL; classperm = classperm->next) {
- if (type & AVRULE_AV) {
- perms = sepol_av_to_string(pdb, classperm->tclass, classperm->data);
- if (perms == NULL) {
- log_err("Failed to generate permission string");
- rc = -1;
- goto exit;
- }
- cil_println(indent, "(%s %s %s (%s (%s)))",
- rule, src, tgt,
- pdb->p_class_val_to_name[classperm->tclass - 1],
- perms + 1);
- } else {
- cil_println(indent, "(%s %s %s %s %s)",
- rule, src, tgt,
- pdb->p_class_val_to_name[classperm->tclass - 1],
- pdb->p_type_val_to_name[classperm->data - 1]);
- }
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int num_digits(int n)
-{
- int num = 1;
- while (n >= 10) {
- n /= 10;
- num++;
- }
- return num;
-}
-
-static int set_to_cil_attr(struct policydb *pdb, int is_type, char ***names, uint32_t *num_names)
-{
- static unsigned int num_attrs = 0;
- int rc = -1;
- int len, rlen;
- const char *attr_infix;
- char *attr;
-
- num_attrs++;
-
- if (is_type) {
- attr_infix = "_typeattr_";
- } else {
- attr_infix = "_roleattr_";
- }
-
- len = strlen(pdb->name) + strlen(attr_infix) + num_digits(num_attrs) + 1;
- attr = malloc(len);
- if (attr == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- rlen = snprintf(attr, len, "%s%s%i", pdb->name, attr_infix, num_attrs);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate attribute name");
- rc = -1;
- goto exit;
- }
-
- *names = malloc(sizeof(**names));
- if (*names == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
-
- *names[0] = attr;
- *num_names = 1;
-
- rc = 0;
-
-exit:
- return rc;
-}
-
-static int cil_print_attr_strs(int indent, struct policydb *pdb, int is_type, struct ebitmap *pos, struct ebitmap *neg, uint32_t flags, char *attr)
-{
- // CIL doesn't support anonymous positive/negative/complemented sets. So
- // instead we create a CIL type/roleattributeset that matches the set. If
- // the set has a negative set, then convert it to is (P & !N), where P is
- // the list of members in the positive set , and N is the list of members
- // in the negative set. Additonally, if the set is complemented, then wrap
- // the whole thing with a negation.
-
- int rc = 0;
- struct ebitmap_node *node;
- unsigned int i;
- char *statement;
- int has_positive = pos && (ebitmap_cardinality(pos) > 0);
- int has_negative = neg && (ebitmap_cardinality(neg) > 0);
- char **val_to_name;
-
- if (is_type) {
- statement = "type";
- val_to_name = pdb->p_type_val_to_name;
- } else {
- statement = "role";
- val_to_name = pdb->p_role_val_to_name;
- }
-
- cil_println(indent, "(%sattribute %s)", statement, attr);
- cil_indent(indent);
- cil_printf("(%sattributeset %s ", statement, attr);
-
- if (flags & TYPE_STAR) {
- cil_printf("(all)");
- }
-
- if (flags & TYPE_COMP) {
- cil_printf("(not ");
- }
-
- if (has_positive && has_negative) {
- cil_printf("(and ");
- }
-
- if (has_positive) {
- cil_printf("(");
- ebitmap_for_each_bit(pos, node, i) {
- if (!ebitmap_get_bit(pos, i)) {
- continue;
- }
- cil_printf("%s ", val_to_name[i]);
- }
- cil_printf(") ");
- }
-
- if (has_negative) {
- cil_printf("(not (");
-
- ebitmap_for_each_bit(neg, node, i) {
- if (!ebitmap_get_bit(neg, i)) {
- continue;
- }
- cil_printf("%s ", val_to_name[i]);
- }
-
- cil_printf("))");
- }
-
- if (has_positive && has_negative) {
- cil_printf(")");
- }
-
- if (flags & TYPE_COMP) {
- cil_printf(")");
- }
-
- cil_printf(")\n");
-
- return rc;
-}
-
-static int ebitmap_to_cil(struct policydb *pdb, struct ebitmap *map, int type)
-{
- struct ebitmap_node *node;
- uint32_t i;
- char **val_to_name = pdb->sym_val_to_name[type];
-
- ebitmap_for_each_bit(map, node, i) {
- if (!ebitmap_get_bit(map, i)) {
- continue;
- }
- cil_printf("%s ", val_to_name[i]);
- }
-
- return 0;
-}
-
-static int ebitmap_to_names(char** vals_to_names, struct ebitmap map, char ***names, uint32_t *num_names)
-{
- int rc = -1;
- struct ebitmap_node *node;
- uint32_t i;
- uint32_t num = 0;
- uint32_t max = 8;
- char **name_arr = NULL;
-
- name_arr = malloc(sizeof(*name_arr) * max);
- if (name_arr == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- ebitmap_for_each_bit(&map, node, i) {
- if (!ebitmap_get_bit(&map, i)) {
- continue;
- }
-
- if (num + 1 == max) {
- max *= 2;
- name_arr = realloc(name_arr, sizeof(*name_arr) * max);
- if (name_arr == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- }
-
- name_arr[num] = strdup(vals_to_names[i]);
- if (name_arr[num] == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- num++;
- }
-
- *names = name_arr;
- *num_names = num;
-
- return 0;
-
-exit:
- for (i = 0; i < num; i++) {
- free(name_arr[i]);
- }
- free(name_arr);
- return rc;
-}
-
-static int cil_add_attr_to_list(struct list *attr_list, char *attribute, int is_type, void *set)
-{
- struct attr_list_node *attr_list_node = NULL;
- int rc = -1;
-
- attr_list_node = calloc(1, sizeof(*attr_list_node));
- if (attr_list_node == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- rc = list_prepend(attr_list, attr_list_node);
- if (rc != 0) {
- goto exit;
- }
-
- attr_list_node->attribute = strdup(attribute);
- if (attr_list_node->attribute == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- attr_list_node->is_type = is_type;
- if (is_type) {
- attr_list_node->set.ts = set;
- } else {
- attr_list_node->set.rs = set;
- }
-
- return rc;
-
-exit:
- if (attr_list_node != NULL) {
- free(attr_list_node->attribute);
- }
- free(attr_list_node);
- return rc;
-}
-
-/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
-static int typeset_to_names(struct policydb *pdb, struct type_set *ts, char ***names, uint32_t *num_names, char **generated_attribute)
-{
- int rc = -1;
- if (ebitmap_cardinality(&ts->negset) > 0 || ts->flags != 0) {
- rc = set_to_cil_attr(pdb, 1, names, num_names);
- if (rc != 0) {
- goto exit;
- }
-
- *generated_attribute = *names[0];
- } else {
- rc = ebitmap_to_names(pdb->p_type_val_to_name, ts->types, names, num_names);
- if (rc != 0) {
- goto exit;
- }
- }
-
- return 0;
-exit:
- return rc;
-}
-
-/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
-static int roleset_to_names(struct policydb *pdb, struct role_set *rs, char ***names, uint32_t *num_names, char **generated_attribute)
-{
- int rc = -1;
- if (rs->flags != 0) {
- rc = set_to_cil_attr(pdb, 0, names, num_names);
- if (rc != 0) {
- goto exit;
- }
-
- *generated_attribute = *names[0];
- } else {
- rc = ebitmap_to_names(pdb->p_role_val_to_name, rs->roles, names, num_names);
- if (rc != 0) {
- goto exit;
- }
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int process_roleset(int indent, struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
-{
- int rc = -1;
- char *generated_attribute = NULL;
- *num_type_names = 0;
-
- rc = roleset_to_names(pdb, rs, type_names, num_type_names, &generated_attribute);
- if (rc != 0) {
- goto exit;
- }
-
- if (generated_attribute == NULL) {
- goto exit;
- }
-
- if (attr_list == NULL) {
- rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
- if (rc != 0) {
- goto exit;
- }
- } else {
- rc = cil_add_attr_to_list(attr_list, generated_attribute, 0, rs);
- if (rc != 0) {
- goto exit;
- }
- }
-
-exit:
- return rc;
-}
-
-static int process_typeset(int indent, struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
-{
- int rc = -1;
- char *generated_attribute = NULL;
- *num_type_names = 0;
-
- rc = typeset_to_names(pdb, ts, type_names, num_type_names, &generated_attribute);
- if (rc != 0) {
- goto exit;
- }
-
- if (generated_attribute == NULL) {
- rc = 0;
- goto exit;
- }
-
- if (attr_list == NULL) {
- rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
- if (rc != 0) {
- goto exit;
- }
- } else {
- rc = cil_add_attr_to_list(attr_list, generated_attribute, 1, ts);
- if (rc != 0) {
- goto exit;
- }
- }
-
-exit:
- return rc;
-}
-
-static void names_destroy(char ***names, uint32_t *num_names)
-{
- char **arr = *names;
- uint32_t num = *num_names;
- uint32_t i;
-
- for (i = 0; i < num; i++) {
- free(arr[i]);
- arr[i] = NULL;
- }
- free(arr);
-
- *names = NULL;
- *num_names = 0;
-}
-
-static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *decl_stack, char *type_name, int indent)
-{
- struct list_node *curr;
- char **tnames = NULL;
- uint32_t num_tnames, i;
- struct role_list_node *role_node = NULL;
- int rc;
- struct type_set *ts;
-
- curr = role_list->head;
- for (curr = role_list->head; curr != NULL; curr = curr->next) {
- role_node = curr->data;
- if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
- continue;
- }
-
- ts = &role_node->role->types;
- rc = process_typeset(indent, pdb, ts, NULL, &tnames, &num_tnames);
- if (rc != 0) {
- goto exit;
- }
- for (i = 0; i < num_tnames; i++) {
- if (!strcmp(type_name, tnames[i])) {
- cil_println(indent, "(roletype %s %s)", role_node->role_name, type_name);
- }
- }
- names_destroy(&tnames, &num_tnames);
- }
-
- rc = 0;
-
-exit:
- return rc;
-}
-
-
-static int name_list_to_string(char **names, int num_names, char **string)
-{
- // create a space separated string of the names
- int rc = -1;
- int len = 0;
- int i;
- char *str;
- char *strpos;
- int name_len;
- int rlen;
-
- for (i = 0; i < num_names; i++) {
- len += strlen(names[i]);
- }
-
- // add spaces + null terminator
- len += (num_names - 1) + 1;
-
- str = malloc(len);
- if (str == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- strpos = str;
-
- for (i = 0; i < num_names; i++) {
- name_len = strlen(names[i]);
- rlen = snprintf(strpos, len - (strpos - str), "%s", names[i]);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate name list");
- rc = -1;
- goto exit;
- }
-
- if (i < num_names - 1) {
- strpos[name_len] = ' ';
- }
- strpos += name_len + 1;
- }
-
- *string = str;
-
- return 0;
-exit:
- return rc;
-}
-
-static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *avrule_list, struct list *attr_list)
-{
- int rc = -1;
- struct avrule *avrule;
- char **snames = NULL;
- char **tnames = NULL;
- uint32_t num_snames;
- uint32_t num_tnames;
- uint32_t s;
- uint32_t t;
- struct type_set *ts;
-
- for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) {
- ts = &avrule->stypes;
- rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames);
- if (rc != 0) {
- goto exit;
- }
-
- ts = &avrule->ttypes;
- rc = process_typeset(indent, pdb, ts, attr_list, &tnames, &num_tnames);
- if (rc != 0) {
- goto exit;
- }
-
- for (s = 0; s < num_snames; s++) {
- for (t = 0; t < num_tnames; t++) {
- rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms);
- if (rc != 0) {
- goto exit;
- }
- }
-
- if (avrule->flags & RULE_SELF) {
- rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms);
- if (rc != 0) {
- goto exit;
- }
- }
- }
-
- names_destroy(&snames, &num_snames);
- names_destroy(&tnames, &num_tnames);
- }
-
- return 0;
-
-exit:
- names_destroy(&snames, &num_snames);
- names_destroy(&tnames, &num_tnames);
-
- return rc;
-}
-
-static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *cond_expr, uint32_t flags)
-{
- int rc = -1;
- struct cond_expr *curr;
- struct stack *stack = NULL;
- int len = 0;
- int rlen;
- char *new_val = NULL;
- char *val1 = NULL;
- char *val2 = NULL;
- int num_params;
- const char *op;
- const char *fmt_str;
- const char *type;
-
- rc = stack_init(&stack);
- if (rc != 0) {
- log_err("Out of memory");
- goto exit;
- }
-
- for (curr = cond_expr; curr != NULL; curr = curr->next) {
- if (curr->expr_type == COND_BOOL) {
- val1 = pdb->p_bool_val_to_name[curr->bool - 1];
- // length of boolean + 2 parens + null terminator
- len = strlen(val1) + 2 + 1;
- new_val = malloc(len);
- if (new_val == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- rlen = snprintf(new_val, len, "(%s)", val1);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate conditional expression");
- rc = -1;
- goto exit;
- }
- num_params = 0;
- } else {
- switch(curr->expr_type) {
- case COND_NOT: op = "not"; break;
- case COND_OR: op = "or"; break;
- case COND_AND: op = "and"; break;
- case COND_XOR: op = "xor"; break;
- case COND_EQ: op = "eq"; break;
- case COND_NEQ: op = "neq"; break;
- default:
- rc = -1;
- goto exit;
- }
-
- num_params = curr->expr_type == COND_NOT ? 1 : 2;
-
- if (num_params == 1) {
- val1 = stack_pop(stack);
- val2 = strdup("");
- if (val2 == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- fmt_str = "(%s %s)";
- } else {
- val2 = stack_pop(stack);
- val1 = stack_pop(stack);
- fmt_str = "(%s %s %s)";
- }
-
- if (val1 == NULL || val2 == NULL) {
- log_err("Invalid conditional expression");
- rc = -1;
- goto exit;
- }
-
- // length = length of parameters +
- // length of operator +
- // 1 space preceeding each parameter +
- // 2 parens around the whole expression
- // + null terminator
- len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
- new_val = malloc(len);
- if (new_val == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- // although we always supply val2 and there isn't always a 2nd
- // value, it should only be used when there are actually two values
- // in the format strings
- rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate conditional expression");
- rc = -1;
- goto exit;
- }
-
- free(val1);
- free(val2);
- val1 = NULL;
- val2 = NULL;
- }
-
- rc = stack_push(stack, new_val);
- if (rc != 0) {
- log_err("Out of memory");
- goto exit;
- }
- new_val = NULL;
- }
-
- if (flags & COND_NODE_FLAGS_TUNABLE) {
- type = "tunableif";
- } else {
- type = "booleanif";
- }
-
- val1 = stack_pop(stack);
- if (val1 == NULL || stack_peek(stack) != NULL) {
- log_err("Invalid conditional expression");
- rc = -1;
- goto exit;
- }
-
- cil_println(indent, "(%s %s", type, val1);
- free(val1);
- val1 = NULL;
-
- rc = 0;
-
-exit:
- free(new_val);
- free(val1);
- free(val2);
- while ((val1 = stack_pop(stack)) != NULL) {
- free(val1);
- }
- stack_destroy(&stack);
-
- return rc;
-}
-
-static int cil_print_attr_list(int indent, struct policydb *pdb, struct list *attr_list)
-{
- struct list_node *curr;
- struct attr_list_node *attr_list_node;
- int rc = 0;
- struct type_set *ts;
- struct role_set *rs;
- char *generated_attribute;
-
- for (curr = attr_list->head; curr != NULL; curr = curr->next) {
- attr_list_node = curr->data;
- generated_attribute = attr_list_node->attribute;
- if (generated_attribute == NULL) {
- return -1;
- }
-
- if (attr_list_node->is_type) {
- ts = attr_list_node->set.ts;
- rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
- if (rc != 0) {
- return rc;
- }
- } else {
- rs = attr_list_node->set.rs;
- rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
- if (rc != 0) {
- return rc;
- }
- }
- }
-
- return rc;
-}
-
-static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node *cond_list)
-{
- int rc = -1;
- struct cond_node *cond;
- struct list *attr_list;
-
- rc = list_init(&attr_list);
- if (rc != 0) {
- goto exit;
- }
-
- for (cond = cond_list; cond != NULL; cond = cond->next) {
-
- rc = cond_expr_to_cil(indent, pdb, cond->expr, cond->flags);
- if (rc != 0) {
- goto exit;
- }
-
- if (cond->avtrue_list != NULL) {
- cil_println(indent + 1, "(true");
- rc = avrule_list_to_cil(indent + 2, pdb, cond->avtrue_list, attr_list);
- if (rc != 0) {
- goto exit;
- }
- cil_println(indent + 1, ")");
- }
-
- if (cond->avfalse_list != NULL) {
- cil_println(indent + 1, "(false");
- rc = avrule_list_to_cil(indent + 2, pdb, cond->avfalse_list, attr_list);
- if (rc != 0) {
- goto exit;
- }
- cil_println(indent + 1, ")");
- }
-
- cil_println(indent, ")");
- }
-
- rc = cil_print_attr_list(indent, pdb, attr_list);
-
-exit:
- attr_list_destroy(&attr_list);
- return rc;
-}
-
-static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans_rule *rules)
-{
- int rc = -1;
- struct role_trans_rule *rule;
- char **role_names = NULL;
- uint32_t num_role_names = 0;
- char **type_names = NULL;
- uint32_t num_type_names = 0;
- uint32_t type;
- uint32_t role;
- uint32_t i;
- struct ebitmap_node *node;
- struct type_set *ts;
- struct role_set *rs;
-
-
- for (rule = rules; rule != NULL; rule = rule->next) {
- rs = &rule->roles;
- rc = process_roleset(indent, pdb, rs, NULL, &role_names, &num_role_names);
- if (rc != 0) {
- goto exit;
- }
-
- ts = &rule->types;
- rc = process_typeset(indent, pdb, ts, NULL, &type_names, &num_type_names);
- if (rc != 0) {
- goto exit;
- }
-
- for (role = 0; role < num_role_names; role++) {
- for (type = 0; type < num_type_names; type++) {
- ebitmap_for_each_bit(&rule->classes, node, i) {
- if (!ebitmap_get_bit(&rule->classes, i)) {
- continue;
- }
- cil_println(indent, "(roletransition %s %s %s %s)", role_names[role],
- type_names[type],
- pdb->p_class_val_to_name[i],
- pdb->p_role_val_to_name[rule->new_role - 1]);
- }
- }
- }
-
- names_destroy(&role_names, &num_role_names);
- names_destroy(&type_names, &num_type_names);
- }
-
- rc = 0;
-
-exit:
- names_destroy(&role_names, &num_role_names);
- names_destroy(&type_names, &num_type_names);
-
- return rc;
-}
-
-static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allow_rule *rules)
-{
- int rc = -1;
- struct role_allow_rule *rule;
- char **roles = NULL;
- uint32_t num_roles = 0;
- char **new_roles = NULL;
- uint32_t num_new_roles = 0;
- uint32_t i;
- uint32_t j;
- struct role_set *rs;
-
- for (rule = rules; rule != NULL; rule = rule->next) {
- rs = &rule->roles;
- rc = process_roleset(indent, pdb, rs, NULL, &roles, &num_roles);
- if (rc != 0) {
- goto exit;
- }
-
- rs = &rule->new_roles;
- rc = process_roleset(indent, pdb, rs, NULL, &new_roles, &num_new_roles);
- if (rc != 0) {
- goto exit;
- }
-
- for (i = 0; i < num_roles; i++) {
- for (j = 0; j < num_new_roles; j++) {
- cil_println(indent, "(roleallow %s %s)", roles[i], new_roles[j]);
- }
- }
-
- names_destroy(&roles, &num_roles);
- names_destroy(&new_roles, &num_new_roles);
- }
-
- rc = 0;
-
-exit:
- names_destroy(&roles, &num_roles);
- names_destroy(&new_roles, &num_new_roles);
-
- return rc;
-}
-
-static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_trans_rule *rules)
-{
- int rc = -1;
- struct range_trans_rule *rule;
- char **stypes = NULL;
- uint32_t num_stypes = 0;
- char **ttypes = NULL;
- uint32_t num_ttypes = 0;
- struct ebitmap_node *node;
- uint32_t i;
- uint32_t stype;
- uint32_t ttype;
- struct type_set *ts;
-
- if (!pdb->mls) {
- return 0;
- }
-
- for (rule = rules; rule != NULL; rule = rule->next) {
- ts = &rule->stypes;
- rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
- if (rc != 0) {
- goto exit;
- }
-
- ts = &rule->ttypes;
- rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
- if (rc != 0) {
- goto exit;
- }
-
- for (stype = 0; stype < num_stypes; stype++) {
- for (ttype = 0; ttype < num_ttypes; ttype++) {
- ebitmap_for_each_bit(&rule->tclasses, node, i) {
- if (!ebitmap_get_bit(&rule->tclasses, i)) {
- continue;
- }
-
- cil_indent(indent);
- cil_printf("(rangetransition %s %s %s ", stypes[stype], ttypes[ttype], pdb->p_class_val_to_name[i]);
-
- cil_printf("(");
-
- rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[0]);
- if (rc != 0) {
- goto exit;
- }
-
- cil_printf(" ");
-
- rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[1]);
- if (rc != 0) {
- goto exit;
- }
-
- cil_printf("))\n");
- }
-
- }
- }
-
- names_destroy(&stypes, &num_stypes);
- names_destroy(&ttypes, &num_ttypes);
- }
-
- rc = 0;
-
-exit:
- names_destroy(&stypes, &num_stypes);
- names_destroy(&ttypes, &num_ttypes);
-
- return rc;
-}
-
-static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules)
-{
- int rc = -1;
- char **stypes = NULL;
- uint32_t num_stypes = 0;
- char **ttypes = NULL;
- uint32_t num_ttypes = 0;
- uint32_t stype;
- uint32_t ttype;
- struct type_set *ts;
-
- struct filename_trans_rule *rule;
-
- for (rule = rules; rule != NULL; rule = rule->next) {
- ts = &rule->stypes;
- rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
- if (rc != 0) {
- goto exit;
- }
-
- ts = &rule->ttypes;
- rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
- if (rc != 0) {
- goto exit;
- }
-
- for (stype = 0; stype < num_stypes; stype++) {
- for (ttype = 0; ttype < num_ttypes; ttype++) {
- cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", stypes[stype],
- ttypes[ttype],
- pdb->p_class_val_to_name[rule->tclass - 1],
- rule->name,
- pdb->p_type_val_to_name[rule->otype - 1]);
- }
- }
-
- names_destroy(&stypes, &num_stypes);
- names_destroy(&ttypes, &num_ttypes);
- }
-
- rc = 0;
-exit:
- names_destroy(&stypes, &num_stypes);
- names_destroy(&ttypes, &num_ttypes);
-
- return rc;
-}
-
-struct class_perm_datum {
- char *name;
- uint32_t val;
-};
-
-struct class_perm_array {
- struct class_perm_datum *perms;
- uint32_t count;
-};
-
-static int class_perm_to_array(char *key, void *data, void *args)
-{
- struct class_perm_array *arr = args;
- struct perm_datum *datum = data;
- arr->perms[arr->count].name = key;
- arr->perms[arr->count].val = datum->s.value;
- arr->count++;
-
- return 0;
-}
-
-static int class_perm_cmp(const void *a, const void *b)
-{
- const struct class_perm_datum *aa = a;
- const struct class_perm_datum *bb = b;
-
- return aa->val - bb->val;
-}
-
-static int common_to_cil(char *key, void *data, void *UNUSED(arg))
-{
- int rc = -1;
- struct common_datum *common = data;
- struct class_perm_array arr;
- uint32_t i;
-
- arr.count = 0;
- arr.perms = calloc(common->permissions.nprim, sizeof(*arr.perms));
- rc = hashtab_map(common->permissions.table, class_perm_to_array, &arr);
- if (rc != 0) {
- goto exit;
- }
-
- qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
-
- cil_printf("(common %s (", key);
- for (i = 0; i < arr.count; i++) {
- cil_printf("%s ", arr.perms[i].name);
- }
- cil_printf("))\n");
-
- rc = 0;
-
-exit:
- free(arr.perms);
- return rc;
-}
-
-
-static int constraint_expr_to_string(int indent, struct policydb *pdb, struct constraint_expr *exprs, char **expr_string)
-{
- int rc = -1;
- struct constraint_expr *expr;
- struct stack *stack = NULL;
- int len = 0;
- int rlen;
- char *new_val = NULL;
- char *val1 = NULL;
- char *val2 = NULL;
- uint32_t num_params;
- const char *op;
- const char *fmt_str;
- const char *attr1;
- const char *attr2;
- char *names;
- char **name_list = NULL;
- uint32_t num_names = 0;
- struct type_set *ts;
-
- rc = stack_init(&stack);
- if (rc != 0) {
- goto exit;
- }
-
- for (expr = exprs; expr != NULL; expr = expr->next) {
- if (expr->expr_type == CEXPR_ATTR || expr->expr_type == CEXPR_NAMES) {
- switch (expr->op) {
- case CEXPR_EQ: op = "eq"; break;
- case CEXPR_NEQ: op = "neq"; break;
- case CEXPR_DOM: op = "dom"; break;
- case CEXPR_DOMBY: op = "domby"; break;
- case CEXPR_INCOMP: op = "incomp"; break;
- default:
- log_err("Unknown constraint operator type: %i", expr->op);
- rc = -1;
- goto exit;
- }
-
- switch (expr->attr) {
- case CEXPR_USER: attr1 = "u1"; attr2 = "u2"; break;
- case CEXPR_USER | CEXPR_TARGET: attr1 = "u2"; attr2 = ""; break;
- case CEXPR_USER | CEXPR_XTARGET: attr1 = "u3"; attr2 = ""; break;
- case CEXPR_ROLE: attr1 = "r1"; attr2 = "r2"; break;
- case CEXPR_ROLE | CEXPR_TARGET: attr1 = "r2"; attr2 = ""; break;
- case CEXPR_ROLE | CEXPR_XTARGET: attr1 = "r3"; attr2 = ""; break;
- case CEXPR_TYPE: attr1 = "t1"; attr2 = ""; break;
- case CEXPR_TYPE | CEXPR_TARGET: attr1 = "t2"; attr2 = ""; break;
- case CEXPR_TYPE | CEXPR_XTARGET: attr1 = "t3"; attr2 = ""; break;
- case CEXPR_L1L2: attr1 = "l1"; attr2 = "l2"; break;
- case CEXPR_L1H2: attr1 = "l1"; attr2 = "h2"; break;
- case CEXPR_H1L2: attr1 = "h1"; attr2 = "l2"; break;
- case CEXPR_H1H2: attr1 = "h1"; attr2 = "h2"; break;
- case CEXPR_L1H1: attr1 = "l1"; attr2 = "h1"; break;
- case CEXPR_L2H2: attr1 = "l2"; attr2 = "h2"; break;
- default:
- log_err("Unknown expression attribute type: %i", expr->attr);
- rc = -1;
- goto exit;
- }
-
- if (expr->expr_type == CEXPR_ATTR) {
- // length of values/attrs + 2 separating spaces + 2 parens + null terminator
- len = strlen(op) + strlen(attr1) + strlen(attr2) + 2 + 2 + 1;
- new_val = malloc(len);
- if (new_val == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, attr2);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate constraint expression");
- rc = -1;
- goto exit;
- }
- } else {
- if (expr->attr & CEXPR_TYPE) {
- ts = expr->type_names;
- rc = process_typeset(indent, pdb, ts, NULL, &name_list, &num_names);
- if (rc != 0) {
- goto exit;
- }
- } else if (expr->attr & CEXPR_USER) {
- rc = ebitmap_to_names(pdb->p_user_val_to_name, expr->names, &name_list, &num_names);
- if (rc != 0) {
- goto exit;
- }
- } else if (expr->attr & CEXPR_ROLE) {
- rc = ebitmap_to_names(pdb->p_role_val_to_name, expr->names, &name_list, &num_names);
- if (rc != 0) {
- goto exit;
- }
- }
- rc = name_list_to_string(name_list, num_names, &names);
- if (rc != 0) {
- goto exit;
- }
-
- // length of values/oper + 2 spaces + 2 parens + null terminator
- len = strlen(op) + strlen(attr1) + strlen(names) + 2 + 2 + 1;
- new_val = malloc(len);
- if (new_val == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate constraint expression");
- rc = -1;
- goto exit;
- }
-
- names_destroy(&name_list, &num_names);
- free(names);
- }
-
- num_params = 0;
- } else {
- switch (expr->expr_type) {
- case CEXPR_NOT: op = "not"; break;
- case CEXPR_AND: op = "and"; break;
- case CEXPR_OR: op = "or"; break;
- default:
- log_err("Unknown constraint expression type: %i", expr->expr_type);
- rc = -1;
- goto exit;
- }
-
- num_params = expr->expr_type == CEXPR_NOT ? 1 : 2;
-
- if (num_params == 1) {
- val1 = stack_pop(stack);
- val2 = strdup("");
- if (val2 == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- fmt_str = "(%s %s)";
- } else {
- val2 = stack_pop(stack);
- val1 = stack_pop(stack);
- fmt_str = "(%s %s %s)";
- }
-
- if (val1 == NULL || val2 == NULL) {
- log_err("Invalid constraint expression");
- rc = -1;
- goto exit;
- }
-
- // length = length of parameters +
- // length of operator +
- // 1 space preceeding each parameter +
- // 2 parens around the whole expression
- // + null terminator
- len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
- new_val = malloc(len);
- if (new_val == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- // although we always supply val2 and there isn't always a 2nd
- // value, it should only be used when there are actually two values
- // in the format strings
- rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
- if (rlen < 0 || rlen >= len) {
- log_err("Failed to generate constraint expression");
- rc = -1;
- goto exit;
- }
-
- free(val1);
- free(val2);
- val1 = NULL;
- val2 = NULL;
- }
-
- rc = stack_push(stack, new_val);
- if (rc != 0) {
- log_err("Out of memory");
- goto exit;
- }
-
- new_val = NULL;
- }
-
- new_val = stack_pop(stack);
- if (new_val == NULL || stack_peek(stack) != NULL) {
- log_err("Invalid constraint expression");
- rc = -1;
- goto exit;
- }
-
- *expr_string = new_val;
- new_val = NULL;
-
- rc = 0;
-
-exit:
- names_destroy(&name_list, &num_names);
-
- free(new_val);
- free(val1);
- free(val2);
- while ((val1 = stack_pop(stack)) != NULL) {
- free(val1);
- }
- stack_destroy(&stack);
-
- return rc;
-}
-
-
-static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey, struct class_datum *class, struct constraint_node *constraints, int is_constraint)
-{
- int rc = -1;
- struct constraint_node *node;
- char *expr = NULL;
- const char *mls;
- char *perms;
-
- mls = pdb->mls ? "mls" : "";
-
- for (node = constraints; node != NULL; node = node->next) {
-
- rc = constraint_expr_to_string(indent, pdb, node->expr, &expr);
- if (rc != 0) {
- goto exit;
- }
-
- if (is_constraint) {
- perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
- cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
- } else {
- cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
- }
-
- free(expr);
- expr = NULL;
- }
-
- rc = 0;
-
-exit:
- free(expr);
- return rc;
-}
-
-static int class_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
- int rc = -1;
- struct class_datum *class = datum;
- const char *dflt;
- struct class_perm_array arr;
- uint32_t i;
-
- if (scope == SCOPE_REQ) {
- return 0;
- }
-
- arr.count = 0;
- arr.perms = calloc(class->permissions.nprim, sizeof(*arr.perms));
- rc = hashtab_map(class->permissions.table, class_perm_to_array, &arr);
- if (rc != 0) {
- goto exit;
- }
-
- qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
-
- cil_indent(indent);
- cil_printf("(class %s (", key);
- for (i = 0; i < arr.count; i++) {
- cil_printf("%s ", arr.perms[i].name);
- }
- cil_printf("))\n");
-
- if (class->comkey != NULL) {
- cil_println(indent, "(classcommon %s %s)", key, class->comkey);
- }
-
- if (class->default_user != 0) {
- switch (class->default_user) {
- case DEFAULT_SOURCE: dflt = "source"; break;
- case DEFAULT_TARGET: dflt = "target"; break;
- default:
- log_err("Unknown default user value: %i", class->default_user);
- rc = -1;
- goto exit;
- }
- cil_println(indent, "(defaultuser %s %s)", key, dflt);
- }
-
- if (class->default_role != 0) {
- switch (class->default_role) {
- case DEFAULT_SOURCE: dflt = "source"; break;
- case DEFAULT_TARGET: dflt = "target"; break;
- default:
- log_err("Unknown default role value: %i", class->default_role);
- rc = -1;
- goto exit;
- }
- cil_println(indent, "(defaultrole %s %s)", key, dflt);
- }
-
- if (class->default_type != 0) {
- switch (class->default_type) {
- case DEFAULT_SOURCE: dflt = "source"; break;
- case DEFAULT_TARGET: dflt = "target"; break;
- default:
- log_err("Unknown default type value: %i", class->default_type);
- rc = -1;
- goto exit;
- }
- cil_println(indent, "(defaulttype %s %s)", key, dflt);
- }
-
- if (class->default_range != 0) {
- switch (class->default_range) {
- case DEFAULT_SOURCE_LOW: dflt = "source low"; break;
- case DEFAULT_SOURCE_HIGH: dflt = "source high"; break;
- case DEFAULT_SOURCE_LOW_HIGH: dflt = "source low-high"; break;
- case DEFAULT_TARGET_LOW: dflt = "target low"; break;
- case DEFAULT_TARGET_HIGH: dflt = "target high"; break;
- case DEFAULT_TARGET_LOW_HIGH: dflt = "target low-high"; break;
- default:
- log_err("Unknown default range value: %i", class->default_range);
- rc = -1;
- goto exit;
- }
- cil_println(indent, "(defaultrange %s %s)", key, dflt);
-
- }
-
- if (class->constraints != NULL) {
- rc = constraints_to_cil(indent, pdb, key, class, class->constraints, 1);
- if (rc != 0) {
- goto exit;
- }
- }
-
- if (class->validatetrans != NULL) {
- rc = constraints_to_cil(indent, pdb, key, class, class->validatetrans, 0);
- if (rc != 0) {
- goto exit;
- }
- }
-
- rc = 0;
-
-exit:
- free(arr.perms);
- return rc;
-}
-
-static int class_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
-{
- struct ebitmap_node *node;
- uint32_t i;
-
- if (ebitmap_cardinality(&order) == 0) {
- return 0;
- }
-
- cil_indent(indent);
- cil_printf("(classorder (");
-
- ebitmap_for_each_bit(&order, node, i) {
- if (!ebitmap_get_bit(&order, i)) {
- continue;
- }
- cil_printf("%s ", pdb->sym_val_to_name[SYM_CLASSES][i]);
- }
-
- cil_printf("))\n");
-
- return 0;
-}
-
-static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
-{
- int rc = -1;
- struct ebitmap_node *node;
- uint32_t i;
- char **types = NULL;
- uint32_t num_types = 0;
- struct role_datum *role = datum;
- struct type_set *ts;
-
- if (scope == SCOPE_REQ) {
- // if a role/roleattr is in the REQ scope, then it could cause an
- // optional block to fail, even if it is never used. However in CIL,
- // symbols must be used in order to cause an optional block to fail. So
- // for symbols in the REQ scope, add them to a roleattribute as a way
- // to 'use' them in the optional without affecting the resulting policy.
- cil_println(indent, "(roleattributeset " GEN_REQUIRE_ATTR " %s)", key);
- }
-
- switch (role->flavor) {
- case ROLE_ROLE:
- if (scope == SCOPE_DECL) {
- // Only declare certain roles if we are reading a base module.
- // These roles are defined in the base module and sometimes in
- // other non-base modules. If we generated the roles regardless of
- // the policy type, it would result in duplicate declarations,
- // which isn't allowed in CIL. Patches have been made to refpolicy
- // to remove these duplicate role declarations, but we need to be
- // backwards compatable and support older policies. Since we know
- // these roles are always declared in base, only print them when we
- // see them in the base module. If the declarations appear in a
- // non-base module, ignore their declarations.
- //
- // Note that this is a hack, and if a policy author does not define
- // one of these roles in base, the declaration will not appeaer in
- // the resulting policy, likely resulting in a compilation error in
- // CIL.
- int is_base_role = (!strcmp(key, "user_r") ||
- !strcmp(key, "staff_r") ||
- !strcmp(key, "sysadm_r") ||
- !strcmp(key, "system_r") ||
- !strcmp(key, "unconfined_r"));
- if ((is_base_role && pdb->policy_type == SEPOL_POLICY_BASE) || !is_base_role) {
- cil_println(indent, "(role %s)", key);
- }
- }
-
- if (ebitmap_cardinality(&role->dominates) > 1) {
- log_err("Warning: role 'dominance' statement unsupported in CIL. Dropping from output.");
- }
-
- ts = &role->types;
- rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
- if (rc != 0) {
- goto exit;
- }
-
- for (i = 0; i < num_types; i++) {
- if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
- cil_println(indent, "(roletype %s %s)", key, types[i]);
- }
- }
-
- if (role->bounds > 0) {
- cil_println(indent, "(rolebounds %s %s)", key, pdb->p_role_val_to_name[role->bounds - 1]);
- }
- break;
-
- case ROLE_ATTRIB:
- if (scope == SCOPE_DECL) {
- cil_println(indent, "(roleattribute %s)", key);
- }
-
- if (ebitmap_cardinality(&role->roles) > 0) {
- cil_indent(indent);
- cil_printf("(roleattributeset %s (", key);
- ebitmap_for_each_bit(&role->roles, node, i) {
- if (!ebitmap_get_bit(&role->roles, i)) {
- continue;
- }
- cil_printf("%s ", pdb->p_role_val_to_name[i]);
- }
- cil_printf("))\n");
- }
-
- ts = &role->types;
- rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
- if (rc != 0) {
- goto exit;
- }
-
-
- for (i = 0; i < num_types; i++) {
- cil_println(indent, "(roletype %s %s)", key, types[i]);
- }
-
- break;
-
- default:
- log_err("Unknown role type: %i", role->flavor);
- rc = -1;
- goto exit;
- }
-
- rc = 0;
-exit:
- names_destroy(&types, &num_types);
-
- return rc;
-}
-
-static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
-{
- int rc = -1;
- struct type_datum *type = datum;
-
- if (scope == SCOPE_REQ) {
- // if a type/typeattr is in the REQ scope, then it could cause an
- // optional block to fail, even if it is never used. However in CIL,
- // symbols must be used in order to cause an optional block to fail. So
- // for symbols in the REQ scope, add them to a typeattribute as a way
- // to 'use' them in the optional without affecting the resulting policy.
- cil_println(indent, "(typeattributeset " GEN_REQUIRE_ATTR " %s)", key);
- }
-
- rc = roletype_role_in_ancestor_to_cil(pdb, decl_stack, key, indent);
- if (rc != 0) {
- goto exit;
- }
-
- switch(type->flavor) {
- case TYPE_TYPE:
- if (scope == SCOPE_DECL) {
- cil_println(indent, "(type %s)", key);
- // object_r is implicit in checkmodule, but not with CIL,
- // create it as part of base
- cil_println(indent, "(roletype " DEFAULT_OBJECT " %s)", key);
- }
-
- if (type->flags & TYPE_FLAGS_PERMISSIVE) {
- cil_println(indent, "(typepermissive %s)", key);
- }
-
- if (type->bounds > 0) {
- cil_println(indent, "(typebounds %s %s)", pdb->p_type_val_to_name[type->bounds - 1], key);
- }
- break;
- case TYPE_ATTRIB:
- if (scope == SCOPE_DECL) {
- cil_println(indent, "(typeattribute %s)", key);
- }
-
- if (ebitmap_cardinality(&type->types) > 0) {
- cil_indent(indent);
- cil_printf("(typeattributeset %s (", key);
- ebitmap_to_cil(pdb, &type->types, SYM_TYPES);
- cil_printf("))\n");
- }
- break;
- default:
- log_err("Unknown flavor (%i) of type %s", type->flavor, key);
- rc = -1;
- goto exit;
- }
-
- rc = 0;
-
-exit:
- return rc;
-}
-
-static int user_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
- struct user_datum *user = datum;
- struct ebitmap roles = user->roles.roles;
- struct mls_semantic_level level = user->dfltlevel;
- struct mls_semantic_range range = user->range;
- struct ebitmap_node *node;
- uint32_t i;
- int sens_offset = 1;
-
- if (scope == SCOPE_DECL) {
- cil_println(indent, "(user %s)", key);
- // object_r is implicit in checkmodule, but not with CIL, create it
- // as part of base
- cil_println(indent, "(userrole %s " DEFAULT_OBJECT ")", key);
- }
-
- ebitmap_for_each_bit(&roles, node, i) {
- if (!ebitmap_get_bit(&roles, i)) {
- continue;
- }
- cil_println(indent, "(userrole %s %s)", key, pdb->p_role_val_to_name[i]);
- }
-
- if (block->flags & AVRULE_OPTIONAL) {
- // sensitivites in user statements in optionals do not have the
- // standard -1 offest
- sens_offset = 0;
- }
-
- cil_indent(indent);
- cil_printf("(userlevel %s ", key);
- if (pdb->mls) {
- semantic_level_to_cil(pdb, sens_offset, &level);
- } else {
- cil_printf(DEFAULT_LEVEL);
- }
- cil_printf(")\n");
-
- cil_indent(indent);
- cil_printf("(userrange %s (", key);
- if (pdb->mls) {
- semantic_level_to_cil(pdb, sens_offset, &range.level[0]);
- cil_printf(" ");
- semantic_level_to_cil(pdb, sens_offset, &range.level[1]);
- } else {
- cil_printf(DEFAULT_LEVEL " " DEFAULT_LEVEL);
- }
- cil_printf("))\n");
-
-
- return 0;
-}
-
-static int boolean_to_cil(int indent, struct policydb *UNUSED(pdb), struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
- struct cond_bool_datum *boolean = datum;
- const char *type;
-
- if (scope == SCOPE_DECL) {
- if (boolean->flags & COND_BOOL_FLAGS_TUNABLE) {
- type = "tunable";
- } else {
- type = "boolean";
- }
-
- cil_println(indent, "(%s %s %s)", type, key, boolean->state ? "true" : "false");
- }
-
- return 0;
-}
-
-static int sens_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
- struct level_datum *level = datum;
-
- if (scope == SCOPE_DECL) {
- if (!level->isalias) {
- cil_println(indent, "(sensitivity %s)", key);
- } else {
- cil_println(indent, "(sensitivityalias %s)", key);
- cil_println(indent, "(sensitivityaliasactual %s %s)", key, pdb->p_sens_val_to_name[level->level->sens - 1]);
- }
- }
-
- if (ebitmap_cardinality(&level->level->cat) > 0) {
- cil_indent(indent);
- cil_printf("(sensitivitycategory %s (", key);
- ebitmap_to_cil(pdb, &level->level->cat, SYM_CATS);
- cil_printf("))\n");
- }
-
- return 0;
-}
-
-static int sens_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
-{
- struct ebitmap_node *node;
- uint32_t i;
-
- if (ebitmap_cardinality(&order) == 0) {
- return 0;
- }
-
- cil_indent(indent);
- cil_printf("(sensitivityorder (");
-
- ebitmap_for_each_bit(&order, node, i) {
- if (!ebitmap_get_bit(&order, i)) {
- continue;
- }
- cil_printf("%s ", pdb->p_sens_val_to_name[i]);
- }
-
- cil_printf("))\n");
-
- return 0;
-}
-
-static int cat_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
- struct cat_datum *cat = datum;
-
- if (scope == SCOPE_REQ) {
- return 0;
- }
-
- if (!cat->isalias) {
- cil_println(indent, "(category %s)", key);
- } else {
- cil_println(indent, "(categoryalias %s)", key);
- cil_println(indent, "(categoryaliasactual %s %s)", key, pdb->p_cat_val_to_name[cat->s.value - 1]);
- }
-
- return 0;
-}
-
-static int cat_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
-{
- int rc = -1;
- struct ebitmap_node *node;
- uint32_t i;
-
- if (ebitmap_cardinality(&order) == 0) {
- rc = 0;
- goto exit;
- }
-
- cil_indent(indent);
- cil_printf("(categoryorder (");
-
- ebitmap_for_each_bit(&order, node, i) {
- if (!ebitmap_get_bit(&order, i)) {
- continue;
- }
- cil_printf("%s ", pdb->p_cat_val_to_name[i]);
- }
-
- cil_printf("))\n");
-
- return 0;
-exit:
- return rc;
-}
-
-static int polcaps_to_cil(struct policydb *pdb)
-{
- int rc = -1;
- struct ebitmap *map;
- struct ebitmap_node *node;
- uint32_t i;
- const char *name;
-
- map = &pdb->policycaps;
-
- ebitmap_for_each_bit(map, node, i) {
- if (!ebitmap_get_bit(map, i)) {
- continue;
- }
- name = sepol_polcap_getname(i);
- if (name == NULL) {
- log_err("Unknown policy capability id: %i", i);
- rc = -1;
- goto exit;
- }
-
- cil_println(0, "(policycap %s)", name);
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int level_to_cil(struct policydb *pdb, struct mls_level *level)
-{
- struct ebitmap *map = &level->cat;
-
- cil_printf("(%s", pdb->p_sens_val_to_name[level->sens - 1]);
-
- if (ebitmap_cardinality(map) > 0) {
- cil_printf("(");
- ebitmap_to_cil(pdb, map, SYM_CATS);
- cil_printf(")");
- }
-
- cil_printf(")");
-
- return 0;
-}
-
-static int context_to_cil(struct policydb *pdb, struct context_struct *con)
-{
- cil_printf("(%s %s %s (",
- pdb->p_user_val_to_name[con->user - 1],
- pdb->p_role_val_to_name[con->role - 1],
- pdb->p_type_val_to_name[con->type - 1]);
-
- if (pdb->mls) {
- level_to_cil(pdb, &con->range.level[0]);
- cil_printf(" ");
- level_to_cil(pdb, &con->range.level[1]);
- } else {
- cil_printf(DEFAULT_LEVEL);
- cil_printf(" ");
- cil_printf(DEFAULT_LEVEL);
- }
-
- cil_printf("))");
-
- return 0;
-}
-
-static int ocontext_isid_to_cil(struct policydb *pdb, const char **sid_to_string, struct ocontext *isids)
-{
- int rc = -1;
-
- struct ocontext *isid;
-
- struct sid_item {
- const char *sid_key;
- struct sid_item *next;
- };
-
- struct sid_item *head = NULL;
- struct sid_item *item = NULL;
-
- for (isid = isids; isid != NULL; isid = isid->next) {
- cil_println(0, "(sid %s)", sid_to_string[isid->sid[0]]);
- cil_printf("(sidcontext %s ", sid_to_string[isid->sid[0]]);
- context_to_cil(pdb, &isid->context[0]);
- cil_printf(")\n");
-
- // get the sid names in the correct order (reverse from the isids
- // ocontext) for sidorder statement
- item = malloc(sizeof(*item));
- if (item == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- item->sid_key = sid_to_string[isid->sid[0]];
- item->next = head;
- head = item;
- }
-
- if (head != NULL) {
- cil_printf("(sidorder (");
- for (item = head; item != NULL; item = item->next) {
- cil_printf("%s ", item->sid_key);
- }
- cil_printf("))\n");
- }
-
- rc = 0;
-
-exit:
- while(head) {
- item = head;
- head = item->next;
- free(item);
- }
- return rc;
-}
-
-static int ocontext_selinux_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
-{
- int rc = -1;
-
- // initial sid names aren't actually stored in the pp files, need to a have
- // a mapping, taken from the linux kernel
- static const char *selinux_sid_to_string[] = {
- "null",
- "kernel",
- "security",
- "unlabeled",
- "fs",
- "file",
- "file_labels",
- "init",
- "any_socket",
- "port",
- "netif",
- "netmsg",
- "node",
- "igmp_packet",
- "icmp_socket",
- "tcp_socket",
- "sysctl_modprobe",
- "sysctl",
- "sysctl_fs",
- "sysctl_kernel",
- "sysctl_net",
- "sysctl_net_unix",
- "sysctl_vm",
- "sysctl_dev",
- "kmod",
- "policy",
- "scmp_packet",
- "devnull",
- NULL
- };
-
- rc = ocontext_isid_to_cil(pdb, selinux_sid_to_string, isids);
- if (rc != 0) {
- goto exit;
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int ocontext_selinux_fs_to_cil(struct policydb *UNUSED(pdb), struct ocontext *fss)
-{
- if (fss != NULL) {
- log_err("Warning: 'fscon' statement unsupported in CIL. Dropping from output.");
- }
-
- return 0;
-}
-
-static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *portcons)
-{
- int rc = -1;
- struct ocontext *portcon;
- const char *protocol;
- uint16_t high;
- uint16_t low;
-
- for (portcon = portcons; portcon != NULL; portcon = portcon->next) {
-
- switch (portcon->u.port.protocol) {
- case IPPROTO_TCP: protocol = "tcp"; break;
- case IPPROTO_UDP: protocol = "udp"; break;
- default:
- log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
- rc = -1;
- goto exit;
- }
-
- low = portcon->u.port.low_port;
- high = portcon->u.port.high_port;
-
- if (low == high) {
- cil_printf("(portcon %s %i ", protocol, low);
- } else {
- cil_printf("(portcon %s (%i %i) ", protocol, low, high);
- }
-
- context_to_cil(pdb, &portcon->context[0]);
-
- cil_printf(")\n");
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
-{
- struct ocontext *netif;
-
- for (netif = netifs; netif != NULL; netif = netif->next) {
- cil_printf("(netifcon %s ", netif->u.name);
- context_to_cil(pdb, &netif->context[0]);
-
- cil_printf(" ");
- context_to_cil(pdb, &netif->context[1]);
- cil_printf(")\n");
- }
-
- return 0;
-}
-
-static int ocontext_selinux_node_to_cil(struct policydb *pdb, struct ocontext *nodes)
-{
- int rc = -1;
- struct ocontext *node;
- char addr[INET_ADDRSTRLEN];
- char mask[INET_ADDRSTRLEN];
-
- for (node = nodes; node != NULL; node = node->next) {
- if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
- log_err("Nodecon address is invalid: %s", strerror(errno));
- rc = -1;
- goto exit;
- }
-
- if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
- log_err("Nodecon mask is invalid: %s", strerror(errno));
- rc = -1;
- goto exit;
- }
-
- cil_printf("(nodecon %s %s ", addr, mask);
-
- context_to_cil(pdb, &node->context[0]);
-
- cil_printf(")\n");
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int ocontext_selinux_node6_to_cil(struct policydb *pdb, struct ocontext *nodes)
-{
- int rc = -1;
- struct ocontext *node;
- char addr[INET6_ADDRSTRLEN];
- char mask[INET6_ADDRSTRLEN];
-
- for (node = nodes; node != NULL; node = node->next) {
- if (inet_ntop(AF_INET6, &node->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
- log_err("Nodecon address is invalid: %s", strerror(errno));
- rc = -1;
- goto exit;
- }
-
- if (inet_ntop(AF_INET6, &node->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
- log_err("Nodecon mask is invalid: %s", strerror(errno));
- rc = -1;
- goto exit;
- }
-
- cil_printf("(nodecon %s %s ", addr, mask);
-
- context_to_cil(pdb, &node->context[0]);
-
- cil_printf(")\n");
- }
-
- return 0;
-exit:
- return rc;
-}
-
-
-static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
-{
- int rc = -1;
- struct ocontext *fsuse;
- const char *behavior;
-
-
- for (fsuse = fsuses; fsuse != NULL; fsuse = fsuse->next) {
- switch (fsuse->v.behavior) {
- case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
- case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
- case SECURITY_FS_USE_TASK: behavior = "task"; break;
- default:
- log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
- rc = -1;
- goto exit;
- }
-
- cil_printf("(fsuse %s %s ", behavior, fsuse->u.name);
-
- context_to_cil(pdb, &fsuse->context[0]);
-
- cil_printf(")\n");
-
- }
-
- return 0;
-exit:
- return rc;
-}
-
-
-static int ocontext_xen_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
-{
- int rc = -1;
-
- // initial sid names aren't actually stored in the pp files, need to a have
- // a mapping, taken from the xen kernel
- static const char *xen_sid_to_string[] = {
- "null",
- "xen",
- "dom0",
- "domio",
- "domxen",
- "unlabeled",
- "security",
- "ioport",
- "iomem",
- "irq",
- "device",
- NULL,
- };
-
- rc = ocontext_isid_to_cil(pdb, xen_sid_to_string, isids);
- if (rc != 0) {
- goto exit;
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int ocontext_xen_pirq_to_cil(struct policydb *pdb, struct ocontext *pirqs)
-{
- struct ocontext *pirq;
-
- for (pirq = pirqs; pirq != NULL; pirq = pirq->next) {
- cil_printf("(pirqcon %i ", pirq->u.pirq);
- context_to_cil(pdb, &pirq->context[0]);
- cil_printf(")\n");
- }
-
- return 0;
-}
-
-static int ocontext_xen_ioport_to_cil(struct policydb *pdb, struct ocontext *ioports)
-{
- struct ocontext *ioport;
- uint32_t low;
- uint32_t high;
-
- for (ioport = ioports; ioport != NULL; ioport = ioport->next) {
- low = ioport->u.ioport.low_ioport;
- high = ioport->u.ioport.high_ioport;
-
- if (low == high) {
- cil_printf("(ioportcon %i ", low);
- } else {
- cil_printf("(ioportcon (%i %i) ", low, high);
- }
-
- context_to_cil(pdb, &ioport->context[0]);
-
- cil_printf(")\n");
- }
-
- return 0;
-}
-
-static int ocontext_xen_iomem_to_cil(struct policydb *pdb, struct ocontext *iomems)
-{
- struct ocontext *iomem;
- uint64_t low;
- uint64_t high;
-
- for (iomem = iomems; iomem != NULL; iomem = iomem->next) {
- low = iomem->u.iomem.low_iomem;
- high = iomem->u.iomem.high_iomem;
-
- if (low == high) {
- cil_printf("(iomemcon %#lX ", (unsigned long)low);
- } else {
- cil_printf("(iomemcon (%#lX %#lX) ", (unsigned long)low, (unsigned long)high);
- }
-
- context_to_cil(pdb, &iomem->context[0]);
-
- cil_printf(")\n");
- }
-
- return 0;
-}
-
-static int ocontext_xen_pcidevice_to_cil(struct policydb *pdb, struct ocontext *pcids)
-{
- struct ocontext *pcid;
-
- for (pcid = pcids; pcid != NULL; pcid = pcid->next) {
- cil_printf("(pcidevicecon %#lx ", (unsigned long)pcid->u.device);
- context_to_cil(pdb, &pcid->context[0]);
- cil_printf(")\n");
- }
-
- return 0;
-}
-
-static int ocontexts_to_cil(struct policydb *pdb)
-{
- int rc = -1;
- int ocon;
-
- static int (**ocon_funcs)(struct policydb *pdb, struct ocontext *ocon);
- static int (*ocon_selinux_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
- ocontext_selinux_isid_to_cil,
- ocontext_selinux_fs_to_cil,
- ocontext_selinux_port_to_cil,
- ocontext_selinux_netif_to_cil,
- ocontext_selinux_node_to_cil,
- ocontext_selinux_fsuse_to_cil,
- ocontext_selinux_node6_to_cil,
- };
- static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
- ocontext_xen_isid_to_cil,
- ocontext_xen_pirq_to_cil,
- ocontext_xen_ioport_to_cil,
- ocontext_xen_iomem_to_cil,
- ocontext_xen_pcidevice_to_cil,
- NULL,
- NULL,
- };
-
- switch (pdb->target_platform) {
- case SEPOL_TARGET_SELINUX:
- ocon_funcs = ocon_selinux_funcs;
- break;
- case SEPOL_TARGET_XEN:
- ocon_funcs = ocon_xen_funcs;
- break;
- default:
- log_err("Unknown target platform: %i", pdb->target_platform);
- rc = -1;
- goto exit;
- }
-
- for (ocon = 0; ocon < OCON_NUM; ocon++) {
- if (ocon_funcs[ocon] != NULL) {
- rc = ocon_funcs[ocon](pdb, pdb->ocontexts[ocon]);
- if (rc != 0) {
- goto exit;
- }
- }
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int genfscon_to_cil(struct policydb *pdb)
-{
- struct genfs *genfs;
- struct ocontext *ocon;
-
- for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
- for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
- cil_printf("(genfscon %s %s ", genfs->fstype, ocon->u.name);
- context_to_cil(pdb, &ocon->context[0]);
- cil_printf(")\n");
- }
- }
-
- return 0;
-}
-
-static int level_string_to_cil(char *levelstr)
-{
- int rc = -1;
- char *sens = NULL;
- char *cats = NULL;
- int matched;
- char *saveptr = NULL;
- char *token = NULL;
- char *ranged = NULL;
-
- matched = sscanf(levelstr, "%m[^:]:%ms", &sens, &cats);
- if (matched < 1 || matched > 2) {
- log_err("Invalid level: %s", levelstr);
- rc = -1;
- goto exit;
- }
-
- cil_printf("(%s", sens);
-
- if (matched == 2) {
- cil_printf("(");
- token = strtok_r(cats, ",", &saveptr);
- while (token != NULL) {
- ranged = strchr(token, '.');
- if (ranged == NULL) {
- cil_printf("%s ", token);
- } else {
- *ranged = '\0';
- cil_printf("(range %s %s) ", token, ranged + 1);
- }
- token = strtok_r(NULL, ",", &saveptr);
- }
- cil_printf(")");
- }
-
- cil_printf(")");
-
- rc = 0;
-exit:
- free(sens);
- free(cats);
- return rc;
-}
-
-static int level_range_string_to_cil(char *levelrangestr)
-{
- char *ranged = NULL;
- char *low;
- char *high;
-
- ranged = strchr(levelrangestr, '-');
- if (ranged == NULL) {
- low = high = levelrangestr;
- } else {
- *ranged = '\0';
- low = levelrangestr;
- high = ranged + 1;
- }
-
- level_string_to_cil(low);
- cil_printf(" ");
- level_string_to_cil(high);
-
- return 0;
-}
-
-static int context_string_to_cil(char *contextstr)
-{
- int rc = -1;
- int matched;
- char *user = NULL;
- char *role = NULL;
- char *type = NULL;
- char *level = NULL;
-
- matched = sscanf(contextstr, "%m[^:]:%m[^:]:%m[^:]:%ms", &user, &role, &type, &level);
- if (matched < 3 || matched > 4) {
- log_err("Invalid context: %s", contextstr);
- rc = -1;
- goto exit;
- }
-
- cil_printf("(%s %s %s (", user, role, type);
-
- if (matched == 3) {
- cil_printf(DEFAULT_LEVEL);
- cil_printf(" ");
- cil_printf(DEFAULT_LEVEL);
- } else {
- level_range_string_to_cil(level);
- }
-
- cil_printf("))");
-
- rc = 0;
-
-exit:
- free(user);
- free(role);
- free(type);
- free(level);
-
- return rc;
-}
-
-static int seusers_to_cil(struct sepol_module_package *mod_pkg)
-{
- int rc = -1;
- FILE *fp = NULL;
- char *seusers = sepol_module_package_get_seusers(mod_pkg);
- size_t seusers_len = sepol_module_package_get_seusers_len(mod_pkg);
- size_t len = 0;
- char *line = NULL;
- ssize_t line_len = 0;
- char *buf = NULL;
-
- char *user = NULL;
- char *seuser = NULL;
- char *level = NULL;
- int matched;
-
- if (seusers_len == 0) {
- return 0;
- }
-
- fp = fmemopen(seusers, seusers_len, "r");
-
- while ((line_len = getline(&line, &len, fp)) != -1) {
- buf = line;
- buf[line_len - 1] = '\0';
- while (*buf && isspace(buf[0])) {
- buf++;
- }
- if (buf[0] == '#' || buf[0] == '\0') {
- continue;
- }
-
- matched = sscanf(buf, "%m[^:]:%m[^:]:%ms", &user, &seuser, &level);
-
- if (matched < 2 || matched > 3) {
- log_err("Invalid seuser line: %s", line);
- rc = -1;
- goto exit;
- }
-
- if (!strcmp(user, "__default__")) {
- cil_printf("(selinuxuserdefault %s (", seuser);
- } else {
- cil_printf("(selinuxuser %s %s (", user, seuser);
- }
-
- switch (matched) {
- case 2:
- cil_printf("systemlow systemlow");
- break;
- case 3:
- level_range_string_to_cil(level);
- break;
- }
-
- cil_printf("))\n");
-
- free(user);
- free(seuser);
- free(level);
- user = seuser = level = NULL;
- }
- if (ferror(fp)) {
- cil_printf("Failed to read seusers\n");
- rc = -1;
- goto exit;
- }
-
- rc = 0;
-
-exit:
- if (fp != NULL) {
- fclose(fp);
- }
- free(line);
- free(user);
- free(seuser);
- free(level);
-
- return rc;
-}
-
-static int netfilter_contexts_to_cil(struct sepol_module_package *mod_pkg)
-{
- size_t netcons_len = sepol_module_package_get_netfilter_contexts_len(mod_pkg);
-
- if (netcons_len > 0) {
- log_err("Warning: netfilter_contexts are unsupported in CIL. Dropping from output.");
- }
-
- return 0;
-}
-
-static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
-{
- int rc = -1;
- char *userx = sepol_module_package_get_user_extra(mod_pkg);
- size_t userx_len = sepol_module_package_get_user_extra_len(mod_pkg);
- FILE *fp = NULL;
- size_t len = 0;
- char *line = NULL;
- ssize_t line_len = 0;
- int matched;
- char *user = NULL;
- char *prefix = NULL;
-
- if (userx_len == 0) {
- return 0;
- }
-
- fp = fmemopen(userx, userx_len, "r");
-
- while ((line_len = getline(&line, &len, fp)) != -1) {
- line[line_len - 1] = '\0';
-
- matched = sscanf(line, "user %ms prefix %m[^;];", &user, &prefix);
- if (matched != 2) {
- rc = -1;
- log_err("Invalid file context line: %s", line);
- goto exit;
- }
-
- cil_println(0, "(userprefix %s %s)", user, prefix);
- free(user);
- free(prefix);
- user = prefix = NULL;
- }
-
- if (ferror(fp)) {
- cil_printf("Failed to read user_extra\n");
- rc = -1;
- goto exit;
- }
-
- rc = 0;
-exit:
- if (fp != NULL) {
- fclose(fp);
- }
- free(line);
- free(user);
- free(prefix);
-
- return rc;
-}
-
-static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
-{
- int rc = -1;
- char *fc = sepol_module_package_get_file_contexts(mod_pkg);
- size_t fc_len = sepol_module_package_get_file_contexts_len(mod_pkg);
- FILE *fp = NULL;
- size_t len = 0;
- char *line = NULL;
- char *buf = NULL;
- ssize_t line_len = 0;
- int matched;
- char *regex = NULL;
- char *mode = NULL;
- char *context = NULL;
- const char *cilmode;
-
- if (fc_len == 0) {
- return 0;
- }
-
- fp = fmemopen(fc, fc_len, "r");
- while ((line_len = getline(&line, &len, fp)) != -1) {
- buf = line;
- if (buf[line_len - 1] == '\n') {
- buf[line_len - 1] = '\0';
- }
- while (*buf && isspace(buf[0])) {
- buf++;
- }
- if (buf[0] == '#' || buf[0] == '\0') {
- continue;
- }
-
- matched = sscanf(buf, "%ms %ms %ms", ®ex, &mode, &context);
- if (matched < 2 || matched > 3) {
- rc = -1;
- log_err("Invalid file context line: %s", line);
- goto exit;
- }
-
- if (matched == 2) {
- context = mode;
- mode = NULL;
- }
-
- if (mode == NULL) {
- cilmode = "any";
- } else if (!strcmp(mode, "--")) {
- cilmode = "file";
- } else if (!strcmp(mode, "-d")) {
- cilmode = "dir";
- } else if (!strcmp(mode, "-c")) {
- cilmode = "char";
- } else if (!strcmp(mode, "-b")) {
- cilmode = "block";
- } else if (!strcmp(mode, "-s")) {
- cilmode = "socket";
- } else if (!strcmp(mode, "-p")) {
- cilmode = "pipe";
- } else if (!strcmp(mode, "-l")) {
- cilmode = "symlink";
- } else {
- rc = -1;
- log_err("Invalid mode in file context line: %s", line);
- goto exit;
- }
-
- cil_printf("(filecon \"%s\" %s ", regex, cilmode);
-
- if (!strcmp(context, "<<none>>")) {
- cil_printf("()");
- } else {
- context_string_to_cil(context);
- }
-
- cil_printf(")\n");
-
- free(regex);
- free(mode);
- free(context);
- regex = mode = context = NULL;
- }
-
- if (ferror(fp)) {
- cil_printf("Failed to read user_extra\n");
- rc = -1;
- goto exit;
- }
-
- rc = 0;
-exit:
- free(line);
- free(regex);
- free(mode);
- free(context);
- if (fp != NULL) {
- fclose(fp);
- }
-
- return rc;
-}
-
-
-static int (*func_to_cil[SYM_NUM])(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack, char *key, void *datum, int scope) = {
- NULL, // commons, only stored in the global symtab, handled elsewhere
- class_to_cil,
- role_to_cil,
- type_to_cil,
- user_to_cil,
- boolean_to_cil,
- sens_to_cil,
- cat_to_cil
-};
-
-static int typealiases_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack)
-{
- struct type_datum *alias_datum;
- char *alias_name;
- struct list_node *curr;
- struct avrule_decl *decl = stack_peek(decl_stack);
- struct list *alias_list = typealias_lists[decl->decl_id];
- int rc = -1;
-
- if (alias_list == NULL) {
- return 0;
- }
-
- for (curr = alias_list->head; curr != NULL; curr = curr->next) {
- alias_name = curr->data;
- alias_datum = hashtab_search(pdb->p_types.table, alias_name);
- if (alias_datum == NULL) {
- rc = -1;
- goto exit;
- }
-
- cil_println(indent, "(typealias %s)", alias_name);
- cil_println(indent, "(typealiasactual %s %s)", alias_name, pdb->p_type_val_to_name[alias_datum->s.value - 1]);
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int declared_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
-{
- int rc = -1;
- struct ebitmap map;
- struct ebitmap_node *node;
- unsigned int i;
- char * key;
- struct scope_datum *scope;
- int sym;
- void *datum;
- struct avrule_decl *decl = stack_peek(decl_stack);
-
- for (sym = 0; sym < SYM_NUM; sym++) {
- if (func_to_cil[sym] == NULL) {
- continue;
- }
-
- map = decl->declared.scope[sym];
- ebitmap_for_each_bit(&map, node, i) {
- if (!ebitmap_get_bit(&map, i)) {
- continue;
- }
- key = pdb->sym_val_to_name[sym][i];
- datum = hashtab_search(pdb->symtab[sym].table, key);
- if (datum == NULL) {
- rc = -1;
- goto exit;
- }
- scope = hashtab_search(pdb->scope[sym].table, key);
- if (scope == NULL) {
- rc = -1;
- goto exit;
- }
- rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, scope->scope);
- if (rc != 0) {
- goto exit;
- }
- }
-
- if (sym == SYM_CATS) {
- rc = cat_order_to_cil(indent, pdb, map);
- if (rc != 0) {
- goto exit;
- }
- }
-
- if (sym == SYM_LEVELS) {
- rc = sens_order_to_cil(indent, pdb, map);
- if (rc != 0) {
- goto exit;
- }
- }
-
- if (sym == SYM_CLASSES) {
- rc = class_order_to_cil(indent, pdb, map);
- if (rc != 0) {
- goto exit;
- }
- }
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int required_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
-{
- int rc = -1;
- struct ebitmap map;
- struct ebitmap_node *node;
- unsigned int i;
- unsigned int j;
- char * key;
- int sym;
- void *datum;
- struct avrule_decl *decl = stack_peek(decl_stack);
- struct scope_datum *scope_datum;
-
- for (sym = 0; sym < SYM_NUM; sym++) {
- if (func_to_cil[sym] == NULL) {
- continue;
- }
-
- map = decl->required.scope[sym];
- ebitmap_for_each_bit(&map, node, i) {
- if (!ebitmap_get_bit(&map, i)) {
- continue;
- }
- key = pdb->sym_val_to_name[sym][i];
-
- scope_datum = hashtab_search(pdb->scope[sym].table, key);
- for (j = 0; j < scope_datum->decl_ids_len; j++) {
- if (scope_datum->decl_ids[j] == decl->decl_id) {
- break;
- }
- }
- if (j >= scope_datum->decl_ids_len) {
- // Symbols required in the global scope are also in the
- // required scope ebitmap of all avrule decls (i.e. required
- // in all optionals). So we need to look at the scopes of each
- // symbol in this avrule_decl to determine if it actually is
- // required in this decl, or if it's just required in the
- // global scope. If we got here, then this symbol is not
- // actually required in this scope, so skip it.
- continue;
- }
-
- datum = hashtab_search(pdb->symtab[sym].table, key);
- if (datum == NULL) {
- rc = -1;
- goto exit;
- }
- rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, SCOPE_REQ);
- if (rc != 0) {
- goto exit;
- }
- }
- }
-
- return 0;
-exit:
- return rc;
-}
-
-
-static int additive_scopes_to_cil_map(char *key, void *data, void *arg)
-{
- int rc = -1;
- struct map_args *args = arg;
-
- rc = func_to_cil[args->sym_index](args->indent, args->pdb, args->block, args->decl_stack, key, data, SCOPE_REQ);
- if (rc != 0) {
- goto exit;
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
-{
- int rc = -1;
- struct map_args args;
- args.pdb = pdb;
- args.block = block;
- args.decl_stack = decl_stack;
- args.indent = indent;
- struct avrule_decl *decl = stack_peek(decl_stack);
-
- for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) {
- rc = hashtab_map(decl->symtab[args.sym_index].table, additive_scopes_to_cil_map, &args);
- if (rc != 0) {
- goto exit;
- }
- }
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int is_scope_superset(struct scope_index *sup, struct scope_index *sub)
-{
- // returns 1 if sup is a superset of sub, returns 0 otherwise
-
- int rc = 0;
-
- uint32_t i;
- struct ebitmap sup_map;
- struct ebitmap sub_map;
- struct ebitmap res;
-
- ebitmap_init(&res);
-
- for (i = 0; i < SYM_NUM; i++) {
- sup_map = sup->scope[i];
- sub_map = sub->scope[i];
-
- ebitmap_and(&res, &sup_map, &sub_map);
- if (!ebitmap_cmp(&res, &sub_map)) {
- goto exit;
- }
- ebitmap_destroy(&res);
- }
-
- if (sup->class_perms_len < sub->class_perms_len) {
- goto exit;
- }
-
- for (i = 0; i < sub->class_perms_len; i++) {
- sup_map = sup->class_perms_map[i];
- sub_map = sub->class_perms_map[i];
-
- ebitmap_and(&res, &sup_map, &sub_map);
- if (!ebitmap_cmp(&res, &sub_map)) {
- goto exit;
- }
- ebitmap_destroy(&res);
- }
-
- rc = 1;
-
-exit:
-
- ebitmap_destroy(&res);
- return rc;
-}
-
-static int blocks_to_cil(struct policydb *pdb)
-{
- int rc = -1;
- struct avrule_block *block;
- struct avrule_decl *decl;
- struct avrule_decl *decl_tmp;
- int indent = 0;
- struct stack *stack;
- struct list *attr_list;
-
- rc = stack_init(&stack);
- if (rc != 0) {
- goto exit;
- }
-
- for (block = pdb->global; block != NULL; block = block->next) {
- rc = list_init(&attr_list);
- if (rc != 0) {
- goto exit;
- }
-
- decl = block->branch_list;
- if (decl == NULL) {
- continue;
- }
-
- if (decl->next != NULL) {
- log_err("Warning: 'else' blocks in optional statements are unsupported in CIL. Dropping from output.");
- }
-
- if (block->flags & AVRULE_OPTIONAL) {
- while (stack->pos > 0) {
- decl_tmp = stack_peek(stack);
- if (is_scope_superset(&decl->required, &decl_tmp->required)) {
- break;
- }
-
- stack_pop(stack);
- indent--;
- cil_println(indent, ")");
- }
-
- cil_println(indent, "(optional %s_optional_%i", pdb->name, decl->decl_id);
- indent++;
- }
-
- stack_push(stack, decl);
-
- if (stack->pos == 0) {
- // type aliases and commons are only stored in the global symtab.
- // However, to get scoping correct, we assume they are in the
- // global block
- struct map_args args;
- args.pdb = pdb;
- args.block = block;
- args.decl_stack = stack;
- args.indent = 0;
- args.scope = SCOPE_DECL;
-
- rc = hashtab_map(pdb->p_commons.table, common_to_cil, &args);
- if (rc != 0) {
- goto exit;
- }
- }
-
- rc = typealiases_to_cil(indent, pdb, block, stack);
- if (rc != 0) {
- goto exit;
- }
-
- rc = declared_scopes_to_cil(indent, pdb, block, stack);
- if (rc != 0) {
- goto exit;
- }
-
- rc = required_scopes_to_cil(indent, pdb, block, stack);
- if (rc != 0) {
- goto exit;
- }
-
- rc = additive_scopes_to_cil(indent, pdb, block, stack);
- if (rc != 0) {
- goto exit;
- }
-
- rc = avrule_list_to_cil(indent, pdb, decl->avrules, attr_list);
- if (rc != 0) {
- goto exit;
- }
-
- rc = role_trans_to_cil(indent, pdb, decl->role_tr_rules);
- if (rc != 0) {
- goto exit;
- }
-
- rc = role_allows_to_cil(indent, pdb, decl->role_allow_rules);
- if (rc != 0) {
- goto exit;
- }
-
- rc = range_trans_to_cil(indent, pdb, decl->range_tr_rules);
- if (rc != 0) {
- goto exit;
- }
-
- rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules);
- if (rc != 0) {
- goto exit;
- }
-
- rc = cond_list_to_cil(indent, pdb, decl->cond_list);
- if (rc != 0) {
- goto exit;
- }
-
- rc = cil_print_attr_list(indent, pdb, attr_list);
- if (rc != 0) {
- goto exit;
- }
- attr_list_destroy(&attr_list);
- }
-
- while (indent > 0) {
- indent--;
- cil_println(indent, ")");
- }
-
- rc = 0;
-
-exit:
- stack_destroy(&stack);
- attr_list_destroy(&attr_list);
-
- return rc;
-}
-
-static int handle_unknown_to_cil(struct policydb *pdb)
-{
- int rc = -1;
- const char *hu;
-
- switch (pdb->handle_unknown) {
- case SEPOL_DENY_UNKNOWN:
- hu = "deny";
- break;
- case SEPOL_REJECT_UNKNOWN:
- hu = "reject";
- break;
- case SEPOL_ALLOW_UNKNOWN:
- hu = "allow";
- break;
- default:
- log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
- rc = -1;
- goto exit;
- }
-
- cil_println(0, "(handleunknown %s)", hu);
-
- return 0;
-
-exit:
- return rc;
-}
-
-static int generate_mls(struct policydb *pdb)
-{
- const char *mls_str = pdb->mls ? "true" : "false";
- cil_println(0, "(mls %s)", mls_str);
-
- return 0;
-}
-
-static int generate_default_level(void)
-{
- cil_println(0, "(sensitivity s0)");
- cil_println(0, "(sensitivityorder (s0))");
- cil_println(0, "(level " DEFAULT_LEVEL " (s0))");
-
- return 0;
-}
-
-static int generate_default_object(void)
-{
- cil_println(0, "(role " DEFAULT_OBJECT ")");
-
- return 0;
-}
-
-static int generate_gen_require_attribute(void)
-{
- cil_println(0, "(typeattribute " GEN_REQUIRE_ATTR ")");
- cil_println(0, "(roleattribute " GEN_REQUIRE_ATTR ")");
-
- return 0;
-}
-
-static int fix_module_name(struct policydb *pdb)
-{
- char *letter;
- int rc = -1;
-
- // The base module doesn't have its name set, but we use that for some
- // autogenerated names, like optionals and attributes, to prevent naming
- // collisions. However, they sometimes need to be fixed up.
-
- // the base module isn't given a name, so just call it "base"
- if (pdb->policy_type == POLICY_BASE) {
- pdb->name = strdup("base");
- if (pdb->name == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- }
-
- // CIL is more restrictive in module names than checkmodule. Convert bad
- // characters to underscores
- for (letter = pdb->name; *letter != '\0'; letter++) {
- if (isalnum(*letter)) {
- continue;
- }
-
- *letter = '_';
- }
-
- return 0;
-exit:
- return rc;
-}
-
-static int module_package_to_cil(struct sepol_module_package *mod_pkg)
-{
- int rc = -1;
- struct sepol_policydb *pdb;
-
- pdb = sepol_module_package_get_policy(mod_pkg);
- if (pdb == NULL) {
- log_err("Failed to get policydb");
- rc = -1;
- goto exit;
- }
-
- if (pdb->p.policy_type != SEPOL_POLICY_BASE &&
- pdb->p.policy_type != SEPOL_POLICY_MOD) {
- log_err("Policy pakcage is not a base or module");
- rc = -1;
- goto exit;
- }
-
- rc = fix_module_name(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- if (pdb->p.policy_type == SEPOL_POLICY_BASE && !pdb->p.mls) {
- // If this is a base non-mls policy, we need to define a default level
- // range that can be used for contexts by other non-mls modules, since
- // CIL requires that all contexts have a range, even if they are
- // ignored as in non-mls policies
- rc = generate_default_level();
- if (rc != 0) {
- goto exit;
- }
- }
-
- if (pdb->p.policy_type == SEPOL_POLICY_BASE) {
- // object_r is implicit in checkmodule, but not with CIL, create it
- // as part of base
- rc = generate_default_object();
- if (rc != 0) {
- goto exit;
- }
-
- // default attribute to be used to mimic gen_require in CIL
- rc = generate_gen_require_attribute();
- if (rc != 0) {
- goto exit;
- }
-
- // handle_unknown is used from only the base module
- rc = handle_unknown_to_cil(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- // mls is used from only the base module
- rc = generate_mls(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
- }
-
- rc = role_list_create(pdb->p.p_roles.table);
- if (rc != 0) {
- goto exit;
- }
-
- rc = typealias_list_create(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- rc = polcaps_to_cil(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- rc = ocontexts_to_cil(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- rc = genfscon_to_cil(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- rc = seusers_to_cil(mod_pkg);
- if (rc != 0) {
- goto exit;
- }
-
- rc = netfilter_contexts_to_cil(mod_pkg);
- if (rc != 0) {
- goto exit;
- }
-
- rc = user_extra_to_cil(mod_pkg);
- if (rc != 0) {
- goto exit;
- }
-
- rc = file_contexts_to_cil(mod_pkg);
- if (rc != 0) {
- goto exit;
- }
-
- // now print everything that is scoped
- rc = blocks_to_cil(&pdb->p);
- if (rc != 0) {
- goto exit;
- }
-
- rc = 0;
-
-exit:
- role_list_destroy();
- typealias_list_destroy();
-
- return rc;
-}
-
-static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
-{
- int rc = -1;
- char *d = NULL;
- size_t d_len = 0;
- size_t read_len = 0;
- size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
-
- d = malloc(max_len);
- if (d == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
-
- while ((read_len = fread(d + d_len, 1, max_len - d_len, fp)) > 0) {
- d_len += read_len;
- if (d_len == max_len) {
- max_len *= 2;
- d = realloc(d, max_len);
- if (d == NULL) {
- log_err("Out of memory");
- rc = -1;
- goto exit;
- }
- }
- }
-
- if (ferror(fp) != 0) {
- log_err("Failed to read pp file");
- rc = -1;
- goto exit;
- }
-
- *data = d;
- *data_len = d_len;
-
- return 0;
-
-exit:
- free(d);
- return rc;
-}
-
-static int ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
-{
- int rc = -1;
- FILE *f = NULL;
- struct sepol_policy_file *pf = NULL;
- struct sepol_module_package *pkg = NULL;
- char *data = NULL;
- size_t data_len;
- int fd;
- struct stat sb;
-
- rc = sepol_policy_file_create(&pf);
- if (rc != 0) {
- log_err("Failed to create policy file");
- goto exit;
- }
-
- fd = fileno(fp);
- if (fstat(fd, &sb) == -1) {
- rc = -1;
- goto exit;
- }
-
- if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
- // libsepol fails when trying to read a policy package from a pipe or a
- // socket due its use of lseek. In this case, read the data into a
- // buffer and provide that to libsepol
- rc = fp_to_buffer(fp, &data, &data_len);
- if (rc != 0) {
- goto exit;
- }
-
- sepol_policy_file_set_mem(pf, data, data_len);
- } else {
- sepol_policy_file_set_fp(pf, fp);
- }
-
- rc = sepol_module_package_create(&pkg);
- if (rc != 0) {
- log_err("Failed to create module package");
- goto exit;
- }
-
- rc = sepol_module_package_read(pkg, pf, 0);
- if (rc != 0) {
- log_err("Failed to read policy package");
- goto exit;
- }
-
- *mod_pkg = pkg;
-
-exit:
- free(data);
-
- sepol_policy_file_free(pf);
- if (f != NULL) {
- fclose(f);
- }
-
- if (rc != 0) {
- sepol_module_package_free(pkg);
- }
-
- return rc;
-}
-
static void usage(int err)
{
fprintf(stderr, "Usage: %s [OPTIONS] [IN_FILE [OUT_FILE]]\n", progname);
@@ -3932,21 +109,20 @@ int main(int argc, char **argv)
} else {
out = stdout;
}
- out_file = out;
if (argc >= optind + 3) {
log_err("Too many arguments");
usage(1);
}
- rc = ppfile_to_module_package(in, &mod_pkg);
+ rc = sepol_ppfile_to_module_package(in, &mod_pkg);
if (rc != 0) {
goto exit;
}
fclose(in);
in = NULL;
- rc = module_package_to_cil(mod_pkg);
+ rc = sepol_module_package_to_cil(out, mod_pkg);
if (rc != 0) {
goto exit;
}
--
1.9.3
^ permalink raw reply related [flat|nested] 11+ messages in thread