Merge branch 'next' into for-linus

This commit is contained in:
James Morris
2010-03-01 09:36:31 +11:00
30 changed files with 2037 additions and 1715 deletions

View File

@@ -489,17 +489,14 @@ void avc_audit(u32 ssid, u32 tsid,
struct common_audit_data stack_data;
u32 denied, audited;
denied = requested & ~avd->allowed;
if (denied) {
audited = denied;
if (!(audited & avd->auditdeny))
return;
} else if (result) {
if (denied)
audited = denied & avd->auditdeny;
else if (result)
audited = denied = requested;
} else {
audited = requested;
if (!(audited & avd->auditallow))
return;
}
else
audited = requested & avd->auditallow;
if (!audited)
return;
if (!a) {
a = &stack_data;
memset(a, 0, sizeof(*a));
@@ -746,9 +743,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
else
avd = &avd_entry;
rc = security_compute_av(ssid, tsid, tclass, requested, avd);
if (rc)
goto out;
security_compute_av(ssid, tsid, tclass, avd);
rcu_read_lock();
node = avc_insert(ssid, tsid, tclass, avd);
} else {
@@ -770,7 +765,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
}
rcu_read_unlock();
out:
return rc;
}

View File

@@ -76,6 +76,7 @@
#include <linux/selinux.h>
#include <linux/mutex.h>
#include <linux/posix-timers.h>
#include <linux/syslog.h>
#include "avc.h"
#include "objsec.h"
@@ -125,13 +126,6 @@ __setup("selinux=", selinux_enabled_setup);
int selinux_enabled = 1;
#endif
/*
* Minimal support for a secondary security module,
* just to allow the use of the capability module.
*/
static struct security_operations *secondary_ops;
/* Lists of inode and superblock security structures initialized
before the policy was loaded. */
static LIST_HEAD(superblock_security_head);
@@ -2049,29 +2043,30 @@ static int selinux_quota_on(struct dentry *dentry)
return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
}
static int selinux_syslog(int type)
static int selinux_syslog(int type, bool from_file)
{
int rc;
rc = cap_syslog(type);
rc = cap_syslog(type, from_file);
if (rc)
return rc;
switch (type) {
case 3: /* Read last kernel messages */
case 10: /* Return size of the log buffer */
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
rc = task_has_system(current, SYSTEM__SYSLOG_READ);
break;
case 6: /* Disable logging to console */
case 7: /* Enable logging to console */
case 8: /* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
break;
case 0: /* Close log */
case 1: /* Open log */
case 2: /* Read from log */
case 4: /* Read/clear last kernel messages */
case 5: /* Clear ring buffer */
case SYSLOG_ACTION_CLOSE: /* Close log */
case SYSLOG_ACTION_OPEN: /* Open log */
case SYSLOG_ACTION_READ: /* Read from log */
case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
default:
rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
break;
@@ -3334,7 +3329,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
if (ret == 0)
tsec->create_sid = isec->sid;
return 0;
return ret;
}
static int selinux_kernel_module_request(char *kmod_name)
@@ -5672,9 +5667,6 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL);
avc_init();
secondary_ops = security_ops;
if (!secondary_ops)
panic("SELinux: No initial security operations\n");
if (register_security(&selinux_ops))
panic("SELinux: Unable to register with kernel.\n");
@@ -5835,8 +5827,7 @@ int selinux_disable(void)
selinux_disabled = 1;
selinux_enabled = 0;
/* Reset security_ops to the secondary module, dummy or capability. */
security_ops = secondary_ops;
reset_security_ops();
/* Try to destroy the avc node cache */
avc_disable();

View File

@@ -57,7 +57,6 @@
struct netlbl_lsm_secattr;
extern int selinux_enabled;
extern int selinux_mls_enabled;
/* Policy capabilities */
enum {
@@ -80,6 +79,8 @@ extern int selinux_policycap_openperm;
/* limitation of boundary depth */
#define POLICYDB_BOUNDS_MAXDEPTH 4
int security_mls_enabled(void);
int security_load_policy(void *data, size_t len);
int security_policycap_supported(unsigned int req_cap);
@@ -96,13 +97,11 @@ struct av_decision {
/* definitions of av_decision.flags */
#define AVD_FLAGS_PERMISSIVE 0x0001
int security_compute_av(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd);
void security_compute_av(u32 ssid, u32 tsid,
u16 tclass, struct av_decision *avd);
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 security_transition_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);

View File

@@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
security_mls_enabled());
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@@ -494,7 +495,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
char *scon, *tcon;
u32 ssid, tsid;
u16 tclass;
u32 req;
struct av_decision avd;
ssize_t length;
@@ -512,7 +512,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
goto out;
length = -EINVAL;
if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
@@ -522,9 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (length < 0)
goto out2;
length = security_compute_av_user(ssid, tsid, tclass, req, &avd);
if (length < 0)
goto out2;
security_compute_av_user(ssid, tsid, tclass, &avd);
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u %x",
@@ -979,6 +977,8 @@ static int sel_make_bools(void)
u32 sid;
/* remove any existing files */
for (i = 0; i < bool_num; i++)
kfree(bool_pending_names[i]);
kfree(bool_pending_names);
kfree(bool_pending_values);
bool_pending_names = NULL;

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;