@@ -275,6 +275,15 @@ int main(int argc, char **argv)
modpolicydb.mls = mlspol;
modpolicydb.handle_unknown = handle_unknown;
+ /*
+ * Init and alloc te_avtab for filename transition duplicate
+ * checking
+ */
+ if (avtab_init(&modpolicydb.te_avtab))
+ exit(1);
+ if (avtab_alloc(&modpolicydb.te_avtab, 1 << 11))
+ exit(1);
+
if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
exit(1);
}
@@ -611,6 +611,15 @@ int main(int argc, char **argv)
parse_policy.mls = mlspol;
parse_policy.handle_unknown = handle_unknown;
+ /*
+ * Init and alloc te_avtab for filename transition duplicate
+ * checking
+ */
+ if (avtab_init(&parse_policy.te_avtab))
+ exit(1);
+ if (avtab_alloc(&parse_policy.te_avtab, 1 << 11))
+ exit(1);
+
policydbp = &parse_policy;
if (read_source_policy(policydbp, file, "checkpolicy") < 0)
@@ -3352,6 +3352,7 @@ int define_filename_trans(void)
ebitmap_node_t *snode, *tnode, *cnode;
filename_trans_rule_t *ftr;
type_datum_t *typdatum;
+ avtab_key_t avt_key;
uint32_t otype;
unsigned int c, s, t;
int add, self, rc;
@@ -3443,9 +3444,13 @@ int define_filename_trans(void)
ebitmap_for_each_positive_bit(&e_tclasses, cnode, c) {
ebitmap_for_each_positive_bit(&e_stypes, snode, s) {
ebitmap_for_each_positive_bit(&e_ttypes, tnode, t) {
- rc = policydb_filetrans_insert(
- policydbp, s+1, t+1, c+1, name,
- NULL, otype, NULL
+ avt_key.specified = AVTAB_TRANSITION;
+ avt_key.source_type = s + 1;
+ avt_key.target_type = t + 1;
+ avt_key.target_class = c + 1;
+ rc = avtab_insert_filename_trans(
+ &policydbp->te_avtab, &avt_key, otype,
+ name, NULL
);
if (rc != SEPOL_OK) {
if (rc == SEPOL_EEXIST) {
@@ -3461,9 +3466,13 @@ int define_filename_trans(void)
}
}
if (self) {
- rc = policydb_filetrans_insert(
- policydbp, s+1, s+1, c+1, name,
- NULL, otype, NULL
+ avt_key.specified = AVTAB_TRANSITION;
+ avt_key.source_type = s + 1;
+ avt_key.target_type = t + 1;
+ avt_key.target_class = c + 1;
+ rc = avtab_insert_filename_trans(
+ &policydbp->te_avtab, &avt_key, otype,
+ name, NULL
);
if (rc != SEPOL_OK) {
if (rc == SEPOL_EEXIST) {
@@ -63,7 +63,6 @@ static struct command {
{CMD, 'a', "display type attributes"},
{CMD, 'p', "display the list of permissive types"},
{CMD, 'u', "display unknown handling setting"},
- {CMD, 'F', "display filename_trans rules"},
{HEADER, 0, ""},
{CMD|NOOPT, 'f', "set output file"},
{CMD|NOOPT, 'm', "display menu"},
@@ -126,6 +125,26 @@ static int render_key(avtab_key_t * key, policydb_t * p, FILE * fp)
return 0;
}
+typedef struct {
+ avtab_key_t *key;
+ policydb_t *p;
+ FILE *fp;
+} render_name_trans_args_t;
+
+static int render_name_trans_helper(hashtab_key_t k, hashtab_datum_t d, void *a)
+{
+ char *name = k;
+ uint32_t *otype = d;
+ render_name_trans_args_t *args = a;
+
+ fprintf(args->fp, "type_transition ");
+ render_key(args->key, args->p, args->fp);
+ render_type(*otype, args->p, args->fp);
+ fprintf(args->fp, " \"%s\";\n", name);
+
+ return 0;
+}
+
/* 'what' values for this function */
#define RENDER_UNCONDITIONAL 0x0001 /* render all regardless of enabled state */
#define RENDER_ENABLED 0x0002
@@ -178,10 +197,19 @@ static int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t wha
}
} else if (key->specified & AVTAB_TYPE) {
if (key->specified & AVTAB_TRANSITION) {
- fprintf(fp, "type_transition ");
- render_key(key, p, fp);
- render_type(datum->trans->otype, p, fp);
- fprintf(fp, ";\n");
+ if (datum->trans->otype) {
+ fprintf(fp, "type_transition ");
+ render_key(key, p, fp);
+ render_type(datum->trans->otype, p, fp);
+ fprintf(fp, ";\n");
+ }
+ render_name_trans_args_t args = {
+ .key = key,
+ .p = p,
+ .fp = fp,
+ };
+ hashtab_map(datum->trans->name_trans.table,
+ render_name_trans_helper, &args);
}
if (key->specified & AVTAB_MEMBER) {
fprintf(fp, "type_member ");
@@ -448,48 +476,6 @@ static void display_role_trans(policydb_t *p, FILE *fp)
}
}
-struct filenametr_display_args {
- policydb_t *p;
- FILE *fp;
-};
-
-static int filenametr_display(hashtab_key_t key,
- hashtab_datum_t datum,
- void *ptr)
-{
- struct filename_trans_key *ft = (struct filename_trans_key *)key;
- struct filename_trans_datum *ftdatum = datum;
- struct filenametr_display_args *args = ptr;
- policydb_t *p = args->p;
- FILE *fp = args->fp;
- ebitmap_node_t *node;
- uint32_t bit;
-
- do {
- ebitmap_for_each_positive_bit(&ftdatum->stypes, node, bit) {
- display_id(p, fp, SYM_TYPES, bit, "");
- display_id(p, fp, SYM_TYPES, ft->ttype - 1, "");
- display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":");
- display_id(p, fp, SYM_TYPES, ftdatum->otype - 1, "");
- fprintf(fp, " %s\n", ft->name);
- }
- ftdatum = ftdatum->next;
- } while (ftdatum);
-
- return 0;
-}
-
-
-static void display_filename_trans(policydb_t *p, FILE *fp)
-{
- struct filenametr_display_args args;
-
- fprintf(fp, "filename_trans rules:\n");
- args.p = p;
- args.fp = fp;
- hashtab_map(p->filename_trans, filenametr_display, &args);
-}
-
static int menu(void)
{
unsigned int i;
@@ -690,9 +676,6 @@ int main(int argc, char **argv)
if (out_fp != stdout)
printf("\nOutput to file: %s\n", OutfileName);
break;
- case 'F':
- display_filename_trans(&policydb, out_fp);
- break;
case 'q':
policydb_destroy(&policydb);
exit(0);
@@ -1005,7 +1005,12 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src,
}
existing = avtab_search_node(&pdb->te_avtab, &avtab_key);
- if (existing) {
+ /*
+ * There might be empty transition node containing filename transitions
+ * only. That is okay, we can merge them later.
+ */
+ if (existing && !(existing->key.specified & AVTAB_TRANSITION &&
+ !existing->datum.trans->otype)) {
/* Don't add duplicate type rule and warn if they conflict.
* A warning should have been previously given if there is a
* non-duplicate rule using the same key.
@@ -1029,7 +1034,13 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src,
}
if (!cond_node) {
- rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum);
+ /* If we have node from empty filename transition, use it */
+ if (existing && existing->key.specified & AVTAB_TRANSITION &&
+ !existing->datum.trans->otype)
+ existing->datum.trans->otype = avtab_datum.trans->otype;
+ else
+ rc = avtab_insert(&pdb->te_avtab, &avtab_key,
+ &avtab_datum);
} else {
existing = avtab_search_node(&pdb->te_cond_avtab, &avtab_key);
if (existing) {
@@ -1189,16 +1200,18 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb,
class_datum_t *sepol_obj = NULL;
uint32_t otype;
struct cil_list_item *c;
+ avtab_key_t avt_key;
cil_list_for_each(c, class_list) {
rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
if (rc != SEPOL_OK) return rc;
- rc = policydb_filetrans_insert(
- pdb, sepol_src->s.value, sepol_tgt->s.value,
- sepol_obj->s.value, name, NULL,
- sepol_result->s.value, &otype
- );
+ avt_key.specified = AVTAB_TRANSITION;
+ avt_key.source_type = sepol_src->s.value;
+ avt_key.target_type = sepol_tgt->s.value;
+ avt_key.target_class = sepol_obj->s.value;
+ rc = avtab_insert_filename_trans(&pdb->te_avtab, &avt_key,
+ sepol_result->s.value, name, &otype);
if (rc != SEPOL_OK) {
if (rc == SEPOL_EEXIST) {
if (sepol_result->s.value!= otype) {
@@ -42,6 +42,7 @@
#include <sys/types.h>
#include <stdint.h>
+#include <sepol/policydb/symtab.h>
#ifdef __cplusplus
extern "C" {
@@ -72,6 +73,7 @@ typedef struct avtab_key {
typedef struct avtab_trans {
uint32_t otype; /* resulting type of the new object */
+ symtab_t name_trans; /* filename transitions */
} avtab_trans_t;
typedef struct avtab_extended_perms {
@@ -115,6 +117,8 @@ extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d);
extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k);
+extern void avtab_trans_destroy(avtab_trans_t *trans);
+
extern void avtab_destroy(avtab_t * h);
extern int avtab_map(const avtab_t * h,
@@ -148,6 +152,11 @@ extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
/* avtab_alloc uses one bucket per 2-4 elements, so adjust to get maximum buckets */
#define MAX_AVTAB_SIZE (MAX_AVTAB_HASH_BUCKETS << 1)
+extern int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
+ uint32_t otype, const char *name,
+ uint32_t *present_otype);
+extern int avtab_filename_trans_read(void *fp, uint32_t vers, avtab_t *a);
+
#ifdef __cplusplus
}
#endif
@@ -110,6 +110,14 @@ extern int hashtab_map(hashtab_t h,
extern void hashtab_hash_eval(hashtab_t h, char *tag);
+/* Returns number of elements in the hashtab h or 0 is h is NULL */
+static inline uint32_t hashtab_nel(hashtab_t h)
+{
+ if (!h)
+ return 0;
+ return h->nel;
+}
+
#ifdef __cplusplus
}
#endif
@@ -161,19 +161,6 @@ typedef struct role_allow {
struct role_allow *next;
} role_allow_t;
-/* filename_trans rules */
-typedef struct filename_trans_key {
- uint32_t ttype;
- uint32_t tclass;
- char *name;
-} filename_trans_key_t;
-
-typedef struct filename_trans_datum {
- ebitmap_t stypes;
- uint32_t otype;
- struct filename_trans_datum *next;
-} filename_trans_datum_t;
-
/* Type attributes */
typedef struct type_datum {
symtab_datum_t s;
@@ -592,10 +579,6 @@ typedef struct policydb {
/* range transitions table (range_trans_key -> mls_range) */
hashtab_t range_tr;
- /* file transitions with the last path component */
- hashtab_t filename_trans;
- uint32_t filename_trans_count;
-
ebitmap_t *type_attr_map;
ebitmap_t *attr_type_map; /* not saved in the binary policy */
@@ -654,11 +637,6 @@ extern int policydb_load_isids(policydb_t * p, sidtab_t * s);
extern int policydb_sort_ocontexts(policydb_t *p);
-extern int policydb_filetrans_insert(policydb_t *p, uint32_t stype,
- uint32_t ttype, uint32_t tclass,
- const char *name, char **name_alloc,
- uint32_t otype, uint32_t *present_otype);
-
/* Deprecated */
extern int policydb_context_isvalid(const policydb_t * p,
const context_struct_t * c);
@@ -315,6 +315,20 @@ avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified)
return NULL;
}
+static int avtab_trans_destroy_helper(hashtab_key_t k, hashtab_datum_t d,
+ void *a __attribute__ ((unused)))
+{
+ free(k);
+ free(d);
+ return 0;
+}
+
+void avtab_trans_destroy(avtab_trans_t *trans)
+{
+ hashtab_map(trans->name_trans.table, avtab_trans_destroy_helper, NULL);
+ symtab_destroy(&trans->name_trans);
+}
+
void avtab_destroy(avtab_t * h)
{
unsigned int i;
@@ -329,6 +343,7 @@ void avtab_destroy(avtab_t * h)
if (cur->key.specified & AVTAB_XPERMS) {
free(cur->datum.xperms);
} else if (cur->key.specified & AVTAB_TRANSITION) {
+ avtab_trans_destroy(cur->datum.trans);
free(cur->datum.trans);
}
temp = cur;
@@ -660,3 +675,187 @@ int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers)
avtab_destroy(a);
return -1;
}
+
+/* policydb filename transition compatibility */
+
+int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
+ uint32_t otype, const char *name,
+ uint32_t *present_otype)
+{
+ int rc = SEPOL_ENOMEM;
+ avtab_trans_t new_trans = {0};
+ avtab_datum_t new_datum = {.trans = &new_trans};
+ avtab_datum_t *datum;
+ avtab_ptr_t node;
+ char *name_key = NULL;
+ uint32_t *otype_datum = NULL;
+
+ datum = avtab_search(a, key);
+ if (!datum) {
+ /*
+ * insert is actually unique, but with this function we can get
+ * the inserted node and therefore the datum
+ */
+ node = avtab_insert_nonunique(a, key, &new_datum);
+ if (!node)
+ return SEPOL_ENOMEM;
+ datum = &node->datum;
+ }
+
+ if (!datum->trans->name_trans.table) {
+ rc = symtab_init(&datum->trans->name_trans, 1 << 8);
+ if (rc < 0)
+ return rc;
+ }
+
+ rc = SEPOL_ENOMEM;
+ name_key = strdup(name);
+ if (!name_key)
+ goto bad;
+
+ rc = SEPOL_ENOMEM;
+ otype_datum = malloc(sizeof(*otype_datum));
+ if (!otype_datum)
+ goto bad;
+ *otype_datum = otype;
+
+ rc = hashtab_insert(datum->trans->name_trans.table, name_key,
+ otype_datum);
+ if (rc < 0)
+ goto bad;
+
+ return SEPOL_OK;
+
+bad:
+ free(name_key);
+ free(otype_datum);
+ if (rc == SEPOL_EEXIST && present_otype) {
+ otype_datum = hashtab_search(datum->trans->name_trans.table,
+ name);
+ if (otype_datum)
+ *present_otype = *otype_datum;
+ }
+ return rc;
+}
+
+static int filename_trans_read_one(avtab_t *a, void *fp)
+{
+ int rc;
+ uint32_t buf[4], len, otype;
+ char *name = NULL;
+ avtab_key_t key;
+
+ /* read length of the name and the name */
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return SEPOL_ERR;
+ len = le32_to_cpu(*buf);
+ rc = str_read(&name, fp, len);
+ if (rc < 0)
+ return SEPOL_ERR;
+
+ /* read stype, ttype, tclass and otype */
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+ if (rc < 0)
+ goto err;
+
+ key.specified = AVTAB_TRANSITION;
+ key.source_type = le32_to_cpu(buf[0]);
+ key.target_type = le32_to_cpu(buf[1]);
+ key.target_class = le32_to_cpu(buf[2]);
+ otype = le32_to_cpu(buf[3]);
+
+ rc = avtab_insert_filename_trans(a, &key, otype, name, NULL);
+ if (rc)
+ goto err;
+
+ free(name);
+ return SEPOL_OK;
+err:
+ free(name);
+ return SEPOL_ERR;
+}
+
+static int filename_trans_comp_read_one(avtab_t *a, void *fp)
+{
+ int rc;
+ uint32_t buf[3], len, ndatum, i, bit, otype;
+ char *name = NULL;
+ avtab_key_t key;
+ ebitmap_t stypes;
+ ebitmap_node_t *node;
+
+ /* read length of the name and the name */
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return SEPOL_ERR;
+ len = le32_to_cpu(*buf);
+ rc = str_read(&name, fp, len);
+ if (rc < 0)
+ return SEPOL_ERR;
+
+ /* read ttype, tclass, ndatum */
+ rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+ if (rc < 0)
+ goto err;
+
+ key.specified = AVTAB_TRANSITION;
+ key.target_type = le32_to_cpu(buf[0]);
+ key.target_class = le32_to_cpu(buf[1]);
+
+ ndatum = le32_to_cpu(buf[2]);
+ for (i = 0; i < ndatum; i++) {
+ rc = ebitmap_read(&stypes, fp);
+ if (rc < 0)
+ goto err;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ goto err_ebitmap;
+ otype = le32_to_cpu(*buf);
+
+ ebitmap_for_each_positive_bit(&stypes, node, bit) {
+ key.source_type = bit + 1;
+
+ rc = avtab_insert_filename_trans(a, &key, otype, name,
+ NULL);
+ if (rc < 0)
+ goto err_ebitmap;
+ }
+ }
+
+ free(name);
+ return SEPOL_OK;
+
+err_ebitmap:
+ ebitmap_destroy(&stypes);
+err:
+ free(name);
+ return rc;
+}
+
+int avtab_filename_trans_read(void *fp, uint32_t vers, avtab_t *a)
+{
+ uint32_t buf[1], nel, i;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(uint32_t));
+ if (rc < 0)
+ return rc;
+ nel = le32_to_cpu(*buf);
+
+ if (vers < POLICYDB_VERSION_COMP_FTRANS) {
+ for (i = 0; i < nel; i++) {
+ rc = filename_trans_read_one(a, fp);
+ if (rc < 0)
+ return rc;
+ }
+ } else {
+ for (i = 0; i < nel; i++) {
+ rc = filename_trans_comp_read_one(a, fp);
+ if (rc < 0)
+ return rc;
+ }
+ }
+ return SEPOL_OK;
+}
@@ -624,6 +624,7 @@ static int cond_insertf(avtab_t * a
struct policydb *p = data->p;
cond_av_list_t *other = data->other, *list, *cur;
avtab_ptr_t node_ptr;
+ avtab_datum_t *existing;
uint8_t found;
/*
@@ -632,7 +633,10 @@ static int cond_insertf(avtab_t * a
* cond_te_avtab.
*/
if (k->specified & AVTAB_TYPE) {
- if (avtab_search(&p->te_avtab, k)) {
+ existing = avtab_search(&p->te_avtab, k);
+ /* empty transition rule is not a conflict */
+ if (existing && !(k->specified & AVTAB_TRANSITION
+ && !existing->trans->otype)) {
WARN(NULL, "security: type rule already exists outside of a conditional.");
return -1;
}
@@ -1413,14 +1413,17 @@ static int expand_filename_trans_helper(expand_state_t *state,
{
uint32_t mapped_otype, present_otype;
int rc;
+ avtab_key_t avt_key;
mapped_otype = state->typemap[rule->otype - 1];
- rc = policydb_filetrans_insert(
- state->out, s + 1, t + 1,
- rule->tclass, rule->name,
- NULL, mapped_otype, &present_otype
- );
+ avt_key.specified = AVTAB_TRANSITION;
+ avt_key.source_type = s + 1;
+ avt_key.target_type = t + 1;
+ avt_key.target_class = rule->tclass;
+
+ rc = avtab_insert_filename_trans(&state->out->te_avtab, &avt_key,
+ mapped_otype, rule->name, &present_otype);
if (rc == SEPOL_EEXIST) {
/* duplicate rule, ignore */
if (present_otype == mapped_otype)
@@ -1734,6 +1737,16 @@ static int expand_terule_helper(sepol_handle_t * handle,
* either in the global scope or in another
* conditional AV tab */
node = avtab_search_node(&p->te_avtab, &avkey);
+
+ /*
+ * if node does not already contain transition, it is not a
+ * conflict and transition otype will be set to node found by
+ * find_avtab_node()
+ */
+ if (specified & AVRULE_TRANSITION && node &&
+ !node->datum.trans->otype)
+ node = NULL;
+
if (node) {
conflict = 1;
} else {
@@ -1741,6 +1754,10 @@ static int expand_terule_helper(sepol_handle_t * handle,
if (node && node->parse_context != other) {
conflict = 2;
}
+ /*
+ * conditional avtab does not contain filename
+ * transitions, no need to check for otype == 0
+ */
}
if (conflict) {
@@ -1702,14 +1702,24 @@ static char *xperms_to_str(avtab_extended_perms_t *xperms)
return xpermsbuf;
}
-static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum)
+static int name_trans_to_strs_helper(hashtab_key_t k, hashtab_datum_t d, void *a)
{
- uint32_t data = key->specified & AVTAB_TRANSITION
- ? datum->trans->otype : datum->data;
+ char *name = k;
+ uint32_t *otype = d;
+ name_trans_to_strs_args_t *args = a;
+ return strs_create_and_add(args->strs, "(%s %s %s %s \"%s\" %s)", 6,
+ args->flavor, args->src, args->tgt,
+ args->class, name,
+ args->pdb->p_type_val_to_name[*otype - 1]);
+}
+
+static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum, struct strs *strs)
+{
+ int rc = SEPOL_OK;
+ uint32_t data = datum->data;
type_datum_t *type;
const char *flavor, *tgt;
char *src, *class, *perms, *new;
- char *rule = NULL;
switch (0xFFF & key->specified) {
case AVTAB_ALLOWED:
@@ -1742,7 +1752,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
break;
default:
ERR(NULL, "Unknown avtab type: %i", key->specified);
- goto exit;
+ return SEPOL_ERR;
}
src = pdb->p_type_val_to_name[key->source_type - 1];
@@ -1759,33 +1769,44 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
perms = sepol_av_to_string(pdb, key->target_class, data);
if (perms == NULL) {
ERR(NULL, "Failed to generate permission string");
- goto exit;
+ return SEPOL_ERR;
}
- rule = create_str("(%s %s %s (%s (%s)))", 5,
- flavor, src, tgt, class, perms+1);
+ rc = strs_create_and_add(strs, "(%s %s %s (%s (%s)))", 5,
+ flavor, src, tgt, class, perms + 1);
} else if (key->specified & AVTAB_XPERMS) {
perms = xperms_to_str(datum->xperms);
if (perms == NULL) {
ERR(NULL, "Failed to generate extended permission string");
- goto exit;
+ return SEPOL_ERR;
}
- rule = create_str("(%s %s %s (%s %s (%s)))", 6,
- flavor, src, tgt, "ioctl", class, perms);
+ rc = strs_create_and_add(strs, "(%s %s %s (%s %s (%s)))", 6,
+ flavor, src, tgt, "ioctl", class, perms);
+ } else if (key->specified & AVTAB_TRANSITION) {
+ if (datum->trans->otype) {
+ rc = strs_create_and_add(strs, "(%s %s %s %s %s)", 5,
+ flavor, src, tgt, class,
+ pdb->p_type_val_to_name[datum->trans->otype - 1]);
+ if (rc < 0)
+ return rc;
+ }
+ name_trans_to_strs_args_t args = {
+ .pdb = pdb,
+ .strs = strs,
+ .flavor = flavor,
+ .src = src,
+ .tgt = tgt,
+ .class = class,
+ };
+ rc = hashtab_map(datum->trans->name_trans.table,
+ name_trans_to_strs_helper, &args);
} else {
new = pdb->p_type_val_to_name[data - 1];
- rule = create_str("(%s %s %s %s %s)", 5, flavor, src, tgt, class, new);
- }
-
- if (!rule) {
- goto exit;
+ rc = strs_create_and_add(strs, "(%s %s %s %s %s)", 5, flavor, src, tgt, class, new);
}
- return rule;
-
-exit:
- return NULL;
+ return rc;
}
struct map_avtab_args {
@@ -1800,23 +1821,12 @@ static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void *
uint32_t flavor = map_args->flavor;
struct policydb *pdb = map_args->pdb;
struct strs *strs = map_args->strs;
- char *rule;
int rc = 0;
if (key->specified & flavor) {
- rule = avtab_node_to_str(pdb, key, datum);
- if (!rule) {
- rc = -1;
- goto exit;
- }
- rc = strs_add(strs, rule);
- if (rc != 0) {
- free(rule);
- goto exit;
- }
+ rc = avtab_node_to_strs(pdb, key, datum, strs);
}
-exit:
return rc;
}
@@ -1870,77 +1880,6 @@ exit:
return rc;
}
-struct map_filename_trans_args {
- struct policydb *pdb;
- struct strs *strs;
-};
-
-static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
-{
- filename_trans_key_t *ft = (filename_trans_key_t *)key;
- filename_trans_datum_t *datum = data;
- struct map_filename_trans_args *map_args = arg;
- struct policydb *pdb = map_args->pdb;
- struct strs *strs = map_args->strs;
- char *src, *tgt, *class, *filename, *new;
- struct ebitmap_node *node;
- uint32_t bit;
- int rc;
-
- tgt = pdb->p_type_val_to_name[ft->ttype - 1];
- class = pdb->p_class_val_to_name[ft->tclass - 1];
- filename = ft->name;
- do {
- new = pdb->p_type_val_to_name[datum->otype - 1];
-
- ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
- src = pdb->p_type_val_to_name[bit];
- rc = strs_create_and_add(strs,
- "(typetransition %s %s %s \"%s\" %s)",
- 5, src, tgt, class, filename, new);
- if (rc)
- return rc;
- }
-
- datum = datum->next;
- } while (datum);
-
- return 0;
-}
-
-static int write_filename_trans_rules_to_cil(FILE *out, struct policydb *pdb)
-{
- struct map_filename_trans_args args;
- struct strs *strs;
- int rc = 0;
-
- rc = strs_init(&strs, 100);
- if (rc != 0) {
- goto exit;
- }
-
- args.pdb = pdb;
- args.strs = strs;
-
- rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
- if (rc != 0) {
- goto exit;
- }
-
- strs_sort(strs);
- strs_write_each(strs, out);
-
-exit:
- strs_free_all(strs);
- strs_destroy(&strs);
-
- if (rc != 0) {
- ERR(NULL, "Error writing filename typetransition rules to CIL");
- }
-
- return rc;
-}
-
static char *level_to_str(struct policydb *pdb, struct mls_level *level)
{
ebitmap_t *cats = &level->cat;
@@ -2060,7 +1999,6 @@ static int write_cond_av_list_to_cil(FILE *out, struct policydb *pdb, cond_av_li
avtab_key_t *key;
avtab_datum_t *datum;
struct strs *strs;
- char *rule;
unsigned i;
int rc;
@@ -2076,14 +2014,8 @@ static int write_cond_av_list_to_cil(FILE *out, struct policydb *pdb, cond_av_li
key = &node->key;
datum = &node->datum;
if (key->specified & flavor) {
- rule = avtab_node_to_str(pdb, key, datum);
- if (!rule) {
- rc = -1;
- goto exit;
- }
- rc = strs_add(strs, rule);
+ rc = avtab_node_to_strs(pdb, key, datum, strs);
if (rc != 0) {
- free(rule);
goto exit;
}
}
@@ -3331,11 +3263,6 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb)
goto exit;
}
- rc = write_filename_trans_rules_to_cil(out, pdb);
- if (rc != 0) {
- goto exit;
- }
-
if (pdb->mls) {
rc = write_range_trans_rules_to_cil(out, pdb);
if (rc != 0) {
@@ -83,6 +83,15 @@ struct strs {
size_t size;
};
+typedef struct {
+ policydb_t *pdb;
+ struct strs *strs;
+ const char *flavor;
+ const char *src;
+ const char *tgt;
+ const char *class;
+} name_trans_to_strs_args_t;
+
void sepol_indent(FILE *out, int indent);
__attribute__ ((format(printf, 2, 3)))
void sepol_printf(FILE *out, const char *fmt, ...);
@@ -1680,13 +1680,24 @@ exit:
return rc;
}
-static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum)
+static int name_trans_to_strs_helper(hashtab_key_t k, hashtab_datum_t d, void *a)
{
- uint32_t data = key->specified & AVTAB_TRANSITION
- ? datum->trans->otype : datum->data;
+ char *name = k;
+ uint32_t *otype = d;
+ name_trans_to_strs_args_t *args = a;
+ return strs_create_and_add(args->strs, "%s %s %s:%s %s \"%s\";", 6,
+ args->flavor, args->src, args->tgt,
+ args->class,
+ args->pdb->p_type_val_to_name[*otype - 1],
+ name);
+}
+
+static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum, struct strs *strs)
+{
+ int rc = SEPOL_OK;
+ uint32_t data = datum->data;
type_datum_t *type;
const char *flavor, *src, *tgt, *class, *perms, *new;
- char *rule = NULL;
switch (0xFFF & key->specified) {
case AVTAB_ALLOWED:
@@ -1719,7 +1730,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
break;
default:
ERR(NULL, "Unknown avtab type: %i", key->specified);
- goto exit;
+ return SEPOL_ERR;
}
src = pdb->p_type_val_to_name[key->source_type - 1];
@@ -1736,32 +1747,42 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
perms = sepol_av_to_string(pdb, key->target_class, data);
if (perms == NULL) {
ERR(NULL, "Failed to generate permission string");
- goto exit;
+ return SEPOL_ERR;
}
- rule = create_str("%s %s %s:%s { %s };", 5,
- flavor, src, tgt, class, perms+1);
+ rc = strs_create_and_add(strs, "%s %s %s:%s { %s };", 5,
+ flavor, src, tgt, class, perms + 1);
} else if (key->specified & AVTAB_XPERMS) {
perms = sepol_extended_perms_to_string(datum->xperms);
if (perms == NULL) {
ERR(NULL, "Failed to generate extended permission string");
- goto exit;
+ return SEPOL_ERR;
+ }
+ rc = strs_create_and_add(strs, "%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms);
+ } else if (key->specified & AVTAB_TRANSITION) {
+ if (datum->trans->otype) {
+ rc = strs_create_and_add(strs, "%s %s %s:%s %s;", 5,
+ flavor, src, tgt, class,
+ pdb->p_type_val_to_name[datum->trans->otype - 1]);
+ if (rc < 0)
+ return rc;
}
-
- rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms);
+ name_trans_to_strs_args_t args = {
+ .pdb = pdb,
+ .strs = strs,
+ .flavor = flavor,
+ .src = src,
+ .tgt = tgt,
+ .class = class,
+ };
+ rc = hashtab_map(datum->trans->name_trans.table,
+ name_trans_to_strs_helper, &args);
} else {
new = pdb->p_type_val_to_name[data - 1];
- rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, new);
+ rc = strs_create_and_add(strs, "%s %s %s:%s %s;", 5, flavor, src, tgt, class, new);
}
- if (!rule) {
- goto exit;
- }
-
- return rule;
-
-exit:
- return NULL;
+ return rc;
}
struct map_avtab_args {
@@ -1776,23 +1797,12 @@ static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void *
uint32_t flavor = map_args->flavor;
struct policydb *pdb = map_args->pdb;
struct strs *strs = map_args->strs;
- char *rule;
int rc = 0;
if (key->specified & flavor) {
- rule = avtab_node_to_str(pdb, key, datum);
- if (!rule) {
- rc = -1;
- goto exit;
- }
- rc = strs_add(strs, rule);
- if (rc != 0) {
- free(rule);
- goto exit;
- }
+ rc = avtab_node_to_strs(pdb, key, datum, strs);
}
-exit:
return rc;
}
@@ -1846,77 +1856,6 @@ exit:
return rc;
}
-struct map_filename_trans_args {
- struct policydb *pdb;
- struct strs *strs;
-};
-
-static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
-{
- filename_trans_key_t *ft = (filename_trans_key_t *)key;
- filename_trans_datum_t *datum = data;
- struct map_filename_trans_args *map_args = arg;
- struct policydb *pdb = map_args->pdb;
- struct strs *strs = map_args->strs;
- char *src, *tgt, *class, *filename, *new;
- struct ebitmap_node *node;
- uint32_t bit;
- int rc;
-
- tgt = pdb->p_type_val_to_name[ft->ttype - 1];
- class = pdb->p_class_val_to_name[ft->tclass - 1];
- filename = ft->name;
- do {
- new = pdb->p_type_val_to_name[datum->otype - 1];
-
- ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
- src = pdb->p_type_val_to_name[bit];
- rc = strs_create_and_add(strs,
- "type_transition %s %s:%s %s \"%s\";",
- 5, src, tgt, class, new, filename);
- if (rc)
- return rc;
- }
-
- datum = datum->next;
- } while (datum);
-
- return 0;
-}
-
-static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
-{
- struct map_filename_trans_args args;
- struct strs *strs;
- int rc = 0;
-
- rc = strs_init(&strs, 100);
- if (rc != 0) {
- goto exit;
- }
-
- args.pdb = pdb;
- args.strs = strs;
-
- rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
- if (rc != 0) {
- goto exit;
- }
-
- strs_sort(strs);
- strs_write_each(strs, out);
-
-exit:
- strs_free_all(strs);
- strs_destroy(&strs);
-
- if (rc != 0) {
- ERR(NULL, "Error writing filename typetransition rules to policy.conf");
- }
-
- return rc;
-}
-
static char *level_to_str(struct policydb *pdb, struct mls_level *level)
{
ebitmap_t *cats = &level->cat;
@@ -2036,7 +1975,6 @@ static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_l
avtab_key_t *key;
avtab_datum_t *datum;
struct strs *strs;
- char *rule;
unsigned i;
int rc;
@@ -2052,14 +1990,8 @@ static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_l
key = &node->key;
datum = &node->datum;
if (key->specified & flavor) {
- rule = avtab_node_to_str(pdb, key, datum);
- if (!rule) {
- rc = -1;
- goto exit;
- }
- rc = strs_add(strs, rule);
+ rc = avtab_node_to_strs(pdb, key, datum, strs);
if (rc != 0) {
- free(rule);
goto exit;
}
}
@@ -3205,7 +3137,6 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
if (rc != 0) {
goto exit;
}
- write_filename_trans_rules_to_conf(out, pdb);
if (pdb->mls) {
rc = write_range_trans_rules_to_conf(out, pdb);
@@ -308,8 +308,10 @@ static void optimize_avtab(policydb_t *p, const struct type_vec *type_map)
*cur = tmp->next;
if (tmp->key.specified & AVTAB_XPERMS)
free(tmp->datum.xperms);
- if (tmp->key.specified & AVTAB_TRANSITION)
+ if (tmp->key.specified & AVTAB_TRANSITION) {
+ avtab_trans_destroy(tmp->datum.trans);
free(tmp->datum.trans);
+ }
free(tmp);
tab->nel--;
@@ -429,8 +431,10 @@ static void optimize_cond_avtab(policydb_t *p, const struct type_vec *type_map)
*cur = tmp->next;
if (tmp->key.specified & AVTAB_XPERMS)
free(tmp->datum.xperms);
- if (tmp->key.specified & AVTAB_TRANSITION)
+ if (tmp->key.specified & AVTAB_TRANSITION) {
+ avtab_trans_destroy(tmp->datum.trans);
free(tmp->datum.trans);
+ }
free(tmp);
tab->nel--;
@@ -801,47 +801,6 @@ static int roles_init(policydb_t * p)
goto out;
}
-ignore_unsigned_overflow_
-static inline unsigned long
-partial_name_hash(unsigned long c, unsigned long prevhash)
-{
- return (prevhash + (c << 4) + (c >> 4)) * 11;
-}
-
-static unsigned int filenametr_hash(hashtab_t h, const_hashtab_key_t k)
-{
- const filename_trans_key_t *ft = (const filename_trans_key_t *)k;
- unsigned long hash;
- unsigned int byte_num;
- unsigned char focus;
-
- hash = ft->ttype ^ ft->tclass;
-
- byte_num = 0;
- while ((focus = ft->name[byte_num++]))
- hash = partial_name_hash(focus, hash);
- return hash & (h->size - 1);
-}
-
-static int filenametr_cmp(hashtab_t h __attribute__ ((unused)),
- const_hashtab_key_t k1, const_hashtab_key_t k2)
-{
- const filename_trans_key_t *ft1 = (const filename_trans_key_t *)k1;
- const filename_trans_key_t *ft2 = (const filename_trans_key_t *)k2;
- int v;
-
- v = spaceship_cmp(ft1->ttype, ft2->ttype);
- if (v)
- return v;
-
- v = spaceship_cmp(ft1->tclass, ft2->tclass);
- if (v)
- return v;
-
- return strcmp(ft1->name, ft2->name);
-
-}
-
static unsigned int rangetr_hash(hashtab_t h, const_hashtab_key_t k)
{
const struct range_trans *key = (const struct range_trans *)k;
@@ -909,12 +868,6 @@ int policydb_init(policydb_t * p)
if (rc)
goto err;
- p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
- if (!p->filename_trans) {
- rc = -ENOMEM;
- goto err;
- }
-
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
if (!p->range_tr) {
rc = -ENOMEM;
@@ -926,7 +879,6 @@ int policydb_init(policydb_t * p)
return 0;
err:
- hashtab_destroy(p->filename_trans);
hashtab_destroy(p->range_tr);
for (i = 0; i < SYM_NUM; i++) {
hashtab_destroy(p->symtab[i].table);
@@ -1412,23 +1364,6 @@ static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
cond_destroy_bool, sens_destroy, cat_destroy,};
-static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
- void *p __attribute__ ((unused)))
-{
- filename_trans_key_t *ft = (filename_trans_key_t *)key;
- filename_trans_datum_t *fd = datum, *next;
-
- free(ft->name);
- free(key);
- do {
- next = fd->next;
- ebitmap_destroy(&fd->stypes);
- free(fd);
- fd = next;
- } while (fd);
- return 0;
-}
-
static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
void *p __attribute__ ((unused)))
{
@@ -1564,9 +1499,6 @@ void policydb_destroy(policydb_t * p)
if (lra)
free(lra);
- hashtab_map(p->filename_trans, filenametr_destroy, NULL);
- hashtab_destroy(p->filename_trans);
-
hashtab_map(p->range_tr, range_tr_destroy, NULL);
hashtab_destroy(p->range_tr);
@@ -2596,279 +2528,6 @@ static int role_allow_read(role_allow_t ** r, struct policy_file *fp)
return 0;
}
-int policydb_filetrans_insert(policydb_t *p, uint32_t stype, uint32_t ttype,
- uint32_t tclass, const char *name,
- char **name_alloc, uint32_t otype,
- uint32_t *present_otype)
-{
- filename_trans_key_t *ft, key;
- filename_trans_datum_t *datum, *last;
-
- key.ttype = ttype;
- key.tclass = tclass;
- key.name = (char *)name;
-
- last = NULL;
- datum = hashtab_search(p->filename_trans, (hashtab_key_t)&key);
- while (datum) {
- if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
- if (present_otype)
- *present_otype = datum->otype;
- return SEPOL_EEXIST;
- }
- if (datum->otype == otype)
- break;
- last = datum;
- datum = datum->next;
- }
- if (!datum) {
- datum = malloc(sizeof(*datum));
- if (!datum)
- return SEPOL_ENOMEM;
-
- ebitmap_init(&datum->stypes);
- datum->otype = otype;
- datum->next = NULL;
-
- if (last) {
- last->next = datum;
- } else {
- char *name_dup;
-
- if (name_alloc) {
- name_dup = *name_alloc;
- *name_alloc = NULL;
- } else {
- name_dup = strdup(name);
- if (!name_dup) {
- free(datum);
- return SEPOL_ENOMEM;
- }
- }
-
- ft = malloc(sizeof(*ft));
- if (!ft) {
- free(name_dup);
- free(datum);
- return SEPOL_ENOMEM;
- }
-
- ft->ttype = ttype;
- ft->tclass = tclass;
- ft->name = name_dup;
-
- if (hashtab_insert(p->filename_trans, (hashtab_key_t)ft,
- (hashtab_datum_t)datum)) {
- free(name_dup);
- free(datum);
- free(ft);
- return SEPOL_ENOMEM;
- }
- }
- }
-
- p->filename_trans_count++;
- return ebitmap_set_bit(&datum->stypes, stype - 1, 1);
-}
-
-static int filename_trans_read_one_compat(policydb_t *p, struct policy_file *fp)
-{
- uint32_t buf[4], len, stype, ttype, tclass, otype;
- char *name = NULL;
- int rc;
-
- rc = next_entry(buf, fp, sizeof(uint32_t));
- if (rc < 0)
- return -1;
- len = le32_to_cpu(buf[0]);
- if (zero_or_saturated(len))
- return -1;
-
- name = calloc(len + 1, sizeof(*name));
- if (!name)
- return -1;
-
- rc = next_entry(name, fp, len);
- if (rc < 0)
- goto err;
-
- rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
- if (rc < 0)
- goto err;
-
- stype = le32_to_cpu(buf[0]);
- if (stype == 0)
- goto err;
-
- ttype = le32_to_cpu(buf[1]);
- tclass = le32_to_cpu(buf[2]);
- otype = le32_to_cpu(buf[3]);
-
- rc = policydb_filetrans_insert(p, stype, ttype, tclass, name, &name,
- otype, NULL);
- if (rc) {
- if (rc != SEPOL_EEXIST)
- goto err;
- /*
- * Some old policies were wrongly generated with
- * duplicate filename transition rules. For backward
- * compatibility, do not reject such policies, just
- * ignore the duplicate.
- */
- }
- free(name);
- return 0;
-err:
- free(name);
- return -1;
-}
-
-static int filename_trans_check_datum(filename_trans_datum_t *datum)
-{
- ebitmap_t stypes, otypes;
- int rc = -1;
-
- ebitmap_init(&stypes);
- ebitmap_init(&otypes);
-
- while (datum) {
- if (ebitmap_get_bit(&otypes, datum->otype))
- goto out;
-
- if (ebitmap_set_bit(&otypes, datum->otype, 1))
- goto out;
-
- if (ebitmap_match_any(&stypes, &datum->stypes))
- goto out;
-
- if (ebitmap_union(&stypes, &datum->stypes))
- goto out;
-
- datum = datum->next;
- }
- rc = 0;
-out:
- ebitmap_destroy(&stypes);
- ebitmap_destroy(&otypes);
- return rc;
-}
-
-static int filename_trans_read_one(policydb_t *p, struct policy_file *fp)
-{
- filename_trans_key_t *ft = NULL;
- filename_trans_datum_t **dst, *datum, *first = NULL;
- unsigned int i;
- uint32_t buf[3], len, ttype, tclass, ndatum;
- char *name = NULL;
- int rc;
-
- rc = next_entry(buf, fp, sizeof(uint32_t));
- if (rc < 0)
- return -1;
- len = le32_to_cpu(buf[0]);
- if (zero_or_saturated(len))
- return -1;
-
- name = calloc(len + 1, sizeof(*name));
- if (!name)
- return -1;
-
- rc = next_entry(name, fp, len);
- if (rc < 0)
- goto err;
-
- rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
- if (rc < 0)
- goto err;
-
- ttype = le32_to_cpu(buf[0]);
- tclass = le32_to_cpu(buf[1]);
- ndatum = le32_to_cpu(buf[2]);
- if (ndatum == 0)
- goto err;
-
- dst = &first;
- for (i = 0; i < ndatum; i++) {
- datum = malloc(sizeof(*datum));
- if (!datum)
- goto err;
-
- datum->next = NULL;
- *dst = datum;
-
- /* ebitmap_read() will at least init the bitmap */
- rc = ebitmap_read(&datum->stypes, fp);
- if (rc < 0)
- goto err;
-
- rc = next_entry(buf, fp, sizeof(uint32_t));
- if (rc < 0)
- goto err;
-
- datum->otype = le32_to_cpu(buf[0]);
-
- p->filename_trans_count += ebitmap_cardinality(&datum->stypes);
-
- dst = &datum->next;
- }
-
- if (ndatum > 1 && filename_trans_check_datum(first))
- goto err;
-
- ft = malloc(sizeof(*ft));
- if (!ft)
- goto err;
-
- ft->ttype = ttype;
- ft->tclass = tclass;
- ft->name = name;
-
- rc = hashtab_insert(p->filename_trans, (hashtab_key_t)ft,
- (hashtab_datum_t)first);
- if (rc)
- goto err;
-
- return 0;
-err:
- free(ft);
- free(name);
- while (first) {
- datum = first;
- first = first->next;
-
- ebitmap_destroy(&datum->stypes);
- free(datum);
- }
- return -1;
-}
-
-static int filename_trans_read(policydb_t *p, struct policy_file *fp)
-{
- unsigned int i;
- uint32_t buf[1], nel;
- int rc;
-
- rc = next_entry(buf, fp, sizeof(uint32_t));
- if (rc < 0)
- return -1;
- nel = le32_to_cpu(buf[0]);
-
- if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
- for (i = 0; i < nel; i++) {
- rc = filename_trans_read_one_compat(p, fp);
- if (rc < 0)
- return -1;
- }
- } else {
- for (i = 0; i < nel; i++) {
- rc = filename_trans_read_one(p, fp);
- if (rc < 0)
- return -1;
- }
- }
- return 0;
-}
-
static int ocontext_read_xen(const struct policydb_compat_info *info,
policydb_t *p, struct policy_file *fp)
{
@@ -4470,7 +4129,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
if (role_allow_read(&p->role_allow, fp))
goto bad;
if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
- filename_trans_read(p, fp))
+ avtab_filename_trans_read(fp, r_policyvers, &p->te_avtab))
goto bad;
} else {
/* first read the AV rule blocks, then the scope tables */
@@ -829,6 +829,18 @@ static int validate_xperms(const avtab_extended_perms_t *xperms)
bad:
return -1;
}
+
+static int validate_name_trans_helper(hashtab_key_t k __attribute__ ((unused)),
+ hashtab_datum_t d, void *a)
+{
+ uint32_t *otype = d;
+ map_arg_t *margs = a;
+
+ if (validate_simpletype(*otype, margs->policy, margs->flavors))
+ return -1;
+ return 0;
+}
+
static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void *args)
{
map_arg_t *margs = args;
@@ -836,10 +848,23 @@ static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void *
if (validate_avtab_key(k, 0, margs->policy, margs->flavors))
return -1;
- uint32_t otype = k->specified & AVTAB_TRANSITION
- ? d->trans->otype : d->data;
- if ((k->specified & AVTAB_TYPE) && validate_simpletype(otype, margs->policy, margs->flavors))
+ if (k->specified & AVTAB_TRANSITION) {
+ /* if otype is set (non-zero), it must by a valid simple type */
+ if (d->trans->otype && validate_simpletype(d->trans->otype, margs->policy, margs->flavors))
+ return -1;
+
+ /* also each transition must be non empty */
+ if (!d->trans->otype &&
+ !hashtab_nel(d->trans->name_trans.table))
+ return -1;
+
+ /* and each filename transition must be also valid */
+ if (hashtab_map(d->trans->name_trans.table,
+ validate_name_trans_helper, margs))
+ return -1;
+ } else if ((k->specified & AVTAB_TYPE) && validate_simpletype(d->data, margs->policy, margs->flavors)) {
return -1;
+ }
if ((k->specified & AVTAB_XPERMS) && validate_xperms(d->xperms))
return -1;
@@ -1092,41 +1117,6 @@ bad:
return -1;
}
-static int validate_filename_trans(hashtab_key_t k, hashtab_datum_t d, void *args)
-{
- const filename_trans_key_t *ftk = (filename_trans_key_t *)k;
- const filename_trans_datum_t *ftd = d;
- validate_t *flavors = (validate_t *)args;
-
- if (validate_value(ftk->ttype, &flavors[SYM_TYPES]))
- goto bad;
- if (validate_value(ftk->tclass, &flavors[SYM_CLASSES]))
- goto bad;
- if (!ftd)
- goto bad;
- for (; ftd; ftd = ftd->next) {
- if (validate_ebitmap(&ftd->stypes, &flavors[SYM_TYPES]))
- goto bad;
- if (validate_value(ftd->otype, &flavors[SYM_TYPES]))
- goto bad;
- }
-
- return 0;
-
-bad:
- return -1;
-}
-
-static int validate_filename_trans_hashtab(sepol_handle_t *handle, hashtab_t filename_trans, validate_t flavors[])
-{
- if (hashtab_map(filename_trans, validate_filename_trans, flavors)) {
- ERR(handle, "Invalid filename trans");
- return -1;
- }
-
- return 0;
-}
-
static int validate_context(const context_struct_t *con, validate_t flavors[], int mls)
{
if (validate_value(con->user, &flavors[SYM_USERS]))
@@ -1556,9 +1546,6 @@ int policydb_validate(sepol_handle_t *handle, const policydb_t *p)
goto bad;
if (validate_role_allows(handle, p->role_allow, flavors))
goto bad;
- if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS)
- if (validate_filename_trans_hashtab(handle, p->filename_trans, flavors))
- goto bad;
} else {
if (validate_avrule_blocks(handle, p->global, p, flavors))
goto bad;
@@ -116,6 +116,14 @@ static int avtab_write_item(policydb_t * p,
&& p->policyvers < POLICYDB_VERSION_AVTAB);
unsigned int i;
+ /* skip entries which only contain filename transitions */
+ if (cur->key.specified & AVTAB_TRANSITION && !cur->datum.trans->otype) {
+ /* if oldvers, reduce nel, because this node will be skipped */
+ if (oldvers && nel)
+ (*nel)--;
+ return 0;
+ }
+
if (oldvers) {
/* Generate the old avtab format.
Requires merging similar entries if uncond avtab. */
@@ -313,8 +321,23 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
avtab_reset_merged(a);
nel = a->nel;
} else {
- /* New avtab format. nel is good to go. */
- nel = cpu_to_le32(a->nel);
+ /*
+ * New avtab format. nel is good to go unless we need to skip
+ * filename transitions.
+ */
+ nel = a->nel;
+ /*
+ * entries containing only filename transitions are skipped and
+ * written out later
+ */
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (cur->key.specified & AVTAB_TRANSITION &&
+ !cur->datum.trans->otype)
+ nel--;
+ }
+ }
+ nel = cpu_to_le32(nel);
items = put_entry(&nel, sizeof(uint32_t), 1, fp);
if (items != 1)
return POLICYDB_ERROR;
@@ -358,6 +381,307 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
return rc;
}
+/* policydb filename transition compatibility */
+
+typedef struct filenametr_key {
+ uint32_t ttype;
+ uint32_t tclass;
+ char *name;
+} filenametr_key_t;
+
+typedef struct filenametr_datum {
+ ebitmap_t stypes;
+ uint32_t otype;
+ struct filenametr_datum *next;
+} filenametr_datum_t;
+
+ignore_unsigned_overflow_
+static inline unsigned long
+partial_name_hash(unsigned long c, unsigned long prevhash)
+{
+ return (prevhash + (c << 4) + (c >> 4)) * 11;
+}
+
+static unsigned int filenametr_hash(hashtab_t h, const_hashtab_key_t k)
+{
+ const filenametr_key_t *ft = (const filenametr_key_t *)k;
+ unsigned long hash;
+ unsigned int byte_num;
+ unsigned char focus;
+
+ hash = ft->ttype ^ ft->tclass;
+
+ byte_num = 0;
+ while ((focus = ft->name[byte_num++]))
+ hash = partial_name_hash(focus, hash);
+ return hash & (h->size - 1);
+}
+
+static int filenametr_cmp(hashtab_t h __attribute__ ((unused)),
+ const_hashtab_key_t k1, const_hashtab_key_t k2)
+{
+ const filenametr_key_t *ft1 = (const filenametr_key_t *)k1;
+ const filenametr_key_t *ft2 = (const filenametr_key_t *)k2;
+ int v;
+
+ v = spaceship_cmp(ft1->ttype, ft2->ttype);
+ if (v)
+ return v;
+
+ v = spaceship_cmp(ft1->tclass, ft2->tclass);
+ if (v)
+ return v;
+
+ return strcmp(ft1->name, ft2->name);
+}
+
+static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
+ void *p __attribute__ ((unused)))
+{
+ filenametr_key_t *ft = (filenametr_key_t *)key;
+ filenametr_datum_t *fd = datum, *next;
+
+ free(ft->name);
+ free(key);
+ do {
+ next = fd->next;
+ ebitmap_destroy(&fd->stypes);
+ free(fd);
+ fd = next;
+ } while (fd);
+ return 0;
+}
+
+typedef struct {
+ void *fp;
+ avtab_key_t *key;
+} name_trans_write_args_t;
+
+static int name_trans_write_helper(hashtab_key_t k, hashtab_datum_t d, void *a)
+{
+ char *name = k;
+ uint32_t *otype = d;
+ name_trans_write_args_t *args = a;
+ size_t items;
+ uint32_t len, buf[4];
+
+ len = strlen(name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, args->fp);
+ if (items != 1)
+ return -1;
+
+ items = put_entry(name, sizeof(char), len,args-> fp);
+ if (items != len)
+ return -1;
+
+ buf[0] = cpu_to_le32(args->key->source_type);
+ buf[1] = cpu_to_le32(args->key->target_type);
+ buf[2] = cpu_to_le32(args->key->target_class);
+ buf[3] = cpu_to_le32(*otype);
+
+ items = put_entry(buf, sizeof(uint32_t), 4, args->fp);
+ if (items != 4)
+ return -1;
+ return 0;
+}
+
+typedef struct {
+ hashtab_t fnts_tab;
+ avtab_key_t *av_key;
+} name_trans_insert_args_t;
+
+static int name_trans_insert_helper(hashtab_key_t k, hashtab_datum_t d, void *a)
+{
+ char *name = k;
+ uint32_t *otype = d;
+ name_trans_insert_args_t *args = a;
+ filenametr_key_t key, *ft = NULL;
+ filenametr_datum_t *last, *datum = NULL;
+ int rc;
+
+ key.ttype = args->av_key->target_type;
+ key.tclass = args->av_key->target_class;
+ key.name = name;
+
+ last = NULL;
+ datum = hashtab_search(args->fnts_tab, (hashtab_key_t)&key);
+ while (datum) {
+ if (ebitmap_get_bit(&datum->stypes, args->av_key->source_type - 1)) {
+ datum = NULL;
+ goto bad;
+ }
+ if (datum->otype == *otype)
+ break;
+ last = datum;
+ datum = datum->next;
+ }
+ if (!datum) {
+ datum = malloc(sizeof(filenametr_datum_t));
+ if (!datum)
+ goto bad;
+
+ ebitmap_init(&datum->stypes);
+ datum->otype = *otype;
+ datum->next = NULL;
+
+ if (last) {
+ last->next = datum;
+ } else {
+ ft = malloc(sizeof(filenametr_key_t));
+ if (!ft)
+ goto bad;
+
+ ft->ttype = args->av_key->target_type;
+ ft->tclass = args->av_key->target_class;
+ ft->name = strdup(name);
+ if (!ft->name)
+ goto bad;
+
+ rc = hashtab_insert(args->fnts_tab, (hashtab_key_t)ft, datum);
+ if (rc)
+ goto bad;
+ }
+ }
+
+ return ebitmap_set_bit(&datum->stypes, args->av_key->source_type - 1, 1);
+
+bad:
+ if (ft != NULL)
+ free(ft->name);
+ free(ft);
+ free(datum);
+ return -1;
+}
+
+static int filenametr_comp_write_one(hashtab_key_t key, void *data, void *ptr)
+{
+ uint32_t buf[3];
+ size_t items, len, ndatum;
+ filenametr_key_t *ft = (filenametr_key_t *)key;
+ filenametr_datum_t *datum;
+ void *fp = ptr;
+
+ len = strlen(ft->name);
+ buf[0] = cpu_to_le32(len);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ items = put_entry(ft->name, sizeof(char), len, fp);
+ if (items != len)
+ return POLICYDB_ERROR;
+
+ ndatum = 0;
+ datum = data;
+ do {
+ ndatum++;
+ datum = datum->next;
+ } while (datum);
+
+ buf[0] = cpu_to_le32(ft->ttype);
+ buf[1] = cpu_to_le32(ft->tclass);
+ buf[2] = cpu_to_le32(ndatum);
+ items = put_entry(buf, sizeof(uint32_t), 3, fp);
+ if (items != 3)
+ return POLICYDB_ERROR;
+
+ datum = data;
+ do {
+ if (ebitmap_write(&datum->stypes, fp))
+ return POLICYDB_ERROR;
+
+ buf[0] = cpu_to_le32(datum->otype);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return POLICYDB_ERROR;
+
+ datum = datum->next;
+ } while (datum);
+
+ return 0;
+}
+
+static int avtab_filename_trans_write(policydb_t *pol, avtab_t *a,
+ policy_file_t *fp)
+{
+ policydb_t *p = pol;
+ uint32_t buf[1];
+ int rc;
+ size_t items;
+ uint32_t i, nel = 0;
+ struct avtab_node *cur;
+ hashtab_t fnts_tab;
+ name_trans_write_args_t write_args = { .fp = fp };
+ name_trans_insert_args_t insert_args;
+
+ /* count number of filename transitions */
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (cur->key.specified & AVTAB_TRANSITION) {
+ nel += hashtab_nel(cur->datum.trans->name_trans.table);
+ }
+ }
+ }
+
+ if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
+ buf[0] = cpu_to_le32(nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ return -1;
+
+ /* write filename transitions */
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (cur->key.specified & AVTAB_TRANSITION) {
+ write_args.key = &cur->key;
+ rc = hashtab_map(cur->datum.trans->name_trans.table,
+ name_trans_write_helper,
+ &write_args);
+ if (rc)
+ return -1;
+ }
+ }
+ }
+ return 0;
+ }
+
+ /* init filename transitions */
+ fnts_tab = hashtab_create(filenametr_hash, filenametr_cmp, nel);
+ if (!fnts_tab)
+ return -1;
+ insert_args.fnts_tab = fnts_tab;
+
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (cur->key.specified & AVTAB_TRANSITION) {
+ insert_args.av_key = &cur->key;
+ rc = hashtab_map(cur->datum.trans->name_trans.table,
+ name_trans_insert_helper,
+ &insert_args);
+ }
+ }
+ }
+
+ rc = -1;
+ /* write compressed filename transitions */
+ buf[0] = cpu_to_le32(fnts_tab->nel);
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
+ if (items != 1)
+ goto out;
+
+ rc = hashtab_map(fnts_tab, filenametr_comp_write_one, fp);
+
+out:
+ /* destroy temp filename transitions table */
+ hashtab_map(fnts_tab, filenametr_destroy, NULL);
+ hashtab_destroy(fnts_tab);
+
+ return rc ? -1 : 0;
+}
+
+/* end policydb filename transition compatibility */
+
/*
* Write a semantic MLS level structure to a policydb binary
* representation file.
@@ -580,118 +904,6 @@ static int role_allow_write(role_allow_t * r, struct policy_file *fp)
return POLICYDB_SUCCESS;
}
-static int filename_write_one_compat(hashtab_key_t key, void *data, void *ptr)
-{
- uint32_t bit, buf[4];
- size_t items, len;
- filename_trans_key_t *ft = (filename_trans_key_t *)key;
- filename_trans_datum_t *datum = data;
- ebitmap_node_t *node;
- void *fp = ptr;
-
- len = strlen(ft->name);
- do {
- ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
- buf[0] = cpu_to_le32(len);
- items = put_entry(buf, sizeof(uint32_t), 1, fp);
- if (items != 1)
- return POLICYDB_ERROR;
-
- items = put_entry(ft->name, sizeof(char), len, fp);
- if (items != len)
- return POLICYDB_ERROR;
-
- buf[0] = cpu_to_le32(bit + 1);
- buf[1] = cpu_to_le32(ft->ttype);
- buf[2] = cpu_to_le32(ft->tclass);
- buf[3] = cpu_to_le32(datum->otype);
- items = put_entry(buf, sizeof(uint32_t), 4, fp);
- if (items != 4)
- return POLICYDB_ERROR;
- }
-
- datum = datum->next;
- } while (datum);
-
- return 0;
-}
-
-static int filename_write_one(hashtab_key_t key, void *data, void *ptr)
-{
- uint32_t buf[3];
- size_t items, len, ndatum;
- filename_trans_key_t *ft = (filename_trans_key_t *)key;
- filename_trans_datum_t *datum;
- void *fp = ptr;
-
- len = strlen(ft->name);
- buf[0] = cpu_to_le32(len);
- items = put_entry(buf, sizeof(uint32_t), 1, fp);
- if (items != 1)
- return POLICYDB_ERROR;
-
- items = put_entry(ft->name, sizeof(char), len, fp);
- if (items != len)
- return POLICYDB_ERROR;
-
- ndatum = 0;
- datum = data;
- do {
- ndatum++;
- datum = datum->next;
- } while (datum);
-
- buf[0] = cpu_to_le32(ft->ttype);
- buf[1] = cpu_to_le32(ft->tclass);
- buf[2] = cpu_to_le32(ndatum);
- items = put_entry(buf, sizeof(uint32_t), 3, fp);
- if (items != 3)
- return POLICYDB_ERROR;
-
- datum = data;
- do {
- if (ebitmap_write(&datum->stypes, fp))
- return POLICYDB_ERROR;
-
- buf[0] = cpu_to_le32(datum->otype);
- items = put_entry(buf, sizeof(uint32_t), 1, fp);
- if (items != 1)
- return POLICYDB_ERROR;
-
- datum = datum->next;
- } while (datum);
-
- return 0;
-}
-
-static int filename_trans_write(struct policydb *p, void *fp)
-{
- size_t items;
- uint32_t buf[1];
- int rc;
-
- if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
- return 0;
-
- if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
- buf[0] = cpu_to_le32(p->filename_trans_count);
- items = put_entry(buf, sizeof(uint32_t), 1, fp);
- if (items != 1)
- return POLICYDB_ERROR;
-
- rc = hashtab_map(p->filename_trans, filename_write_one_compat,
- fp);
- } else {
- buf[0] = cpu_to_le32(p->filename_trans->nel);
- items = put_entry(buf, sizeof(uint32_t), 1, fp);
- if (items != 1)
- return POLICYDB_ERROR;
-
- rc = hashtab_map(p->filename_trans, filename_write_one, fp);
- }
- return rc;
-}
-
static int role_set_write(role_set_t * x, struct policy_file *fp)
{
size_t items;
@@ -2202,6 +2414,21 @@ static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
return 0;
}
+static int avtab_has_filename_transitions(avtab_t *a)
+{
+ uint32_t i;
+ struct avtab_node *cur;
+ for (i = 0; i < a->nslot; i++) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
+ if (cur->key.specified & AVTAB_TRANSITION) {
+ if (hashtab_nel(cur->datum.trans->name_trans.table))
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
/*
* Write the configuration data in a policy database
* structure to a policy database binary representation
@@ -2381,11 +2608,11 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
if (role_allow_write(p->role_allow, fp))
return POLICYDB_ERROR;
if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
- if (filename_trans_write(p, fp))
+ if (avtab_filename_trans_write(p, &p->te_avtab, fp))
return POLICYDB_ERROR;
- } else {
- if (p->filename_trans)
- WARN(fp->handle, "Discarding filename type transition rules");
+ } else if (avtab_has_filename_transitions(&p->te_avtab)) {
+ WARN(fp->handle,
+ "Discarding filename type transition rules");
}
} else {
if (avrule_block_write(p->global, num_syms, p, fp) == -1) {