Merge branch 'next' into for-linus
This commit is contained in:
@@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
dst->range.level[0].sens = src->range.level[0].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
|
||||
if (rc)
|
||||
@@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
dst->range.level[0].sens = src->range.level[0].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
|
||||
if (rc)
|
||||
@@ -82,9 +76,6 @@ out:
|
||||
|
||||
static inline int mls_context_cmp(struct context *c1, struct context *c2)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
|
||||
ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
|
||||
(c1->range.level[1].sens == c2->range.level[1].sens) &&
|
||||
@@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2)
|
||||
|
||||
static inline void mls_context_destroy(struct context *c)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return;
|
||||
|
||||
ebitmap_destroy(&c->range.level[0].cat);
|
||||
ebitmap_destroy(&c->range.level[1].cat);
|
||||
mls_context_init(c);
|
||||
|
@@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context)
|
||||
struct ebitmap *e;
|
||||
struct ebitmap_node *node;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
|
||||
len = 1; /* for the beginning ":" */
|
||||
@@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context,
|
||||
struct ebitmap *e;
|
||||
struct ebitmap_node *node;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return;
|
||||
|
||||
scontextp = *scontext;
|
||||
@@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
|
||||
{
|
||||
struct user_datum *usrdatum;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!p->mls_enabled)
|
||||
return 1;
|
||||
|
||||
if (!mls_range_isvalid(p, &c->range))
|
||||
@@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol,
|
||||
struct cat_datum *catdatum, *rngdatum;
|
||||
int l, rc = -EINVAL;
|
||||
|
||||
if (!selinux_mls_enabled) {
|
||||
if (!pol->mls_enabled) {
|
||||
if (def_sid != SECSID_NULL && oldc)
|
||||
*scontext += strlen(*scontext)+1;
|
||||
return 0;
|
||||
@@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
|
||||
char *tmpstr, *freestr;
|
||||
int rc;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return -EINVAL;
|
||||
|
||||
/* we need freestr because mls_context_to_sid will change
|
||||
@@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
|
||||
/*
|
||||
* Copies the MLS range `range' into `context'.
|
||||
*/
|
||||
static inline int mls_range_set(struct context *context,
|
||||
int mls_range_set(struct context *context,
|
||||
struct mls_range *range)
|
||||
{
|
||||
int l, rc = 0;
|
||||
@@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context,
|
||||
int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
|
||||
struct context *usercon)
|
||||
{
|
||||
if (selinux_mls_enabled) {
|
||||
if (policydb.mls_enabled) {
|
||||
struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
|
||||
struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
|
||||
struct mls_level *user_low = &(user->range.level[0]);
|
||||
@@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp,
|
||||
struct ebitmap_node *node;
|
||||
int l, i;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
@@ -513,23 +513,21 @@ int mls_compute_sid(struct context *scontext,
|
||||
u32 specified,
|
||||
struct context *newcontext)
|
||||
{
|
||||
struct range_trans *rtr;
|
||||
struct range_trans rtr;
|
||||
struct mls_range *r;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
|
||||
switch (specified) {
|
||||
case AVTAB_TRANSITION:
|
||||
/* Look for a range transition rule. */
|
||||
for (rtr = policydb.range_tr; rtr; rtr = rtr->next) {
|
||||
if (rtr->source_type == scontext->type &&
|
||||
rtr->target_type == tcontext->type &&
|
||||
rtr->target_class == tclass) {
|
||||
/* Set the range from the rule */
|
||||
return mls_range_set(newcontext,
|
||||
&rtr->target_range);
|
||||
}
|
||||
}
|
||||
rtr.source_type = scontext->type;
|
||||
rtr.target_type = tcontext->type;
|
||||
rtr.target_class = tclass;
|
||||
r = hashtab_search(policydb.range_tr, &rtr);
|
||||
if (r)
|
||||
return mls_range_set(newcontext, r);
|
||||
/* Fallthrough */
|
||||
case AVTAB_CHANGE:
|
||||
if (tclass == policydb.process_class)
|
||||
@@ -541,8 +539,8 @@ int mls_compute_sid(struct context *scontext,
|
||||
case AVTAB_MEMBER:
|
||||
/* Use the process effective MLS attributes. */
|
||||
return mls_context_cpy_low(newcontext, scontext);
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
/* fall through */
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -561,7 +559,7 @@ int mls_compute_sid(struct context *scontext,
|
||||
void mls_export_netlbl_lvl(struct context *context,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return;
|
||||
|
||||
secattr->attr.mls.lvl = context->range.level[0].sens - 1;
|
||||
@@ -581,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context,
|
||||
void mls_import_netlbl_lvl(struct context *context,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return;
|
||||
|
||||
context->range.level[0].sens = secattr->attr.mls.lvl + 1;
|
||||
@@ -603,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context,
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
|
||||
rc = ebitmap_netlbl_export(&context->range.level[0].cat,
|
||||
@@ -631,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context,
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
|
||||
rc = ebitmap_netlbl_import(&context->range.level[0].cat,
|
||||
|
@@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p,
|
||||
|
||||
int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
|
||||
|
||||
int mls_range_set(struct context *context, struct mls_range *range);
|
||||
|
||||
int mls_convert_context(struct policydb *oldp,
|
||||
struct policydb *newp,
|
||||
struct context *context);
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#define _SS_MLS_TYPES_H_
|
||||
|
||||
#include "security.h"
|
||||
#include "ebitmap.h"
|
||||
|
||||
struct mls_level {
|
||||
u32 sens; /* sensitivity */
|
||||
@@ -27,18 +28,12 @@ struct mls_range {
|
||||
|
||||
static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
return ((l1->sens == l2->sens) &&
|
||||
ebitmap_cmp(&l1->cat, &l2->cat));
|
||||
}
|
||||
|
||||
static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
return ((l1->sens >= l2->sens) &&
|
||||
ebitmap_contains(&l1->cat, &l2->cat));
|
||||
}
|
||||
|
@@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
int selinux_mls_enabled;
|
||||
|
||||
static unsigned int symtab_sizes[SYM_NUM] = {
|
||||
2,
|
||||
32,
|
||||
@@ -177,6 +175,21 @@ out_free_role:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static u32 rangetr_hash(struct hashtab *h, const void *k)
|
||||
{
|
||||
const struct range_trans *key = k;
|
||||
return (key->source_type + (key->target_type << 3) +
|
||||
(key->target_class << 5)) & (h->size - 1);
|
||||
}
|
||||
|
||||
static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
|
||||
{
|
||||
const struct range_trans *key1 = k1, *key2 = k2;
|
||||
return (key1->source_type != key2->source_type ||
|
||||
key1->target_type != key2->target_type ||
|
||||
key1->target_class != key2->target_class);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a policy database structure.
|
||||
*/
|
||||
@@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p)
|
||||
if (rc)
|
||||
goto out_free_symtab;
|
||||
|
||||
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
|
||||
if (!p->range_tr)
|
||||
goto out_free_symtab;
|
||||
|
||||
ebitmap_init(&p->policycaps);
|
||||
ebitmap_init(&p->permissive_map);
|
||||
|
||||
@@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s)
|
||||
info.slots_used, h->size, info.max_chain_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void rangetr_hash_eval(struct hashtab *h)
|
||||
{
|
||||
struct hashtab_info info;
|
||||
|
||||
hashtab_stat(h, &info);
|
||||
printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, "
|
||||
"longest chain length %d\n", h->nel,
|
||||
info.slots_used, h->size, info.max_chain_len);
|
||||
}
|
||||
#else
|
||||
static inline void rangetr_hash_eval(struct hashtab *h)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p)
|
||||
|
||||
printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools",
|
||||
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
|
||||
if (selinux_mls_enabled)
|
||||
if (p->mls_enabled)
|
||||
printk(", %d sens, %d cats", p->p_levels.nprim,
|
||||
p->p_cats.nprim);
|
||||
printk("\n");
|
||||
@@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
||||
cat_destroy,
|
||||
};
|
||||
|
||||
static int range_tr_destroy(void *key, void *datum, void *p)
|
||||
{
|
||||
struct mls_range *rt = datum;
|
||||
kfree(key);
|
||||
ebitmap_destroy(&rt->level[0].cat);
|
||||
ebitmap_destroy(&rt->level[1].cat);
|
||||
kfree(datum);
|
||||
cond_resched();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ocontext_destroy(struct ocontext *c, int i)
|
||||
{
|
||||
context_destroy(&c->context[0]);
|
||||
@@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p)
|
||||
int i;
|
||||
struct role_allow *ra, *lra = NULL;
|
||||
struct role_trans *tr, *ltr = NULL;
|
||||
struct range_trans *rt, *lrt = NULL;
|
||||
|
||||
for (i = 0; i < SYM_NUM; i++) {
|
||||
cond_resched();
|
||||
@@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p)
|
||||
}
|
||||
kfree(lra);
|
||||
|
||||
for (rt = p->range_tr; rt; rt = rt->next) {
|
||||
cond_resched();
|
||||
if (lrt) {
|
||||
ebitmap_destroy(&lrt->target_range.level[0].cat);
|
||||
ebitmap_destroy(&lrt->target_range.level[1].cat);
|
||||
kfree(lrt);
|
||||
}
|
||||
lrt = rt;
|
||||
}
|
||||
if (lrt) {
|
||||
ebitmap_destroy(&lrt->target_range.level[0].cat);
|
||||
ebitmap_destroy(&lrt->target_range.level[1].cat);
|
||||
kfree(lrt);
|
||||
}
|
||||
hashtab_map(p->range_tr, range_tr_destroy, NULL);
|
||||
hashtab_destroy(p->range_tr);
|
||||
|
||||
if (p->type_attr_map) {
|
||||
for (i = 0; i < p->p_types.nprim; i++)
|
||||
@@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp)
|
||||
int i, j, rc;
|
||||
__le32 buf[4];
|
||||
u32 nodebuf[8];
|
||||
u32 len, len2, config, nprim, nel, nel2;
|
||||
u32 len, len2, nprim, nel, nel2;
|
||||
char *policydb_str;
|
||||
struct policydb_compat_info *info;
|
||||
struct range_trans *rt, *lrt;
|
||||
|
||||
config = 0;
|
||||
struct range_trans *rt;
|
||||
struct mls_range *r;
|
||||
|
||||
rc = policydb_init(p);
|
||||
if (rc)
|
||||
@@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp)
|
||||
kfree(policydb_str);
|
||||
policydb_str = NULL;
|
||||
|
||||
/* Read the version, config, and table sizes. */
|
||||
/* Read the version and table sizes. */
|
||||
rc = next_entry(buf, fp, sizeof(u32)*4);
|
||||
if (rc < 0)
|
||||
goto bad;
|
||||
@@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp)
|
||||
}
|
||||
|
||||
if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
|
||||
if (ss_initialized && !selinux_mls_enabled) {
|
||||
printk(KERN_ERR "SELinux: Cannot switch between non-MLS"
|
||||
" and MLS policies\n");
|
||||
goto bad;
|
||||
}
|
||||
selinux_mls_enabled = 1;
|
||||
config |= POLICYDB_CONFIG_MLS;
|
||||
p->mls_enabled = 1;
|
||||
|
||||
if (p->policyvers < POLICYDB_VERSION_MLS) {
|
||||
printk(KERN_ERR "SELinux: security policydb version %d "
|
||||
@@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp)
|
||||
p->policyvers);
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
if (ss_initialized && selinux_mls_enabled) {
|
||||
printk(KERN_ERR "SELinux: Cannot switch between MLS and"
|
||||
" non-MLS policies\n");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
|
||||
p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
|
||||
@@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp)
|
||||
if (rc < 0)
|
||||
goto bad;
|
||||
nel = le32_to_cpu(buf[0]);
|
||||
lrt = NULL;
|
||||
for (i = 0; i < nel; i++) {
|
||||
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
|
||||
if (!rt) {
|
||||
rc = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
if (lrt)
|
||||
lrt->next = rt;
|
||||
else
|
||||
p->range_tr = rt;
|
||||
rc = next_entry(buf, fp, (sizeof(u32) * 2));
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
kfree(rt);
|
||||
goto bad;
|
||||
}
|
||||
rt->source_type = le32_to_cpu(buf[0]);
|
||||
rt->target_type = le32_to_cpu(buf[1]);
|
||||
if (new_rangetr) {
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
kfree(rt);
|
||||
goto bad;
|
||||
}
|
||||
rt->target_class = le32_to_cpu(buf[0]);
|
||||
} else
|
||||
rt->target_class = p->process_class;
|
||||
if (!policydb_type_isvalid(p, rt->source_type) ||
|
||||
!policydb_type_isvalid(p, rt->target_type) ||
|
||||
!policydb_class_isvalid(p, rt->target_class)) {
|
||||
kfree(rt);
|
||||
rc = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
rc = mls_read_range_helper(&rt->target_range, fp);
|
||||
if (rc)
|
||||
goto bad;
|
||||
if (!mls_range_isvalid(p, &rt->target_range)) {
|
||||
printk(KERN_WARNING "SELinux: rangetrans: invalid range\n");
|
||||
r = kzalloc(sizeof(*r), GFP_KERNEL);
|
||||
if (!r) {
|
||||
kfree(rt);
|
||||
rc = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
rc = mls_read_range_helper(r, fp);
|
||||
if (rc) {
|
||||
kfree(rt);
|
||||
kfree(r);
|
||||
goto bad;
|
||||
}
|
||||
if (!mls_range_isvalid(p, r)) {
|
||||
printk(KERN_WARNING "SELinux: rangetrans: invalid range\n");
|
||||
kfree(rt);
|
||||
kfree(r);
|
||||
goto bad;
|
||||
}
|
||||
rc = hashtab_insert(p->range_tr, rt, r);
|
||||
if (rc) {
|
||||
kfree(rt);
|
||||
kfree(r);
|
||||
goto bad;
|
||||
}
|
||||
lrt = rt;
|
||||
}
|
||||
rangetr_hash_eval(p->range_tr);
|
||||
}
|
||||
|
||||
p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL);
|
||||
|
@@ -27,6 +27,8 @@
|
||||
#include "symtab.h"
|
||||
#include "avtab.h"
|
||||
#include "sidtab.h"
|
||||
#include "ebitmap.h"
|
||||
#include "mls_types.h"
|
||||
#include "context.h"
|
||||
#include "constraint.h"
|
||||
|
||||
@@ -113,8 +115,6 @@ struct range_trans {
|
||||
u32 source_type;
|
||||
u32 target_type;
|
||||
u32 target_class;
|
||||
struct mls_range target_range;
|
||||
struct range_trans *next;
|
||||
};
|
||||
|
||||
/* Boolean data type */
|
||||
@@ -187,6 +187,8 @@ struct genfs {
|
||||
|
||||
/* The policy database */
|
||||
struct policydb {
|
||||
int mls_enabled;
|
||||
|
||||
/* symbol tables */
|
||||
struct symtab symtab[SYM_NUM];
|
||||
#define p_commons symtab[SYM_COMMONS]
|
||||
@@ -240,8 +242,8 @@ struct policydb {
|
||||
fixed labeling behavior. */
|
||||
struct genfs *genfs;
|
||||
|
||||
/* range transitions */
|
||||
struct range_trans *range_tr;
|
||||
/* range transitions table (range_trans_key -> mls_range) */
|
||||
struct hashtab *range_tr;
|
||||
|
||||
/* type -> attribute reverse mapping */
|
||||
struct ebitmap *type_attr_map;
|
||||
|
@@ -26,6 +26,10 @@
|
||||
*
|
||||
* Added support for bounds domain and audit messaged on masked permissions
|
||||
*
|
||||
* Updated: Guido Trentalancia <guido@trentalancia.com>
|
||||
*
|
||||
* Added support for runtime switching of the policy type
|
||||
*
|
||||
* Copyright (C) 2008, 2009 NEC Corporation
|
||||
* Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
|
||||
@@ -87,11 +91,10 @@ static u32 latest_granting;
|
||||
static int context_struct_to_string(struct context *context, char **scontext,
|
||||
u32 *scontext_len);
|
||||
|
||||
static int context_struct_compute_av(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
u32 requested,
|
||||
struct av_decision *avd);
|
||||
static void context_struct_compute_av(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
struct av_decision *avd);
|
||||
|
||||
struct selinux_mapping {
|
||||
u16 value; /* policy value */
|
||||
@@ -196,23 +199,6 @@ static u16 unmap_class(u16 tclass)
|
||||
return tclass;
|
||||
}
|
||||
|
||||
static u32 unmap_perm(u16 tclass, u32 tperm)
|
||||
{
|
||||
if (tclass < current_mapping_size) {
|
||||
unsigned i;
|
||||
u32 kperm = 0;
|
||||
|
||||
for (i = 0; i < current_mapping[tclass].num_perms; i++)
|
||||
if (tperm & (1<<i)) {
|
||||
kperm |= current_mapping[tclass].perms[i];
|
||||
tperm &= ~(1<<i);
|
||||
}
|
||||
return kperm;
|
||||
}
|
||||
|
||||
return tperm;
|
||||
}
|
||||
|
||||
static void map_decision(u16 tclass, struct av_decision *avd,
|
||||
int allow_unknown)
|
||||
{
|
||||
@@ -250,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd,
|
||||
}
|
||||
}
|
||||
|
||||
int security_mls_enabled(void)
|
||||
{
|
||||
return policydb.mls_enabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the boolean value of a constraint expression
|
||||
@@ -465,7 +455,8 @@ static void security_dump_masked_av(struct context *scontext,
|
||||
char *scontext_name = NULL;
|
||||
char *tcontext_name = NULL;
|
||||
char *permission_names[32];
|
||||
int index, length;
|
||||
int index;
|
||||
u32 length;
|
||||
bool need_comma = false;
|
||||
|
||||
if (!permissions)
|
||||
@@ -532,7 +523,6 @@ out:
|
||||
static void type_attribute_bounds_av(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
u32 requested,
|
||||
struct av_decision *avd)
|
||||
{
|
||||
struct context lo_scontext;
|
||||
@@ -553,7 +543,6 @@ static void type_attribute_bounds_av(struct context *scontext,
|
||||
context_struct_compute_av(&lo_scontext,
|
||||
tcontext,
|
||||
tclass,
|
||||
requested,
|
||||
&lo_avd);
|
||||
if ((lo_avd.allowed & avd->allowed) == avd->allowed)
|
||||
return; /* no masked permission */
|
||||
@@ -569,7 +558,6 @@ static void type_attribute_bounds_av(struct context *scontext,
|
||||
context_struct_compute_av(scontext,
|
||||
&lo_tcontext,
|
||||
tclass,
|
||||
requested,
|
||||
&lo_avd);
|
||||
if ((lo_avd.allowed & avd->allowed) == avd->allowed)
|
||||
return; /* no masked permission */
|
||||
@@ -586,7 +574,6 @@ static void type_attribute_bounds_av(struct context *scontext,
|
||||
context_struct_compute_av(&lo_scontext,
|
||||
&lo_tcontext,
|
||||
tclass,
|
||||
requested,
|
||||
&lo_avd);
|
||||
if ((lo_avd.allowed & avd->allowed) == avd->allowed)
|
||||
return; /* no masked permission */
|
||||
@@ -607,11 +594,10 @@ static void type_attribute_bounds_av(struct context *scontext,
|
||||
* Compute access vectors based on a context structure pair for
|
||||
* the permissions in a particular class.
|
||||
*/
|
||||
static int context_struct_compute_av(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
u32 requested,
|
||||
struct av_decision *avd)
|
||||
static void context_struct_compute_av(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
struct av_decision *avd)
|
||||
{
|
||||
struct constraint_node *constraint;
|
||||
struct role_allow *ra;
|
||||
@@ -622,19 +608,14 @@ static int context_struct_compute_av(struct context *scontext,
|
||||
struct ebitmap_node *snode, *tnode;
|
||||
unsigned int i, j;
|
||||
|
||||
/*
|
||||
* Initialize the access vectors to the default values.
|
||||
*/
|
||||
avd->allowed = 0;
|
||||
avd->auditallow = 0;
|
||||
avd->auditdeny = 0xffffffff;
|
||||
avd->seqno = latest_granting;
|
||||
avd->flags = 0;
|
||||
|
||||
if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass);
|
||||
return -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
tclass_datum = policydb.class_val_to_struct[tclass - 1];
|
||||
@@ -705,9 +686,7 @@ static int context_struct_compute_av(struct context *scontext,
|
||||
* permission and notice it to userspace via audit.
|
||||
*/
|
||||
type_attribute_bounds_av(scontext, tcontext,
|
||||
tclass, requested, avd);
|
||||
|
||||
return 0;
|
||||
tclass, avd);
|
||||
}
|
||||
|
||||
static int security_validtrans_handle_fail(struct context *ocontext,
|
||||
@@ -864,7 +843,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
|
||||
if (rc) {
|
||||
char *old_name = NULL;
|
||||
char *new_name = NULL;
|
||||
int length;
|
||||
u32 length;
|
||||
|
||||
if (!context_struct_to_string(old_context,
|
||||
&old_name, &length) &&
|
||||
@@ -886,110 +865,116 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int security_compute_av_core(u32 ssid,
|
||||
u32 tsid,
|
||||
u16 tclass,
|
||||
u32 requested,
|
||||
struct av_decision *avd)
|
||||
static void avd_init(struct av_decision *avd)
|
||||
{
|
||||
struct context *scontext = NULL, *tcontext = NULL;
|
||||
int rc = 0;
|
||||
|
||||
scontext = sidtab_search(&sidtab, ssid);
|
||||
if (!scontext) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, ssid);
|
||||
return -EINVAL;
|
||||
}
|
||||
tcontext = sidtab_search(&sidtab, tsid);
|
||||
if (!tcontext) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, tsid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = context_struct_compute_av(scontext, tcontext, tclass,
|
||||
requested, avd);
|
||||
|
||||
/* permissive domain? */
|
||||
if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
||||
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
||||
|
||||
return rc;
|
||||
avd->allowed = 0;
|
||||
avd->auditallow = 0;
|
||||
avd->auditdeny = 0xffffffff;
|
||||
avd->seqno = latest_granting;
|
||||
avd->flags = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* security_compute_av - Compute access vector decisions.
|
||||
* @ssid: source security identifier
|
||||
* @tsid: target security identifier
|
||||
* @tclass: target security class
|
||||
* @requested: requested permissions
|
||||
* @avd: access vector decisions
|
||||
*
|
||||
* Compute a set of access vector decisions based on the
|
||||
* SID pair (@ssid, @tsid) for the permissions in @tclass.
|
||||
* Return -%EINVAL if any of the parameters are invalid or %0
|
||||
* if the access vector decisions were computed successfully.
|
||||
*/
|
||||
int security_compute_av(u32 ssid,
|
||||
u32 tsid,
|
||||
u16 orig_tclass,
|
||||
u32 orig_requested,
|
||||
struct av_decision *avd)
|
||||
void security_compute_av(u32 ssid,
|
||||
u32 tsid,
|
||||
u16 orig_tclass,
|
||||
struct av_decision *avd)
|
||||
{
|
||||
u16 tclass;
|
||||
u32 requested;
|
||||
int rc;
|
||||
struct context *scontext = NULL, *tcontext = NULL;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
avd_init(avd);
|
||||
if (!ss_initialized)
|
||||
goto allow;
|
||||
|
||||
requested = unmap_perm(orig_tclass, orig_requested);
|
||||
scontext = sidtab_search(&sidtab, ssid);
|
||||
if (!scontext) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, ssid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* permissive domain? */
|
||||
if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
||||
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
||||
|
||||
tcontext = sidtab_search(&sidtab, tsid);
|
||||
if (!tcontext) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, tsid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tclass = unmap_class(orig_tclass);
|
||||
if (unlikely(orig_tclass && !tclass)) {
|
||||
if (policydb.allow_unknown)
|
||||
goto allow;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
rc = security_compute_av_core(ssid, tsid, tclass, requested, avd);
|
||||
context_struct_compute_av(scontext, tcontext, tclass, avd);
|
||||
map_decision(orig_tclass, avd, policydb.allow_unknown);
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
return rc;
|
||||
return;
|
||||
allow:
|
||||
avd->allowed = 0xffffffff;
|
||||
avd->auditallow = 0;
|
||||
avd->auditdeny = 0xffffffff;
|
||||
avd->seqno = latest_granting;
|
||||
avd->flags = 0;
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int security_compute_av_user(u32 ssid,
|
||||
u32 tsid,
|
||||
u16 tclass,
|
||||
u32 requested,
|
||||
struct av_decision *avd)
|
||||
void security_compute_av_user(u32 ssid,
|
||||
u32 tsid,
|
||||
u16 tclass,
|
||||
struct av_decision *avd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!ss_initialized) {
|
||||
avd->allowed = 0xffffffff;
|
||||
avd->auditallow = 0;
|
||||
avd->auditdeny = 0xffffffff;
|
||||
avd->seqno = latest_granting;
|
||||
return 0;
|
||||
}
|
||||
struct context *scontext = NULL, *tcontext = NULL;
|
||||
|
||||
read_lock(&policy_rwlock);
|
||||
rc = security_compute_av_core(ssid, tsid, tclass, requested, avd);
|
||||
avd_init(avd);
|
||||
if (!ss_initialized)
|
||||
goto allow;
|
||||
|
||||
scontext = sidtab_search(&sidtab, ssid);
|
||||
if (!scontext) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, ssid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* permissive domain? */
|
||||
if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
|
||||
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
||||
|
||||
tcontext = sidtab_search(&sidtab, tsid);
|
||||
if (!tcontext) {
|
||||
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
|
||||
__func__, tsid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(!tclass)) {
|
||||
if (policydb.allow_unknown)
|
||||
goto allow;
|
||||
goto out;
|
||||
}
|
||||
|
||||
context_struct_compute_av(scontext, tcontext, tclass, avd);
|
||||
out:
|
||||
read_unlock(&policy_rwlock);
|
||||
return rc;
|
||||
return;
|
||||
allow:
|
||||
avd->allowed = 0xffffffff;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1565,7 +1550,10 @@ static int clone_sid(u32 sid,
|
||||
{
|
||||
struct sidtab *s = arg;
|
||||
|
||||
return sidtab_insert(s, sid, context);
|
||||
if (sid > SECINITSID_NUM)
|
||||
return sidtab_insert(s, sid, context);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int convert_context_handle_invalid_context(struct context *context)
|
||||
@@ -1606,12 +1594,17 @@ static int convert_context(u32 key,
|
||||
{
|
||||
struct convert_context_args *args;
|
||||
struct context oldc;
|
||||
struct ocontext *oc;
|
||||
struct mls_range *range;
|
||||
struct role_datum *role;
|
||||
struct type_datum *typdatum;
|
||||
struct user_datum *usrdatum;
|
||||
char *s;
|
||||
u32 len;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
if (key <= SECINITSID_NUM)
|
||||
goto out;
|
||||
|
||||
args = p;
|
||||
|
||||
@@ -1673,9 +1666,39 @@ static int convert_context(u32 key,
|
||||
goto bad;
|
||||
c->type = typdatum->value;
|
||||
|
||||
rc = mls_convert_context(args->oldp, args->newp, c);
|
||||
if (rc)
|
||||
goto bad;
|
||||
/* Convert the MLS fields if dealing with MLS policies */
|
||||
if (args->oldp->mls_enabled && args->newp->mls_enabled) {
|
||||
rc = mls_convert_context(args->oldp, args->newp, c);
|
||||
if (rc)
|
||||
goto bad;
|
||||
} else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
|
||||
/*
|
||||
* Switching between MLS and non-MLS policy:
|
||||
* free any storage used by the MLS fields in the
|
||||
* context for all existing entries in the sidtab.
|
||||
*/
|
||||
mls_context_destroy(c);
|
||||
} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
|
||||
/*
|
||||
* Switching between non-MLS and MLS policy:
|
||||
* ensure that the MLS fields of the context for all
|
||||
* existing entries in the sidtab are filled in with a
|
||||
* suitable default value, likely taken from one of the
|
||||
* initial SIDs.
|
||||
*/
|
||||
oc = args->newp->ocontexts[OCON_ISID];
|
||||
while (oc && oc->sid[0] != SECINITSID_UNLABELED)
|
||||
oc = oc->next;
|
||||
if (!oc) {
|
||||
printk(KERN_ERR "SELinux: unable to look up"
|
||||
" the initial SIDs list\n");
|
||||
goto bad;
|
||||
}
|
||||
range = &oc->context[0].range;
|
||||
rc = mls_range_set(c, range);
|
||||
if (rc)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Check the validity of the new context. */
|
||||
if (!policydb_context_isvalid(args->newp, c)) {
|
||||
@@ -1771,9 +1794,17 @@ int security_load_policy(void *data, size_t len)
|
||||
if (policydb_read(&newpolicydb, fp))
|
||||
return -EINVAL;
|
||||
|
||||
if (sidtab_init(&newsidtab)) {
|
||||
/* If switching between different policy types, log MLS status */
|
||||
if (policydb.mls_enabled && !newpolicydb.mls_enabled)
|
||||
printk(KERN_INFO "SELinux: Disabling MLS support...\n");
|
||||
else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
|
||||
printk(KERN_INFO "SELinux: Enabling MLS support...\n");
|
||||
|
||||
rc = policydb_load_isids(&newpolicydb, &newsidtab);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "SELinux: unable to load the initial SIDs\n");
|
||||
policydb_destroy(&newpolicydb);
|
||||
return -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (selinux_set_mapping(&newpolicydb, secclass_map,
|
||||
@@ -1800,8 +1831,12 @@ int security_load_policy(void *data, size_t len)
|
||||
args.oldp = &policydb;
|
||||
args.newp = &newpolicydb;
|
||||
rc = sidtab_map(&newsidtab, convert_context, &args);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
printk(KERN_ERR "SELinux: unable to convert the internal"
|
||||
" representation of contexts in the new SID"
|
||||
" table\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Save the old policydb and SID table to free later. */
|
||||
memcpy(&oldpolicydb, &policydb, sizeof policydb);
|
||||
@@ -2397,7 +2432,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
|
||||
u32 len;
|
||||
int rc = 0;
|
||||
|
||||
if (!ss_initialized || !selinux_mls_enabled) {
|
||||
if (!ss_initialized || !policydb.mls_enabled) {
|
||||
*new_sid = sid;
|
||||
goto out;
|
||||
}
|
||||
@@ -2498,7 +2533,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
|
||||
/* we don't need to check ss_initialized here since the only way both
|
||||
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
|
||||
* security server was initialized and ss_initialized was true */
|
||||
if (!selinux_mls_enabled) {
|
||||
if (!policydb.mls_enabled) {
|
||||
*peer_sid = SECSID_NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -2555,7 +2590,7 @@ int security_get_classes(char ***classes, int *nclasses)
|
||||
read_lock(&policy_rwlock);
|
||||
|
||||
*nclasses = policydb.p_classes.nprim;
|
||||
*classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC);
|
||||
*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
|
||||
if (!*classes)
|
||||
goto out;
|
||||
|
||||
@@ -2602,7 +2637,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
|
||||
}
|
||||
|
||||
*nperms = match->permissions.nprim;
|
||||
*perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC);
|
||||
*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
|
||||
if (!*perms)
|
||||
goto out;
|
||||
|
||||
|
Reference in New Issue
Block a user