diff options
Diffstat (limited to 'security/selinux/ss')
-rw-r--r-- | security/selinux/ss/avtab.h | 22 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 5 | ||||
-rw-r--r-- | security/selinux/ss/mls.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 130 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 14 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 73 |
6 files changed, 214 insertions, 33 deletions
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 3417f9cc1cb..63ce2f9e441 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -14,7 +14,7 @@ * * Copyright (C) 2003 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> @@ -27,16 +27,16 @@ struct avtab_key { u16 source_type; /* source type */ u16 target_type; /* target type */ u16 target_class; /* target object class */ -#define AVTAB_ALLOWED 1 -#define AVTAB_AUDITALLOW 2 -#define AVTAB_AUDITDENY 4 -#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) -#define AVTAB_TRANSITION 16 -#define AVTAB_MEMBER 32 -#define AVTAB_CHANGE 64 -#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) -#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ -#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ +#define AVTAB_ALLOWED 0x0001 +#define AVTAB_AUDITALLOW 0x0002 +#define AVTAB_AUDITDENY 0x0004 +#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) +#define AVTAB_TRANSITION 0x0010 +#define AVTAB_MEMBER 0x0020 +#define AVTAB_CHANGE 0x0040 +#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) +#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ +#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ u16 specified; /* what field is specified */ }; diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 1ef8e4e8988..e96174216bc 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -512,7 +512,8 @@ int mls_compute_sid(struct context *scontext, struct context *tcontext, u16 tclass, u32 specified, - struct context *newcontext) + struct context *newcontext, + bool sock) { struct range_trans rtr; struct mls_range *r; @@ -531,7 +532,7 @@ int mls_compute_sid(struct context *scontext, return mls_range_set(newcontext, r); /* Fallthrough */ case AVTAB_CHANGE: - if (tclass == policydb.process_class) + if ((tclass == policydb.process_class) || (sock == true)) /* Use the process MLS attributes. */ return mls_context_cpy(newcontext, scontext); else diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index cd9152632e5..037bf9d82d4 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -49,7 +49,8 @@ int mls_compute_sid(struct context *scontext, struct context *tcontext, u16 tclass, u32 specified, - struct context *newcontext); + struct context *newcontext, + bool sock); int mls_setup_user_range(struct context *fromcon, struct user_datum *user, struct context *usercon); diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 57363562f0f..e7b850ad57e 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -123,6 +123,11 @@ static struct policydb_compat_info policydb_compat[] = { .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, + { + .version = POLICYDB_VERSION_FILENAME_TRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, }; static struct policydb_compat_info *policydb_lookup_compat(int version) @@ -704,6 +709,7 @@ void policydb_destroy(struct policydb *p) int i; struct role_allow *ra, *lra = NULL; struct role_trans *tr, *ltr = NULL; + struct filename_trans *ft, *nft; for (i = 0; i < SYM_NUM; i++) { cond_resched(); @@ -781,6 +787,15 @@ void policydb_destroy(struct policydb *p) } flex_array_free(p->type_attr_map_array); } + + ft = p->filename_trans; + while (ft) { + nft = ft->next; + kfree(ft->name); + kfree(ft); + ft = nft; + } + ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->permissive_map); @@ -1788,6 +1803,76 @@ out: return rc; } +static int filename_trans_read(struct policydb *p, void *fp) +{ + struct filename_trans *ft, *last; + u32 nel, len; + char *name; + __le32 buf[4]; + int rc, i; + + if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) + return 0; + + rc = next_entry(buf, fp, sizeof(u32)); + if (rc) + goto out; + nel = le32_to_cpu(buf[0]); + + printk(KERN_ERR "%s: nel=%d\n", __func__, nel); + + last = p->filename_trans; + while (last && last->next) + last = last->next; + + for (i = 0; i < nel; i++) { + rc = -ENOMEM; + ft = kzalloc(sizeof(*ft), GFP_KERNEL); + if (!ft) + goto out; + + /* add it to the tail of the list */ + if (!last) + p->filename_trans = ft; + else + last->next = ft; + last = ft; + + /* length of the path component string */ + rc = next_entry(buf, fp, sizeof(u32)); + if (rc) + goto out; + len = le32_to_cpu(buf[0]); + + rc = -ENOMEM; + name = kmalloc(len + 1, GFP_KERNEL); + if (!name) + goto out; + + ft->name = name; + + /* path component string */ + rc = next_entry(name, fp, len); + if (rc) + goto out; + name[len] = 0; + + printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->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]); + ft->otype = le32_to_cpu(buf[3]); + } + rc = 0; +out: + return rc; +} + static int genfs_read(struct policydb *p, void *fp) { int i, j, rc; @@ -2251,6 +2336,10 @@ int policydb_read(struct policydb *p, void *fp) lra = ra; } + rc = filename_trans_read(p, fp); + if (rc) + goto bad; + rc = policydb_index(p); if (rc) goto bad; @@ -3025,6 +3114,43 @@ static int range_write(struct policydb *p, void *fp) return 0; } +static int filename_trans_write(struct policydb *p, void *fp) +{ + struct filename_trans *ft; + u32 len, nel = 0; + __le32 buf[4]; + int rc; + + for (ft = p->filename_trans; ft; ft = ft->next) + nel++; + + buf[0] = cpu_to_le32(nel); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return rc; + + for (ft = p->filename_trans; ft; ft = ft->next) { + len = strlen(ft->name); + 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] = ft->stype; + buf[1] = ft->ttype; + buf[2] = ft->tclass; + buf[3] = ft->otype; + + rc = put_entry(buf, sizeof(u32), 4, fp); + if (rc) + return rc; + } + return 0; +} /* * Write the configuration data in a policy database * structure to a policy database binary representation @@ -3135,6 +3261,10 @@ int policydb_write(struct policydb *p, void *fp) if (rc) return rc; + rc = filename_trans_write(p, fp); + if (rc) + return rc; + rc = ocontext_write(p, info, fp); if (rc) return rc; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 4e3ab9d0b31..732ea4a6868 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -77,6 +77,15 @@ struct role_trans { struct role_trans *next; }; +struct filename_trans { + struct filename_trans *next; + u32 stype; /* current process */ + u32 ttype; /* parent dir context */ + u16 tclass; /* class of new object */ + const char *name; /* last path component */ + u32 otype; /* expected of new object */ +}; + struct role_allow { u32 role; /* current role */ u32 new_role; /* new role */ @@ -217,6 +226,9 @@ struct policydb { /* role transitions */ struct role_trans *role_tr; + /* file transitions with the last path component */ + struct filename_trans *filename_trans; + /* bools indexed by (value - 1) */ struct cond_bool_datum **bool_val_to_struct; /* type enforcement conditional access vectors and transitions */ @@ -302,7 +314,7 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) return 0; } -static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp) +static inline int put_entry(const void *buf, size_t bytes, int num, struct policy_file *fp) { size_t len = bytes * num; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index a03cfaf0ee0..3e7544d2a07 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -201,6 +201,21 @@ static u16 unmap_class(u16 tclass) return tclass; } +/* + * Get kernel value for class from its policy value + */ +static u16 map_class(u16 pol_value) +{ + u16 i; + + for (i = 1; i < current_mapping_size; i++) { + if (current_mapping[i].value == pol_value) + return i; + } + + return pol_value; +} + static void map_decision(u16 tclass, struct av_decision *avd, int allow_unknown) { @@ -1343,10 +1358,27 @@ out: return -EACCES; } +static void filename_compute_type(struct policydb *p, struct context *newcontext, + u32 scon, u32 tcon, u16 tclass, + const struct qstr *qstr) +{ + struct filename_trans *ft; + for (ft = p->filename_trans; ft; ft = ft->next) { + if (ft->stype == scon && + ft->ttype == tcon && + ft->tclass == tclass && + !strcmp(ft->name, qstr->name)) { + newcontext->type = ft->otype; + return; + } + } +} + static int security_compute_sid(u32 ssid, u32 tsid, u16 orig_tclass, u32 specified, + const struct qstr *qstr, u32 *out_sid, bool kern) { @@ -1357,6 +1389,7 @@ static int security_compute_sid(u32 ssid, struct avtab_node *node; u16 tclass; int rc = 0; + bool sock; if (!ss_initialized) { switch (orig_tclass) { @@ -1374,10 +1407,13 @@ static int security_compute_sid(u32 ssid, read_lock(&policy_rwlock); - if (kern) + if (kern) { tclass = unmap_class(orig_tclass); - else + sock = security_is_socket_class(orig_tclass); + } else { tclass = orig_tclass; + sock = security_is_socket_class(map_class(tclass)); + } scontext = sidtab_search(&sidtab, ssid); if (!scontext) { @@ -1408,7 +1444,7 @@ static int security_compute_sid(u32 ssid, } /* Set the role and type to default values. */ - if (tclass == policydb.process_class) { + if ((tclass == policydb.process_class) || (sock == true)) { /* Use the current role and type of process. */ newcontext.role = scontext->role; newcontext.type = scontext->type; @@ -1442,6 +1478,11 @@ static int security_compute_sid(u32 ssid, newcontext.type = avdatum->data; } + /* if we have a qstr this is a file trans check so check those rules */ + if (qstr) + filename_compute_type(&policydb, &newcontext, scontext->type, + tcontext->type, tclass, qstr); + /* Check for class-specific changes. */ if (tclass == policydb.process_class) { if (specified & AVTAB_TRANSITION) { @@ -1460,7 +1501,8 @@ static int security_compute_sid(u32 ssid, /* Set the MLS attributes. This is done last because it may allocate memory. */ - rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); + rc = mls_compute_sid(scontext, tcontext, tclass, specified, + &newcontext, sock); if (rc) goto out_unlock; @@ -1495,22 +1537,17 @@ out: * if insufficient memory is available, or %0 if the new SID was * computed successfully. */ -int security_transition_sid(u32 ssid, - u32 tsid, - u16 tclass, - u32 *out_sid) +int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, + const struct qstr *qstr, u32 *out_sid) { return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, - out_sid, true); + qstr, out_sid, true); } -int security_transition_sid_user(u32 ssid, - u32 tsid, - u16 tclass, - u32 *out_sid) +int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) { return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, - out_sid, false); + NULL, out_sid, false); } /** @@ -1531,8 +1568,8 @@ int security_member_sid(u32 ssid, u16 tclass, u32 *out_sid) { - return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid, - false); + return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, + out_sid, false); } /** @@ -1553,8 +1590,8 @@ int security_change_sid(u32 ssid, u16 tclass, u32 *out_sid) { - return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid, - false); + return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, + out_sid, false); } /* Clone the SID into the new SID table. */ |