summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/selinux/include/security.h3
-rw-r--r--security/selinux/ss/policydb.c212
2 files changed, 189 insertions, 26 deletions
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index d6036c018cf2..b0e02cfe3ce1 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -41,10 +41,11 @@
#define POLICYDB_VERSION_XPERMS_IOCTL 30
#define POLICYDB_VERSION_INFINIBAND 31
#define POLICYDB_VERSION_GLBLUB 32
+#define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_GLBLUB
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COMP_FTRANS
/* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index dc6729860bd6..ef8d5b46b05b 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -154,6 +154,11 @@ static struct policydb_compat_info policydb_compat[] = {
.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)
@@ -492,23 +497,16 @@ static int role_trans_cmp(struct hashtab *h, const void *k1, const void *k2)
/*
* Initialize a policy database structure.
*/
-static int policydb_init(struct policydb *p)
+static void policydb_init(struct policydb *p)
{
memset(p, 0, sizeof(*p));
avtab_init(&p->te_avtab);
cond_policydb_init(p);
- p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp,
- (1 << 11));
- if (!p->filename_trans)
- return -ENOMEM;
-
ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map);
-
- return 0;
}
/*
@@ -1862,7 +1860,7 @@ out:
return rc;
}
-static int filename_trans_read_one(struct policydb *p, void *fp)
+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;
@@ -1945,6 +1943,99 @@ out:
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);
+ if (rc == -EEXIST)
+ pr_err("SELinux: Duplicate filename transition key\n");
+ if (rc)
+ goto out;
+
+ rc = ebitmap_set_bit(&p->filename_trans_ttypes, ttype, 1);
+ if (rc)
+ return rc;
+
+ p->filename_trans_count += ndatum;
+ return 0;
+
+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)
{
u32 nel;
@@ -1959,12 +2050,29 @@ static int filename_trans_read(struct policydb *p, void *fp)
return rc;
nel = le32_to_cpu(buf[0]);
- p->filename_trans_count = nel;
+ if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
+ p->filename_trans_count = nel;
+ p->filename_trans = hashtab_create(filenametr_hash,
+ filenametr_cmp, (1 << 11));
+ if (!p->filename_trans)
+ return -ENOMEM;
- for (i = 0; i < nel; i++) {
- rc = filename_trans_read_one(p, fp);
- if (rc)
- return rc;
+ for (i = 0; i < nel; i++) {
+ rc = filename_trans_read_helper_compat(p, fp);
+ if (rc)
+ return rc;
+ }
+ } else {
+ p->filename_trans = hashtab_create(filenametr_hash,
+ filenametr_cmp, nel);
+ if (!p->filename_trans)
+ return -ENOMEM;
+
+ for (i = 0; i < nel; i++) {
+ rc = filename_trans_read_helper(p, fp);
+ if (rc)
+ return rc;
+ }
}
hash_eval(p->filename_trans, "filenametr");
return 0;
@@ -2281,9 +2389,7 @@ int policydb_read(struct policydb *p, void *fp)
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);
@@ -3367,7 +3473,7 @@ static int range_write(struct policydb *p, void *fp)
return 0;
}
-static int filename_write_helper(void *key, void *data, void *ptr)
+static int filename_write_helper_compat(void *key, void *data, void *ptr)
{
struct filename_trans_key *ft = key;
struct filename_trans_datum *datum = data;
@@ -3404,26 +3510,82 @@ static int filename_write_helper(void *key, void *data, void *ptr)
return 0;
}
-static int filename_trans_write(struct policydb *p, void *fp)
+static int filename_write_helper(void *key, void *data, void *ptr)
{
- __le32 buf[1];
+ struct filename_trans_key *ft = key;
+ struct filename_trans_datum *datum;
+ void *fp = ptr;
+ __le32 buf[3];
int rc;
+ u32 ndatum, len = strlen(ft->name);
- if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
- return 0;
-
- buf[0] = cpu_to_le32(p->filename_trans_count);
+ buf[0] = cpu_to_le32(len);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
- rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
+ rc = put_entry(ft->name, sizeof(char), len, fp);
if (rc)
return rc;
+ ndatum = 0;
+ datum = data;
+ do {
+ ndatum++;
+ datum = datum->next;
+ } while (unlikely(datum));
+
+ 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)
+{
+ __le32 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);
+ 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);
+ }
+ return rc;
+}
+
/*
* Write the configuration data in a policy database
* structure to a policy database binary representation