Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index dd7aabd..6a04de2 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -56,17 +56,6 @@
};
#endif
-static unsigned int symtab_sizes[SYM_NUM] = {
- 2,
- 32,
- 16,
- 512,
- 128,
- 16,
- 16,
- 16,
-};
-
struct policydb_compat_info {
int version;
int sym_num;
@@ -160,6 +149,16 @@
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_GLBLUB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_COMP_FTRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -196,8 +195,8 @@
kfree(key);
if (datum) {
comdatum = datum;
- hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
- hashtab_destroy(comdatum->permissions.table);
+ hashtab_map(&comdatum->permissions.table, perm_destroy, NULL);
+ hashtab_destroy(&comdatum->permissions.table);
}
kfree(datum);
return 0;
@@ -225,8 +224,8 @@
kfree(key);
if (datum) {
cladatum = datum;
- hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
- hashtab_destroy(cladatum->permissions.table);
+ hashtab_map(&cladatum->permissions.table, perm_destroy, NULL);
+ hashtab_destroy(&cladatum->permissions.table);
constraint = cladatum->constraints;
while (constraint) {
e = constraint->expr;
@@ -331,11 +330,17 @@
static int filenametr_destroy(void *key, void *datum, void *p)
{
- struct filename_trans *ft = key;
+ struct filename_trans_key *ft = key;
+ struct filename_trans_datum *next, *d = datum;
kfree(ft->name);
kfree(key);
- kfree(datum);
+ do {
+ ebitmap_destroy(&d->stypes);
+ next = d->next;
+ kfree(d);
+ d = next;
+ } while (unlikely(d));
cond_resched();
return 0;
}
@@ -352,6 +357,13 @@
return 0;
}
+static int role_tr_destroy(void *key, void *datum, void *p)
+{
+ kfree(key);
+ kfree(datum);
+ return 0;
+}
+
static void ocontext_destroy(struct ocontext *c, int i)
{
if (!c)
@@ -388,7 +400,7 @@
if (!key)
goto out;
- rc = hashtab_insert(p->p_roles.table, key, role);
+ rc = symtab_insert(&p->p_roles, key, role);
if (rc)
goto out;
@@ -399,31 +411,27 @@
return rc;
}
-static u32 filenametr_hash(struct hashtab *h, const void *k)
+static u32 filenametr_hash(const void *k)
{
- const struct filename_trans *ft = k;
+ const struct filename_trans_key *ft = k;
unsigned long hash;
unsigned int byte_num;
unsigned char focus;
- hash = ft->stype ^ ft->ttype ^ ft->tclass;
+ 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);
+ return hash;
}
-static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
+static int filenametr_cmp(const void *k1, const void *k2)
{
- const struct filename_trans *ft1 = k1;
- const struct filename_trans *ft2 = k2;
+ const struct filename_trans_key *ft1 = k1;
+ const struct filename_trans_key *ft2 = k2;
int v;
- v = ft1->stype - ft2->stype;
- if (v)
- return v;
-
v = ft1->ttype - ft2->ttype;
if (v)
return v;
@@ -436,15 +444,26 @@
}
-static u32 rangetr_hash(struct hashtab *h, const void *k)
+static const struct hashtab_key_params filenametr_key_params = {
+ .hash = filenametr_hash,
+ .cmp = filenametr_cmp,
+};
+
+struct filename_trans_datum *policydb_filenametr_search(
+ struct policydb *p, struct filename_trans_key *key)
+{
+ return hashtab_search(&p->filename_trans, key, filenametr_key_params);
+}
+
+static u32 rangetr_hash(const void *k)
{
const struct range_trans *key = k;
- return (key->source_type + (key->target_type << 3) +
- (key->target_class << 5)) & (h->size - 1);
+ return key->source_type + (key->target_type << 3) +
+ (key->target_class << 5);
}
-static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
+static int rangetr_cmp(const void *k1, const void *k2)
{
const struct range_trans *key1 = k1, *key2 = k2;
int v;
@@ -462,59 +481,64 @@
return v;
}
+static const struct hashtab_key_params rangetr_key_params = {
+ .hash = rangetr_hash,
+ .cmp = rangetr_cmp,
+};
+
+struct mls_range *policydb_rangetr_search(struct policydb *p,
+ struct range_trans *key)
+{
+ return hashtab_search(&p->range_tr, key, rangetr_key_params);
+}
+
+static u32 role_trans_hash(const void *k)
+{
+ const struct role_trans_key *key = k;
+
+ return key->role + (key->type << 3) + (key->tclass << 5);
+}
+
+static int role_trans_cmp(const void *k1, const void *k2)
+{
+ const struct role_trans_key *key1 = k1, *key2 = k2;
+ int v;
+
+ v = key1->role - key2->role;
+ if (v)
+ return v;
+
+ v = key1->type - key2->type;
+ if (v)
+ return v;
+
+ return key1->tclass - key2->tclass;
+}
+
+static const struct hashtab_key_params roletr_key_params = {
+ .hash = role_trans_hash,
+ .cmp = role_trans_cmp,
+};
+
+struct role_trans_datum *policydb_roletr_search(struct policydb *p,
+ struct role_trans_key *key)
+{
+ return hashtab_search(&p->role_tr, key, roletr_key_params);
+}
+
/*
* Initialize a policy database structure.
*/
-static int policydb_init(struct policydb *p)
+static void policydb_init(struct policydb *p)
{
- int i, rc;
-
memset(p, 0, sizeof(*p));
- for (i = 0; i < SYM_NUM; i++) {
- rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
- if (rc)
- goto out;
- }
-
- rc = avtab_init(&p->te_avtab);
- if (rc)
- goto out;
-
- rc = roles_init(p);
- if (rc)
- goto out;
-
- rc = cond_policydb_init(p);
- if (rc)
- goto out;
-
- p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp,
- (1 << 10));
- if (!p->filename_trans) {
- rc = -ENOMEM;
- goto out;
- }
-
- p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
- if (!p->range_tr) {
- rc = -ENOMEM;
- goto out;
- }
+ avtab_init(&p->te_avtab);
+ cond_policydb_init(p);
ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map);
-
- return 0;
-out:
- hashtab_destroy(p->filename_trans);
- hashtab_destroy(p->range_tr);
- for (i = 0; i < SYM_NUM; i++) {
- hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
- hashtab_destroy(p->symtab[i].table);
- }
- return rc;
}
/*
@@ -676,7 +700,7 @@
int i;
for (i = 0; i < SYM_NUM; i++)
- hash_eval(s[i].table, symtab_name[i]);
+ hash_eval(&s[i].table, symtab_name[i]);
}
#else
@@ -747,7 +771,7 @@
if (!p->sym_val_to_name[i])
return -ENOMEM;
- rc = hashtab_map(p->symtab[i].table, index_f[i], p);
+ rc = hashtab_map(&p->symtab[i].table, index_f[i], p);
if (rc)
goto out;
}
@@ -765,12 +789,11 @@
struct genfs *g, *gtmp;
int i;
struct role_allow *ra, *lra = NULL;
- struct role_trans *tr, *ltr = NULL;
for (i = 0; i < SYM_NUM; i++) {
cond_resched();
- hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
- hashtab_destroy(p->symtab[i].table);
+ hashtab_map(&p->symtab[i].table, destroy_f[i], NULL);
+ hashtab_destroy(&p->symtab[i].table);
}
for (i = 0; i < SYM_NUM; i++)
@@ -812,12 +835,8 @@
cond_policydb_destroy(p);
- for (tr = p->role_tr; tr; tr = tr->next) {
- cond_resched();
- kfree(ltr);
- ltr = tr;
- }
- kfree(ltr);
+ hashtab_map(&p->role_tr, role_tr_destroy, NULL);
+ hashtab_destroy(&p->role_tr);
for (ra = p->role_allow; ra; ra = ra->next) {
cond_resched();
@@ -826,11 +845,11 @@
}
kfree(lra);
- hashtab_map(p->filename_trans, filenametr_destroy, NULL);
- hashtab_destroy(p->filename_trans);
+ 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);
+ hashtab_map(&p->range_tr, range_tr_destroy, NULL);
+ hashtab_destroy(&p->range_tr);
if (p->type_attr_map_array) {
for (i = 0; i < p->p_types.nprim; i++)
@@ -855,36 +874,33 @@
rc = sidtab_init(s);
if (rc) {
pr_err("SELinux: out of memory on SID table init\n");
- goto out;
+ return rc;
}
head = p->ocontexts[OCON_ISID];
for (c = head; c; c = c->next) {
- rc = -EINVAL;
- if (!c->context[0].user) {
- pr_err("SELinux: SID %s was never defined.\n",
- c->u.name);
+ u32 sid = c->sid[0];
+ const char *name = security_get_initial_sid_context(sid);
+
+ if (sid == SECSID_NULL) {
+ pr_err("SELinux: SID 0 was assigned a context.\n");
sidtab_destroy(s);
- goto out;
- }
- if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) {
- pr_err("SELinux: Initial SID %s out of range.\n",
- c->u.name);
- sidtab_destroy(s);
- goto out;
+ return -EINVAL;
}
- rc = sidtab_set_initial(s, c->sid[0], &c->context[0]);
+ /* Ignore initial SIDs unused by this kernel. */
+ if (!name)
+ continue;
+
+ rc = sidtab_set_initial(s, sid, &c->context[0]);
if (rc) {
pr_err("SELinux: unable to load initial SID %s.\n",
- c->u.name);
+ name);
sidtab_destroy(s);
- goto out;
+ return rc;
}
}
- rc = 0;
-out:
- return rc;
+ return 0;
}
int policydb_class_isvalid(struct policydb *p, unsigned int class)
@@ -1068,18 +1084,18 @@
if (!str)
return -ENOMEM;
- /* it's expected the caller should free the str */
- *strp = str;
-
rc = next_entry(str, fp, len);
- if (rc)
+ if (rc) {
+ kfree(str);
return rc;
+ }
str[len] = '\0';
+ *strp = str;
return 0;
}
-static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
+static int perm_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct perm_datum *perdatum;
@@ -1102,7 +1118,7 @@
if (rc)
goto bad;
- rc = hashtab_insert(h, key, perdatum);
+ rc = symtab_insert(s, key, perdatum);
if (rc)
goto bad;
@@ -1112,7 +1128,7 @@
return rc;
}
-static int common_read(struct policydb *p, struct hashtab *h, void *fp)
+static int common_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct common_datum *comdatum;
@@ -1130,24 +1146,24 @@
len = le32_to_cpu(buf[0]);
comdatum->value = le32_to_cpu(buf[1]);
+ nel = le32_to_cpu(buf[3]);
- rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
+ rc = symtab_init(&comdatum->permissions, nel);
if (rc)
goto bad;
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
- nel = le32_to_cpu(buf[3]);
rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
goto bad;
for (i = 0; i < nel; i++) {
- rc = perm_read(p, comdatum->permissions.table, fp);
+ rc = perm_read(p, &comdatum->permissions, fp);
if (rc)
goto bad;
}
- rc = hashtab_insert(h, key, comdatum);
+ rc = symtab_insert(s, key, comdatum);
if (rc)
goto bad;
return 0;
@@ -1252,10 +1268,9 @@
if (rc)
return rc;
if (p->policyvers >=
- POLICYDB_VERSION_CONSTRAINT_NAMES) {
- e->type_names = kzalloc(sizeof
- (*e->type_names),
- GFP_KERNEL);
+ POLICYDB_VERSION_CONSTRAINT_NAMES) {
+ e->type_names = kzalloc(sizeof
+ (*e->type_names), GFP_KERNEL);
if (!e->type_names)
return -ENOMEM;
type_set_init(e->type_names);
@@ -1277,7 +1292,7 @@
return 0;
}
-static int class_read(struct policydb *p, struct hashtab *h, void *fp)
+static int class_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct class_datum *cladatum;
@@ -1296,12 +1311,12 @@
len = le32_to_cpu(buf[0]);
len2 = le32_to_cpu(buf[1]);
cladatum->value = le32_to_cpu(buf[2]);
+ nel = le32_to_cpu(buf[4]);
- rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
+ rc = symtab_init(&cladatum->permissions, nel);
if (rc)
goto bad;
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
- nel = le32_to_cpu(buf[4]);
ncons = le32_to_cpu(buf[5]);
@@ -1315,7 +1330,8 @@
goto bad;
rc = -EINVAL;
- cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey);
+ cladatum->comdatum = symtab_search(&p->p_commons,
+ cladatum->comkey);
if (!cladatum->comdatum) {
pr_err("SELinux: unknown common %s\n",
cladatum->comkey);
@@ -1323,7 +1339,7 @@
}
}
for (i = 0; i < nel; i++) {
- rc = perm_read(p, cladatum->permissions.table, fp);
+ rc = perm_read(p, &cladatum->permissions, fp);
if (rc)
goto bad;
}
@@ -1361,7 +1377,7 @@
cladatum->default_type = le32_to_cpu(buf[0]);
}
- rc = hashtab_insert(h, key, cladatum);
+ rc = symtab_insert(s, key, cladatum);
if (rc)
goto bad;
@@ -1371,7 +1387,7 @@
return rc;
}
-static int role_read(struct policydb *p, struct hashtab *h, void *fp)
+static int role_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct role_datum *role;
@@ -1418,7 +1434,7 @@
goto bad;
}
- rc = hashtab_insert(h, key, role);
+ rc = symtab_insert(s, key, role);
if (rc)
goto bad;
return 0;
@@ -1427,7 +1443,7 @@
return rc;
}
-static int type_read(struct policydb *p, struct hashtab *h, void *fp)
+static int type_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct type_datum *typdatum;
@@ -1465,7 +1481,7 @@
if (rc)
goto bad;
- rc = hashtab_insert(h, key, typdatum);
+ rc = symtab_insert(s, key, typdatum);
if (rc)
goto bad;
return 0;
@@ -1501,7 +1517,7 @@
return 0;
}
-static int user_read(struct policydb *p, struct hashtab *h, void *fp)
+static int user_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct user_datum *usrdatum;
@@ -1542,7 +1558,7 @@
goto bad;
}
- rc = hashtab_insert(h, key, usrdatum);
+ rc = symtab_insert(s, key, usrdatum);
if (rc)
goto bad;
return 0;
@@ -1551,7 +1567,7 @@
return rc;
}
-static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
+static int sens_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct level_datum *levdatum;
@@ -1583,7 +1599,7 @@
if (rc)
goto bad;
- rc = hashtab_insert(h, key, levdatum);
+ rc = symtab_insert(s, key, levdatum);
if (rc)
goto bad;
return 0;
@@ -1592,7 +1608,7 @@
return rc;
}
-static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
+static int cat_read(struct policydb *p, struct symtab *s, void *fp)
{
char *key = NULL;
struct cat_datum *catdatum;
@@ -1616,7 +1632,7 @@
if (rc)
goto bad;
- rc = hashtab_insert(h, key, catdatum);
+ rc = symtab_insert(s, key, catdatum);
if (rc)
goto bad;
return 0;
@@ -1625,7 +1641,7 @@
return rc;
}
-static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
+static int (*read_f[SYM_NUM]) (struct policydb *p, struct symtab *s, void *fp) =
{
common_read,
class_read,
@@ -1746,18 +1762,15 @@
if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
return 0;
- rc = hashtab_map(p->p_users.table,
- user_bounds_sanity_check, p);
+ rc = hashtab_map(&p->p_users.table, user_bounds_sanity_check, p);
if (rc)
return rc;
- rc = hashtab_map(p->p_roles.table,
- role_bounds_sanity_check, p);
+ rc = hashtab_map(&p->p_roles.table, role_bounds_sanity_check, p);
if (rc)
return rc;
- rc = hashtab_map(p->p_types.table,
- type_bounds_sanity_check, p);
+ rc = hashtab_map(&p->p_types.table, type_bounds_sanity_check, p);
if (rc)
return rc;
@@ -1768,7 +1781,7 @@
{
struct class_datum *cladatum;
- cladatum = hashtab_search(p->p_classes.table, name);
+ cladatum = symtab_search(&p->p_classes, name);
if (!cladatum)
return 0;
@@ -1787,11 +1800,9 @@
cladatum = p->class_val_to_struct[tclass-1];
comdatum = cladatum->comdatum;
if (comdatum)
- perdatum = hashtab_search(comdatum->permissions.table,
- name);
+ perdatum = symtab_search(&comdatum->permissions, name);
if (!perdatum)
- perdatum = hashtab_search(cladatum->permissions.table,
- name);
+ perdatum = symtab_search(&cladatum->permissions, name);
if (!perdatum)
return 0;
@@ -1814,6 +1825,11 @@
return rc;
nel = le32_to_cpu(buf[0]);
+
+ rc = hashtab_init(&p->range_tr, nel);
+ if (rc)
+ return rc;
+
for (i = 0; i < nel; i++) {
rc = -ENOMEM;
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
@@ -1855,14 +1871,14 @@
goto out;
}
- rc = hashtab_insert(p->range_tr, rt, r);
+ rc = hashtab_insert(&p->range_tr, rt, r, rangetr_key_params);
if (rc)
goto out;
rt = NULL;
r = NULL;
}
- hash_eval(p->range_tr, "rangetr");
+ hash_eval(&p->range_tr, "rangetr");
rc = 0;
out:
kfree(rt);
@@ -1870,13 +1886,183 @@
return rc;
}
+static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
+{
+ struct filename_trans_key key, *ft = NULL;
+ struct filename_trans_datum *last, *datum = NULL;
+ char *name = NULL;
+ u32 len, stype, otype;
+ __le32 buf[4];
+ int rc;
+
+ /* length of the path component string */
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ return rc;
+ len = le32_to_cpu(buf[0]);
+
+ /* path component string */
+ rc = str_read(&name, GFP_KERNEL, fp, len);
+ if (rc)
+ return rc;
+
+ rc = next_entry(buf, fp, sizeof(u32) * 4);
+ if (rc)
+ goto out;
+
+ stype = le32_to_cpu(buf[0]);
+ key.ttype = le32_to_cpu(buf[1]);
+ key.tclass = le32_to_cpu(buf[2]);
+ key.name = name;
+
+ otype = le32_to_cpu(buf[3]);
+
+ last = NULL;
+ datum = policydb_filenametr_search(p, &key);
+ while (datum) {
+ if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
+ /* conflicting/duplicate rules are ignored */
+ datum = NULL;
+ goto out;
+ }
+ if (likely(datum->otype == otype))
+ break;
+ last = datum;
+ datum = datum->next;
+ }
+ if (!datum) {
+ rc = -ENOMEM;
+ datum = kmalloc(sizeof(*datum), GFP_KERNEL);
+ if (!datum)
+ goto out;
+
+ ebitmap_init(&datum->stypes);
+ datum->otype = otype;
+ datum->next = NULL;
+
+ if (unlikely(last)) {
+ last->next = datum;
+ } else {
+ rc = -ENOMEM;
+ ft = kmemdup(&key, sizeof(key), GFP_KERNEL);
+ if (!ft)
+ goto out;
+
+ rc = hashtab_insert(&p->filename_trans, ft, datum,
+ filenametr_key_params);
+ if (rc)
+ goto out;
+ name = NULL;
+
+ rc = ebitmap_set_bit(&p->filename_trans_ttypes,
+ key.ttype, 1);
+ if (rc)
+ return rc;
+ }
+ }
+ kfree(name);
+ return ebitmap_set_bit(&datum->stypes, stype - 1, 1);
+
+out:
+ kfree(ft);
+ kfree(name);
+ kfree(datum);
+ return rc;
+}
+
+static int filename_trans_read_helper(struct policydb *p, void *fp)
+{
+ struct filename_trans_key *ft = NULL;
+ struct filename_trans_datum **dst, *datum, *first = NULL;
+ char *name = NULL;
+ u32 len, ttype, tclass, ndatum, i;
+ __le32 buf[3];
+ int rc;
+
+ /* length of the path component string */
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ return rc;
+ len = le32_to_cpu(buf[0]);
+
+ /* path component string */
+ rc = str_read(&name, GFP_KERNEL, fp, len);
+ if (rc)
+ return rc;
+
+ rc = next_entry(buf, fp, sizeof(u32) * 3);
+ if (rc)
+ goto out;
+
+ ttype = le32_to_cpu(buf[0]);
+ tclass = le32_to_cpu(buf[1]);
+
+ ndatum = le32_to_cpu(buf[2]);
+ if (ndatum == 0) {
+ pr_err("SELinux: Filename transition key with no datum\n");
+ rc = -ENOENT;
+ goto out;
+ }
+
+ dst = &first;
+ for (i = 0; i < ndatum; i++) {
+ rc = -ENOMEM;
+ datum = kmalloc(sizeof(*datum), GFP_KERNEL);
+ if (!datum)
+ goto out;
+
+ *dst = datum;
+
+ /* ebitmap_read() will at least init the bitmap */
+ rc = ebitmap_read(&datum->stypes, fp);
+ if (rc)
+ goto out;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+
+ datum->otype = le32_to_cpu(buf[0]);
+ datum->next = NULL;
+
+ dst = &datum->next;
+ }
+
+ rc = -ENOMEM;
+ ft = kmalloc(sizeof(*ft), GFP_KERNEL);
+ if (!ft)
+ goto out;
+
+ ft->ttype = ttype;
+ ft->tclass = tclass;
+ ft->name = name;
+
+ rc = hashtab_insert(&p->filename_trans, ft, first,
+ filenametr_key_params);
+ if (rc == -EEXIST)
+ pr_err("SELinux: Duplicate filename transition key\n");
+ if (rc)
+ goto out;
+
+ return ebitmap_set_bit(&p->filename_trans_ttypes, ttype, 1);
+
+out:
+ kfree(ft);
+ kfree(name);
+ while (first) {
+ datum = first;
+ first = first->next;
+
+ ebitmap_destroy(&datum->stypes);
+ kfree(datum);
+ }
+ return rc;
+}
+
static int filename_trans_read(struct policydb *p, void *fp)
{
- struct filename_trans *ft;
- struct filename_trans_datum *otype;
- char *name;
- u32 nel, len;
- __le32 buf[4];
+ u32 nel;
+ __le32 buf[1];
int rc, i;
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
@@ -1887,69 +2073,31 @@
return rc;
nel = le32_to_cpu(buf[0]);
- for (i = 0; i < nel; i++) {
- otype = NULL;
- name = NULL;
+ if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
+ p->compat_filename_trans_count = nel;
- rc = -ENOMEM;
- ft = kzalloc(sizeof(*ft), GFP_KERNEL);
- if (!ft)
- goto out;
-
- rc = -ENOMEM;
- otype = kmalloc(sizeof(*otype), GFP_KERNEL);
- if (!otype)
- goto out;
-
- /* length of the path component string */
- rc = next_entry(buf, fp, sizeof(u32));
+ rc = hashtab_init(&p->filename_trans, (1 << 11));
if (rc)
- goto out;
- len = le32_to_cpu(buf[0]);
+ return rc;
- /* path component string */
- rc = str_read(&name, GFP_KERNEL, fp, len);
+ for (i = 0; i < nel; i++) {
+ rc = filename_trans_read_helper_compat(p, fp);
+ if (rc)
+ return rc;
+ }
+ } else {
+ rc = hashtab_init(&p->filename_trans, nel);
if (rc)
- goto out;
+ return rc;
- ft->name = name;
-
- rc = next_entry(buf, fp, sizeof(u32) * 4);
- if (rc)
- goto out;
-
- ft->stype = le32_to_cpu(buf[0]);
- ft->ttype = le32_to_cpu(buf[1]);
- ft->tclass = le32_to_cpu(buf[2]);
-
- otype->otype = le32_to_cpu(buf[3]);
-
- rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
- if (rc)
- goto out;
-
- rc = hashtab_insert(p->filename_trans, ft, otype);
- if (rc) {
- /*
- * Do not return -EEXIST to the caller, or the system
- * will not boot.
- */
- if (rc != -EEXIST)
- goto out;
- /* But free memory to avoid memory leak. */
- kfree(ft);
- kfree(name);
- kfree(otype);
+ for (i = 0; i < nel; i++) {
+ rc = filename_trans_read_helper(p, fp);
+ if (rc)
+ return rc;
}
}
- hash_eval(p->filename_trans, "filenametr");
+ hash_eval(&p->filename_trans, "filenametr");
return 0;
-out:
- kfree(ft);
- kfree(name);
- kfree(otype);
-
- return rc;
}
static int genfs_read(struct policydb *p, void *fp)
@@ -2254,17 +2402,16 @@
int policydb_read(struct policydb *p, void *fp)
{
struct role_allow *ra, *lra;
- struct role_trans *tr, *ltr;
+ struct role_trans_key *rtk = NULL;
+ struct role_trans_datum *rtd = NULL;
int i, j, rc;
__le32 buf[4];
- u32 len, nprim, nel;
+ u32 len, nprim, nel, perm;
char *policydb_str;
struct policydb_compat_info *info;
- rc = policydb_init(p);
- if (rc)
- return rc;
+ policydb_init(p);
/* Read the magic number and string length. */
rc = next_entry(buf, fp, sizeof(u32) * 2);
@@ -2380,8 +2527,19 @@
goto bad;
nprim = le32_to_cpu(buf[0]);
nel = le32_to_cpu(buf[1]);
+
+ rc = symtab_init(&p->symtab[i], nel);
+ if (rc)
+ goto out;
+
+ if (i == SYM_ROLES) {
+ rc = roles_init(p);
+ if (rc)
+ goto out;
+ }
+
for (j = 0; j < nel; j++) {
- rc = read_f[i](p, p->symtab[i].table, fp);
+ rc = read_f[i](p, &p->symtab[i], fp);
if (rc)
goto bad;
}
@@ -2391,8 +2549,10 @@
rc = -EINVAL;
p->process_class = string_to_security_class(p, "process");
- if (!p->process_class)
+ if (!p->process_class) {
+ pr_err("SELinux: process class is required, not defined in policy\n");
goto bad;
+ }
rc = avtab_read(&p->te_avtab, fp, p);
if (rc)
@@ -2408,39 +2568,50 @@
if (rc)
goto bad;
nel = le32_to_cpu(buf[0]);
- ltr = NULL;
+
+ rc = hashtab_init(&p->role_tr, nel);
+ if (rc)
+ goto bad;
for (i = 0; i < nel; i++) {
rc = -ENOMEM;
- tr = kzalloc(sizeof(*tr), GFP_KERNEL);
- if (!tr)
+ rtk = kmalloc(sizeof(*rtk), GFP_KERNEL);
+ if (!rtk)
goto bad;
- if (ltr)
- ltr->next = tr;
- else
- p->role_tr = tr;
+
+ rc = -ENOMEM;
+ rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+ goto bad;
+
rc = next_entry(buf, fp, sizeof(u32)*3);
if (rc)
goto bad;
rc = -EINVAL;
- tr->role = le32_to_cpu(buf[0]);
- tr->type = le32_to_cpu(buf[1]);
- tr->new_role = le32_to_cpu(buf[2]);
+ rtk->role = le32_to_cpu(buf[0]);
+ rtk->type = le32_to_cpu(buf[1]);
+ rtd->new_role = le32_to_cpu(buf[2]);
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
goto bad;
- tr->tclass = le32_to_cpu(buf[0]);
+ rtk->tclass = le32_to_cpu(buf[0]);
} else
- tr->tclass = p->process_class;
+ rtk->tclass = p->process_class;
rc = -EINVAL;
- if (!policydb_role_isvalid(p, tr->role) ||
- !policydb_type_isvalid(p, tr->type) ||
- !policydb_class_isvalid(p, tr->tclass) ||
- !policydb_role_isvalid(p, tr->new_role))
+ if (!policydb_role_isvalid(p, rtk->role) ||
+ !policydb_type_isvalid(p, rtk->type) ||
+ !policydb_class_isvalid(p, rtk->tclass) ||
+ !policydb_role_isvalid(p, rtd->new_role))
goto bad;
- ltr = tr;
+
+ rc = hashtab_insert(&p->role_tr, rtk, rtd, roletr_key_params);
+ if (rc)
+ goto bad;
+
+ rtk = NULL;
+ rtd = NULL;
}
rc = next_entry(buf, fp, sizeof(u32));
@@ -2479,10 +2650,18 @@
goto bad;
rc = -EINVAL;
- p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
- p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
- if (!p->process_trans_perms)
+ perm = string_to_av_perm(p, p->process_class, "transition");
+ if (!perm) {
+ pr_err("SELinux: process transition permission is required, not defined in policy\n");
goto bad;
+ }
+ p->process_trans_perms = perm;
+ perm = string_to_av_perm(p, p->process_class, "dyntransition");
+ if (!perm) {
+ pr_err("SELinux: process dyntransition permission is required, not defined in policy\n");
+ goto bad;
+ }
+ p->process_trans_perms |= perm;
rc = ocontext_read(p, info, fp);
if (rc)
@@ -2529,6 +2708,8 @@
out:
return rc;
bad:
+ kfree(rtk);
+ kfree(rtd);
policydb_destroy(p);
goto out;
}
@@ -2646,43 +2827,49 @@
return 0;
}
-static int role_trans_write(struct policydb *p, void *fp)
+static int role_trans_write_one(void *key, void *datum, void *ptr)
{
- struct role_trans *r = p->role_tr;
- struct role_trans *tr;
- u32 buf[3];
- size_t nel;
+ struct role_trans_key *rtk = key;
+ struct role_trans_datum *rtd = datum;
+ struct policy_data *pd = ptr;
+ void *fp = pd->fp;
+ struct policydb *p = pd->p;
+ __le32 buf[3];
int rc;
- nel = 0;
- for (tr = r; tr; tr = tr->next)
- nel++;
- buf[0] = cpu_to_le32(nel);
+ buf[0] = cpu_to_le32(rtk->role);
+ buf[1] = cpu_to_le32(rtk->type);
+ buf[2] = cpu_to_le32(rtd->new_role);
+ rc = put_entry(buf, sizeof(u32), 3, fp);
+ if (rc)
+ return rc;
+ if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+ buf[0] = cpu_to_le32(rtk->tclass);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+static int role_trans_write(struct policydb *p, void *fp)
+{
+ struct policy_data pd = { .p = p, .fp = fp };
+ __le32 buf[1];
+ int rc;
+
+ buf[0] = cpu_to_le32(p->role_tr.nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
- for (tr = r; tr; tr = tr->next) {
- buf[0] = cpu_to_le32(tr->role);
- buf[1] = cpu_to_le32(tr->type);
- buf[2] = cpu_to_le32(tr->new_role);
- rc = put_entry(buf, sizeof(u32), 3, fp);
- if (rc)
- return rc;
- if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
- buf[0] = cpu_to_le32(tr->tclass);
- rc = put_entry(buf, sizeof(u32), 1, fp);
- if (rc)
- return rc;
- }
- }
- return 0;
+ return hashtab_map(&p->role_tr, role_trans_write_one, &pd);
}
static int role_allow_write(struct role_allow *r, void *fp)
{
struct role_allow *ra;
- u32 buf[2];
+ __le32 buf[2];
size_t nel;
int rc;
@@ -2770,7 +2957,7 @@
buf[0] = cpu_to_le32(len);
buf[1] = cpu_to_le32(comdatum->value);
buf[2] = cpu_to_le32(comdatum->permissions.nprim);
- buf[3] = cpu_to_le32(comdatum->permissions.table->nel);
+ buf[3] = cpu_to_le32(comdatum->permissions.table.nel);
rc = put_entry(buf, sizeof(u32), 4, fp);
if (rc)
return rc;
@@ -2779,7 +2966,7 @@
if (rc)
return rc;
- rc = hashtab_map(comdatum->permissions.table, perm_write, fp);
+ rc = hashtab_map(&comdatum->permissions.table, perm_write, fp);
if (rc)
return rc;
@@ -2878,10 +3065,7 @@
buf[1] = cpu_to_le32(len2);
buf[2] = cpu_to_le32(cladatum->value);
buf[3] = cpu_to_le32(cladatum->permissions.nprim);
- if (cladatum->permissions.table)
- buf[4] = cpu_to_le32(cladatum->permissions.table->nel);
- else
- buf[4] = 0;
+ buf[4] = cpu_to_le32(cladatum->permissions.table.nel);
buf[5] = cpu_to_le32(ncons);
rc = put_entry(buf, sizeof(u32), 6, fp);
if (rc)
@@ -2897,7 +3081,7 @@
return rc;
}
- rc = hashtab_map(cladatum->permissions.table, perm_write, fp);
+ rc = hashtab_map(&cladatum->permissions.table, perm_write, fp);
if (rc)
return rc;
@@ -3255,14 +3439,6 @@
return 0;
}
-static int hashtab_cnt(void *key, void *data, void *ptr)
-{
- int *cnt = ptr;
- *cnt = *cnt + 1;
-
- return 0;
-}
-
static int range_write_helper(void *key, void *data, void *ptr)
{
__le32 buf[2];
@@ -3294,41 +3470,71 @@
static int range_write(struct policydb *p, void *fp)
{
__le32 buf[1];
- int rc, nel;
+ int rc;
struct policy_data pd;
pd.p = p;
pd.fp = fp;
- /* count the number of entries in the hashtab */
- nel = 0;
- rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
- if (rc)
- return rc;
-
- buf[0] = cpu_to_le32(nel);
+ buf[0] = cpu_to_le32(p->range_tr.nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
/* actually write all of the entries */
- rc = hashtab_map(p->range_tr, range_write_helper, &pd);
+ rc = hashtab_map(&p->range_tr, range_write_helper, &pd);
if (rc)
return rc;
return 0;
}
+static int filename_write_helper_compat(void *key, void *data, void *ptr)
+{
+ struct filename_trans_key *ft = key;
+ struct filename_trans_datum *datum = data;
+ struct ebitmap_node *node;
+ void *fp = ptr;
+ __le32 buf[4];
+ int rc;
+ u32 bit, len = strlen(ft->name);
+
+ do {
+ ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
+ buf[0] = cpu_to_le32(len);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
+
+ rc = put_entry(ft->name, sizeof(char), len, fp);
+ if (rc)
+ return rc;
+
+ 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);
+
+ rc = put_entry(buf, sizeof(u32), 4, fp);
+ if (rc)
+ return rc;
+ }
+
+ datum = datum->next;
+ } while (unlikely(datum));
+
+ return 0;
+}
+
static int filename_write_helper(void *key, void *data, void *ptr)
{
- __le32 buf[4];
- struct filename_trans *ft = key;
- struct filename_trans_datum *otype = data;
+ struct filename_trans_key *ft = key;
+ struct filename_trans_datum *datum;
void *fp = ptr;
+ __le32 buf[3];
int rc;
- u32 len;
+ u32 ndatum, len = strlen(ft->name);
- len = strlen(ft->name);
buf[0] = cpu_to_le32(len);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
@@ -3338,42 +3544,62 @@
if (rc)
return rc;
- buf[0] = cpu_to_le32(ft->stype);
- buf[1] = cpu_to_le32(ft->ttype);
- buf[2] = cpu_to_le32(ft->tclass);
- buf[3] = cpu_to_le32(otype->otype);
+ ndatum = 0;
+ datum = data;
+ do {
+ ndatum++;
+ datum = datum->next;
+ } while (unlikely(datum));
- rc = put_entry(buf, sizeof(u32), 4, fp);
+ buf[0] = cpu_to_le32(ft->ttype);
+ buf[1] = cpu_to_le32(ft->tclass);
+ buf[2] = cpu_to_le32(ndatum);
+ rc = put_entry(buf, sizeof(u32), 3, fp);
if (rc)
return rc;
+ datum = data;
+ do {
+ rc = ebitmap_write(&datum->stypes, fp);
+ if (rc)
+ return rc;
+
+ buf[0] = cpu_to_le32(datum->otype);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
+
+ datum = datum->next;
+ } while (unlikely(datum));
+
return 0;
}
static int filename_trans_write(struct policydb *p, void *fp)
{
- u32 nel;
__le32 buf[1];
int rc;
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
return 0;
- nel = 0;
- rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
- if (rc)
- return rc;
+ if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
+ buf[0] = cpu_to_le32(p->compat_filename_trans_count);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
- buf[0] = cpu_to_le32(nel);
- rc = put_entry(buf, sizeof(u32), 1, fp);
- if (rc)
- return rc;
+ rc = hashtab_map(&p->filename_trans,
+ filename_write_helper_compat, fp);
+ } else {
+ buf[0] = cpu_to_le32(p->filename_trans.nel);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
- rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
- if (rc)
- return rc;
-
- return 0;
+ rc = hashtab_map(&p->filename_trans, filename_write_helper, fp);
+ }
+ return rc;
}
/*
@@ -3460,12 +3686,12 @@
pd.p = p;
buf[0] = cpu_to_le32(p->symtab[i].nprim);
- buf[1] = cpu_to_le32(p->symtab[i].table->nel);
+ buf[1] = cpu_to_le32(p->symtab[i].table.nel);
rc = put_entry(buf, sizeof(u32), 2, fp);
if (rc)
return rc;
- rc = hashtab_map(p->symtab[i].table, write_f[i], &pd);
+ rc = hashtab_map(&p->symtab[i].table, write_f[i], &pd);
if (rc)
return rc;
}
@@ -3474,7 +3700,7 @@
if (rc)
return rc;
- rc = cond_write_list(p, p->cond_list, fp);
+ rc = cond_write_list(p, fp);
if (rc)
return rc;