@@ -297,7 +297,7 @@ static int avtab_trans_destroy_helper(void *k, void *d, void *args)
return 0;
}
-static void avtab_trans_destroy(struct avtab_trans *trans)
+void avtab_trans_destroy(struct avtab_trans *trans)
{
hashtab_map(&trans->name_trans.table, avtab_trans_destroy_helper, NULL);
hashtab_destroy(&trans->name_trans.table);
@@ -125,6 +125,8 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified
#define MAX_AVTAB_HASH_BITS 16
#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+void avtab_trans_destroy(struct avtab_trans *trans);
+
/* policydb filename transitions compatibility */
int avtab_filename_trans_read(struct avtab *a, void *fp, struct policydb *p);
@@ -605,11 +605,36 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
}
}
+static int cond_avtab_trans_destroy_helper(void *k, void *d, __always_unused void *args)
+{
+ kfree(k);
+ kfree(d);
+ return 0;
+}
+
+static int cond_avtab_trans_copy(struct hashtab_node *new, const struct hashtab_node *orig,
+ __always_unused void *args)
+{
+ new->key = kstrdup(orig->key, GFP_KERNEL);
+ if (!new->key)
+ return -ENOMEM;
+
+ new->datum = kmemdup(orig->datum, sizeof(u32), GFP_KERNEL);
+ if (!new->datum) {
+ kfree(new->key);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static int cond_dup_av_list(struct cond_av_list *new,
- struct cond_av_list *orig,
- struct avtab *avtab)
+ const struct cond_av_list *orig,
+ struct avtab *avtab,
+ const struct policydb *origp)
{
u32 i;
+ int rc;
memset(new, 0, sizeof(*new));
@@ -618,9 +643,66 @@ static int cond_dup_av_list(struct cond_av_list *new,
return -ENOMEM;
for (i = 0; i < orig->len; i++) {
- new->nodes[i] = avtab_insert_nonunique(avtab,
- &orig->nodes[i]->key,
- &orig->nodes[i]->datum);
+ const struct avtab_key *orig_key = &orig->nodes[i]->key;
+ struct avtab_datum datum = orig->nodes[i]->datum;
+
+ if (origp->policyvers >= POLICYDB_VERSION_AVTAB_FTRANS &&
+ (orig_key->specified & AVTAB_TRANSITION)) {
+ struct avtab_trans trans = {
+ .otype = datum.u.trans->otype,
+ };
+
+ rc = symtab_init(&trans.name_trans,
+ datum.u.trans->name_trans.table.nel);
+ if (rc) {
+ avtab_trans_destroy(&trans);
+ return rc;
+ }
+ rc = symtab_init(&trans.prefix_trans,
+ datum.u.trans->prefix_trans.table.nel);
+ if (rc) {
+ avtab_trans_destroy(&trans);
+ return rc;
+ }
+ rc = symtab_init(&trans.suffix_trans,
+ datum.u.trans->suffix_trans.table.nel);
+ if (rc) {
+ avtab_trans_destroy(&trans);
+ return rc;
+ }
+
+ rc = hashtab_duplicate(&trans.name_trans.table,
+ &datum.u.trans->name_trans.table,
+ cond_avtab_trans_copy,
+ cond_avtab_trans_destroy_helper,
+ NULL);
+ if (rc) {
+ avtab_trans_destroy(&trans);
+ return rc;
+ }
+ rc = hashtab_duplicate(&trans.prefix_trans.table,
+ &datum.u.trans->prefix_trans.table,
+ cond_avtab_trans_copy,
+ cond_avtab_trans_destroy_helper,
+ NULL);
+ if (rc) {
+ avtab_trans_destroy(&trans);
+ return rc;
+ }
+ rc = hashtab_duplicate(&trans.suffix_trans.table,
+ &datum.u.trans->suffix_trans.table,
+ cond_avtab_trans_copy,
+ cond_avtab_trans_destroy_helper,
+ NULL);
+ if (rc) {
+ avtab_trans_destroy(&trans);
+ return rc;
+ }
+
+ datum.u.trans = &trans;
+ }
+
+ new->nodes[i] = avtab_insert_nonunique(avtab, orig_key, &datum);
if (!new->nodes[i])
return -ENOMEM;
new->len++;
@@ -662,12 +744,12 @@ static int duplicate_policydb_cond_list(struct policydb *newp,
newn->expr.len = orign->expr.len;
rc = cond_dup_av_list(&newn->true_list, &orign->true_list,
- &newp->te_cond_avtab);
+ &newp->te_cond_avtab, origp);
if (rc)
goto error;
rc = cond_dup_av_list(&newn->false_list, &orign->false_list,
- &newp->te_cond_avtab);
+ &newp->te_cond_avtab, origp);
if (rc)
goto error;
}