@@ -46,10 +46,11 @@
#define POLICYDB_VERSION_INFINIBAND 31
#define POLICYDB_VERSION_GLBLUB 32
#define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */
+#define POLICYDB_VERSION_PREFIX_SUFFIX 34 /* prefix/suffix filename transitions */
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COMP_FTRANS
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_PREFIX_SUFFIX
/* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f
@@ -157,6 +157,11 @@ static const struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_PREFIX_SUFFIX,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static const struct policydb_compat_info *policydb_lookup_compat(unsigned int version)
@@ -444,10 +449,33 @@ static const struct hashtab_key_params filenametr_key_params = {
.cmp = filenametr_cmp,
};
-struct filename_trans_datum *policydb_filenametr_search(
- struct policydb *p, struct filename_trans_key *key)
+/**
+ * policydb_filenametr_search() - Search for filename transition in policy
+ * @p: policydb structure to search in
+ * @match_type: filename transition match type to search for
+ * @key: key to search for
+ * @stype: source type to search for, when stype is zero, the function will
+ * return head of the linked list with matching key, otherwise it will
+ * traverse the linked list to find the item with matching stype
+ *
+ * Return: head of the linked list of filename transition datums or single item
+ * of the list, based on the stype value
+ */
+struct filename_trans_datum *policydb_filenametr_search(struct policydb *p,
+ unsigned int match_type, struct filename_trans_key *key, u32 stype)
{
- return hashtab_search(&p->filename_trans, key, filenametr_key_params);
+ struct filename_trans_datum *datum = hashtab_search(
+ &p->filename_trans[match_type], key, filenametr_key_params);
+
+ if (stype) {
+ while (datum) {
+ if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
+ return datum;
+ }
+ datum = datum->next;
+ }
+ }
+ return datum;
}
static u32 rangetr_hash(const void *k)
@@ -840,8 +868,10 @@ void policydb_destroy(struct policydb *p)
}
kfree(lra);
- hashtab_map(&p->filename_trans, filenametr_destroy, NULL);
- hashtab_destroy(&p->filename_trans);
+ for (unsigned int i = 0; i < FILENAME_TRANS_MATCH_NUM; i++) {
+ hashtab_map(&p->filename_trans[i], filenametr_destroy, NULL);
+ hashtab_destroy(&p->filename_trans[i]);
+ }
hashtab_map(&p->range_tr, range_tr_destroy, NULL);
hashtab_destroy(&p->range_tr);
@@ -1916,7 +1946,9 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
otype = le32_to_cpu(buf[3]);
last = NULL;
- datum = policydb_filenametr_search(p, &key);
+ // this version does not support other than exact match
+ datum = policydb_filenametr_search(p, FILENAME_TRANS_MATCH_EXACT, &key,
+ 0);
while (datum) {
if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
/* conflicting/duplicate rules are ignored */
@@ -1946,8 +1978,9 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
if (!ft)
goto out;
- rc = hashtab_insert(&p->filename_trans, ft, datum,
- filenametr_key_params);
+ rc = hashtab_insert(
+ &p->filename_trans[FILENAME_TRANS_MATCH_EXACT],
+ ft, datum, filenametr_key_params);
if (rc)
goto out;
name = NULL;
@@ -1968,7 +2001,8 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
return rc;
}
-static int filename_trans_read_helper(struct policydb *p, void *fp)
+static int filename_trans_read_helper(struct policydb *p, void *fp,
+ unsigned int match_type)
{
struct filename_trans_key *ft = NULL;
struct filename_trans_datum **dst, *datum, *first = NULL;
@@ -2035,7 +2069,7 @@ static int filename_trans_read_helper(struct policydb *p, void *fp)
ft->tclass = tclass;
ft->name = name;
- rc = hashtab_insert(&p->filename_trans, ft, first,
+ rc = hashtab_insert(&p->filename_trans[match_type], ft, first,
filenametr_key_params);
if (rc == -EEXIST)
pr_err("SELinux: Duplicate filename transition key\n");
@@ -2057,7 +2091,8 @@ static int filename_trans_read_helper(struct policydb *p, void *fp)
return rc;
}
-static int filename_trans_read(struct policydb *p, void *fp)
+static int filename_trans_read(struct policydb *p, void *fp,
+ unsigned int match_type)
{
u32 nel, i;
__le32 buf[1];
@@ -2074,27 +2109,28 @@ static int filename_trans_read(struct policydb *p, void *fp)
if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
p->compat_filename_trans_count = nel;
- rc = hashtab_init(&p->filename_trans, (1 << 11));
+ rc = hashtab_init(&p->filename_trans[match_type], (1 << 11));
if (rc)
return rc;
for (i = 0; i < nel; i++) {
+ // this version does not support other than exact match
rc = filename_trans_read_helper_compat(p, fp);
if (rc)
return rc;
}
} else {
- rc = hashtab_init(&p->filename_trans, nel);
+ rc = hashtab_init(&p->filename_trans[match_type], nel);
if (rc)
return rc;
for (i = 0; i < nel; i++) {
- rc = filename_trans_read_helper(p, fp);
+ rc = filename_trans_read_helper(p, fp, match_type);
if (rc)
return rc;
}
}
- hash_eval(&p->filename_trans, "filenametr");
+ hash_eval(&p->filename_trans[match_type], "filenametr");
return 0;
}
@@ -2643,9 +2679,17 @@ int policydb_read(struct policydb *p, void *fp)
lra = ra;
}
- rc = filename_trans_read(p, fp);
+ rc = filename_trans_read(p, fp, FILENAME_TRANS_MATCH_EXACT);
if (rc)
goto bad;
+ if (p->policyvers >= POLICYDB_VERSION_PREFIX_SUFFIX) {
+ rc = filename_trans_read(p, fp, FILENAME_TRANS_MATCH_PREFIX);
+ if (rc)
+ goto bad;
+ rc = filename_trans_read(p, fp, FILENAME_TRANS_MATCH_SUFFIX);
+ if (rc)
+ goto bad;
+ }
rc = policydb_index(p);
if (rc)
@@ -3576,7 +3620,8 @@ 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_trans_write(struct policydb *p, void *fp,
+ unsigned int match_type)
{
__le32 buf[1];
int rc;
@@ -3590,15 +3635,16 @@ static int filename_trans_write(struct policydb *p, void *fp)
if (rc)
return rc;
- rc = hashtab_map(&p->filename_trans,
+ rc = hashtab_map(&p->filename_trans[match_type],
filename_write_helper_compat, fp);
} else {
- buf[0] = cpu_to_le32(p->filename_trans.nel);
+ buf[0] = cpu_to_le32(p->filename_trans[match_type].nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
- rc = hashtab_map(&p->filename_trans, filename_write_helper, fp);
+ rc = hashtab_map(&p->filename_trans[match_type],
+ filename_write_helper, fp);
}
return rc;
}
@@ -3713,9 +3759,17 @@ int policydb_write(struct policydb *p, void *fp)
if (rc)
return rc;
- rc = filename_trans_write(p, fp);
+ rc = filename_trans_write(p, fp, FILENAME_TRANS_MATCH_EXACT);
if (rc)
return rc;
+ if (p->policyvers >= POLICYDB_VERSION_PREFIX_SUFFIX) {
+ rc = filename_trans_write(p, fp, FILENAME_TRANS_MATCH_PREFIX);
+ if (rc)
+ return rc;
+ rc = filename_trans_write(p, fp, FILENAME_TRANS_MATCH_SUFFIX);
+ if (rc)
+ return rc;
+ }
rc = ocontext_write(p, info, fp);
if (rc)
@@ -235,6 +235,13 @@ struct genfs {
#define OCON_IBENDPORT 8 /* Infiniband end ports */
#define OCON_NUM 9
+enum {
+ FILENAME_TRANS_MATCH_EXACT,
+ FILENAME_TRANS_MATCH_PREFIX,
+ FILENAME_TRANS_MATCH_SUFFIX,
+ FILENAME_TRANS_MATCH_NUM,
+};
+
/* The policy database */
struct policydb {
int mls_enabled;
@@ -269,7 +276,7 @@ struct policydb {
/* quickly exclude lookups when parent ttype has no rules */
struct ebitmap filename_trans_ttypes;
/* actual set of filename_trans rules */
- struct hashtab filename_trans;
+ struct hashtab filename_trans[FILENAME_TRANS_MATCH_NUM];
/* only used if policyvers < POLICYDB_VERSION_COMP_FTRANS */
u32 compat_filename_trans_count;
@@ -325,7 +332,8 @@ extern int policydb_read(struct policydb *p, void *fp);
extern int policydb_write(struct policydb *p, void *fp);
extern struct filename_trans_datum *policydb_filenametr_search(
- struct policydb *p, struct filename_trans_key *key);
+ struct policydb *p, unsigned int match_type,
+ struct filename_trans_key *key, u32 stype);
extern struct mls_range *policydb_rangetr_search(
struct policydb *p, struct range_trans *key);
@@ -1661,13 +1661,16 @@ static int compute_sid_handle_invalid_context(
return -EACCES;
}
-static void filename_compute_type(struct policydb *policydb,
+static int filename_compute_type(struct policydb *policydb,
struct context *newcontext,
u32 stype, u32 ttype, u16 tclass,
const char *objname)
{
struct filename_trans_key ft;
struct filename_trans_datum *datum;
+ size_t name_len = strlen(objname);
+ size_t i;
+ char *name_copy;
/*
* Most filename trans rules are going to live in specific directories
@@ -1675,20 +1678,50 @@ static void filename_compute_type(struct policydb *policydb,
* if the ttype does not contain any rules.
*/
if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
- return;
+ return 0;
ft.ttype = ttype;
ft.tclass = tclass;
+
+ /* Search for exact rules */
ft.name = objname;
+ datum = policydb_filenametr_search(policydb, FILENAME_TRANS_MATCH_EXACT,
+ &ft, stype);
+ if (datum) {
+ newcontext->type = datum->otype;
+ return 0;
+ }
- datum = policydb_filenametr_search(policydb, &ft);
- while (datum) {
- if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
+ /* Search for prefix rules */
+ name_copy = kstrdup(objname, GFP_KERNEL);
+ if (!name_copy)
+ return -ENOMEM;
+ ft.name = name_copy;
+ for (i = name_len; i > 0; i--) {
+ name_copy[i] = '\0';
+ datum = policydb_filenametr_search(policydb,
+ FILENAME_TRANS_MATCH_PREFIX,
+ &ft, stype);
+ if (datum) {
newcontext->type = datum->otype;
- return;
+ kfree(name_copy);
+ return 0;
}
- datum = datum->next;
}
+ kfree(name_copy);
+
+ /* Search for suffix rules */
+ for (i = 0; i < name_len; i++) {
+ ft.name = &objname[i];
+ datum = policydb_filenametr_search(policydb,
+ FILENAME_TRANS_MATCH_SUFFIX,
+ &ft, stype);
+ if (datum) {
+ newcontext->type = datum->otype;
+ return 0;
+ }
+ }
+ return 0;
}
static int security_compute_sid(u32 ssid,
@@ -1833,9 +1866,13 @@ static int security_compute_sid(u32 ssid,
}
/* if we have a objname this is a file trans check so check those rules */
- if (objname)
- filename_compute_type(policydb, &newcontext, scontext->type,
- tcontext->type, tclass, objname);
+ if (objname) {
+ rc = filename_compute_type(policydb, &newcontext,
+ scontext->type, tcontext->type,
+ tclass, objname);
+ if (rc)
+ goto out_unlock;
+ }
/* Check for class-specific changes. */
if (specified & AVTAB_TRANSITION) {