* Updated: Hewlett-Packard <paul.moore@hp.com>
*
* Added support for NetLabel
+ * Added support for the policy capability bitmap
*
* Updated: Chad Sellers <csellers@tresys.com>
*
* Added validation of kernel classes and permissions
*
- * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
extern void selnl_notify_policyload(u32 seqno);
unsigned int policydb_loaded_version;
+int selinux_policycap_netpeer;
+
/*
* This is declared in avc.c
*/
struct class_datum *tclass_datum;
struct ebitmap *sattr, *tattr;
struct ebitmap_node *snode, *tnode;
+ const struct selinux_class_perm *kdefs = &selinux_class_perm;
unsigned int i, j;
/*
tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
tclass = SECCLASS_NETLINK_SOCKET;
- if (!tclass || tclass > policydb.p_classes.nprim) {
- printk(KERN_ERR "security_compute_av: unrecognized class %d\n",
- tclass);
- return -EINVAL;
- }
- tclass_datum = policydb.class_val_to_struct[tclass - 1];
-
/*
* Initialize the access vectors to the default values.
*/
avd->auditdeny = 0xffffffff;
avd->seqno = latest_granting;
+ /*
+ * Check for all the invalid cases.
+ * - tclass 0
+ * - tclass > policy and > kernel
+ * - tclass > policy but is a userspace class
+ * - tclass > policy but we do not allow unknowns
+ */
+ if (unlikely(!tclass))
+ goto inval_class;
+ if (unlikely(tclass > policydb.p_classes.nprim))
+ if (tclass > kdefs->cts_len ||
+ !kdefs->class_to_string[tclass - 1] ||
+ !policydb.allow_unknown)
+ goto inval_class;
+
+ /*
+ * Kernel class and we allow unknown so pad the allow decision
+ * the pad will be all 1 for unknown classes.
+ */
+ if (tclass <= kdefs->cts_len && policydb.allow_unknown)
+ avd->allowed = policydb.undefined_perms[tclass - 1];
+
+ /*
+ * Not in policy. Since decision is completed (all 1 or all 0) return.
+ */
+ if (unlikely(tclass > policydb.p_classes.nprim))
+ return 0;
+
+ tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
/*
* If a specific type enforcement rule was defined for
* this permission check, then use it.
avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1];
- ebitmap_for_each_bit(sattr, snode, i) {
- if (!ebitmap_node_get_bit(snode, i))
- continue;
- ebitmap_for_each_bit(tattr, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(sattr, snode, i) {
+ ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey);
}
return 0;
+
+inval_class:
+ printk(KERN_ERR "%s: unrecognized class %d\n", __FUNCTION__, tclass);
+ return -EINVAL;
}
static int security_validtrans_handle_fail(struct context *ocontext,
* @scontext: security context
* @scontext_len: length in bytes
* @sid: security identifier, SID
- * @def_sid: default SID to assign on errror
+ * @def_sid: default SID to assign on error
*
* Obtains a SID associated with the security context that
* has the string representation specified by @scontext.
const char *def_class, *def_perm, *pol_class;
struct symtab *perms;
+ if (p->allow_unknown) {
+ u32 num_classes = kdefs->cts_len;
+ p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL);
+ if (!p->undefined_perms)
+ return -ENOMEM;
+ }
+
for (i = 1; i < kdefs->cts_len; i++) {
def_class = kdefs->class_to_string[i];
if (!def_class)
printk(KERN_INFO
"security: class %s not defined in policy\n",
def_class);
+ if (p->reject_unknown)
+ return -EINVAL;
+ if (p->allow_unknown)
+ p->undefined_perms[i-1] = ~0U;
continue;
}
pol_class = p->p_class_val_to_name[i-1];
printk(KERN_INFO
"security: permission %s in class %s not defined in policy\n",
def_perm, pol_class);
+ if (p->reject_unknown)
+ return -EINVAL;
+ if (p->allow_unknown)
+ p->undefined_perms[class_val-1] |= perm_val;
continue;
}
perdatum = hashtab_search(perms->table, def_perm);
if (perdatum == NULL) {
printk(KERN_ERR
- "security: permission %s in class %s not found in policy\n",
+ "security: permission %s in class %s not found in policy, bad policy\n",
def_perm, pol_class);
return -EINVAL;
}
printk(KERN_INFO
"security: permission %s in class %s not defined in policy\n",
def_perm, pol_class);
+ if (p->reject_unknown)
+ return -EINVAL;
+ if (p->allow_unknown)
+ p->undefined_perms[class_val-1] |= (1 << j);
continue;
}
perdatum = hashtab_search(perms->table, def_perm);
if (perdatum == NULL) {
printk(KERN_ERR
- "security: permission %s in class %s not found in policy\n",
+ "security: permission %s in class %s not found in policy, bad policy\n",
def_perm, pol_class);
return -EINVAL;
}
goto out;
}
+static void security_load_policycaps(void)
+{
+ selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
+ POLICYDB_CAPABILITY_NETPEER);
+}
+
extern void selinux_complete_init(void);
static int security_preserve_bools(struct policydb *p);
avtab_cache_destroy();
return -EINVAL;
}
+ security_load_policycaps();
policydb_loaded_version = policydb.policyvers;
ss_initialized = 1;
seqno = ++latest_granting;
POLICY_WRLOCK;
memcpy(&policydb, &newpolicydb, sizeof policydb);
sidtab_set(&sidtab, &newsidtab);
+ security_load_policycaps();
seqno = ++latest_granting;
policydb_loaded_version = policydb.policyvers;
POLICY_WRUNLOCK;
* security_netif_sid - Obtain the SID for a network interface.
* @name: interface name
* @if_sid: interface SID
- * @msg_sid: default SID for received packets
*/
-int security_netif_sid(char *name,
- u32 *if_sid,
- u32 *msg_sid)
+int security_netif_sid(char *name, u32 *if_sid)
{
int rc = 0;
struct ocontext *c;
goto out;
}
*if_sid = c->sid[0];
- *msg_sid = c->sid[1];
- } else {
+ } else
*if_sid = SECINITSID_NETIF;
- *msg_sid = SECINITSID_NETMSG;
- }
out:
POLICY_RDUNLOCK;
goto out_unlock;
}
- ebitmap_for_each_bit(&user->roles, rnode, i) {
- if (!ebitmap_node_get_bit(rnode, i))
- continue;
+ ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i];
usercon.role = i+1;
- ebitmap_for_each_bit(&role->types, tnode, j) {
- if (!ebitmap_node_get_bit(tnode, j))
- continue;
+ ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon))
struct ocontext *c;
int rc = 0, cmp = 0;
+ while (path[0] == '/' && path[1] == '/')
+ path++;
+
POLICY_RDLOCK;
for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
return rc;
}
+int security_get_reject_unknown(void)
+{
+ return policydb.reject_unknown;
+}
+
+int security_get_allow_unknown(void)
+{
+ return policydb.allow_unknown;
+}
+
+/**
+ * security_get_policycaps - Query the loaded policy for its capabilities
+ * @len: the number of capability bits
+ * @values: the capability bit array
+ *
+ * Description:
+ * Get an array of the policy capabilities in @values where each entry in
+ * @values is either true (1) or false (0) depending the policy's support of
+ * that feature. The policy capabilities are defined by the
+ * POLICYDB_CAPABILITY_* enums. The size of the array is stored in @len and it
+ * is up to the caller to free the array in @values. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int security_get_policycaps(int *len, int **values)
+{
+ int rc = -ENOMEM;
+ unsigned int iter;
+
+ POLICY_RDLOCK;
+
+ *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
+ if (*values == NULL)
+ goto out;
+ for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
+ (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
+ *len = POLICYDB_CAPABILITY_MAX;
+
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
+/**
+ * security_policycap_supported - Check for a specific policy capability
+ * @req_cap: capability
+ *
+ * Description:
+ * This function queries the currently loaded policy to see if it supports the
+ * capability specified by @req_cap. Returns true (1) if the capability is
+ * supported, false (0) if it isn't supported.
+ *
+ */
+int security_policycap_supported(unsigned int req_cap)
+{
+ int rc;
+
+ POLICY_RDLOCK;
+ rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
+ POLICY_RDUNLOCK;
+
+ return rc;
+}
+
struct selinux_audit_rule {
u32 au_seqno;
struct context au_ctxt;
*rule = NULL;
if (!ss_initialized)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
switch (field) {
case AUDIT_SUBJ_USER:
cache->type = NETLBL_CACHE_T_MLS;
if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
- &ctx->range.level[0].cat) != 0)
+ &ctx->range.level[0].cat) != 0) {
+ kfree(cache);
return;
+ }
cache->data.mls_label.level[1].cat.highbit =
cache->data.mls_label.level[0].cat.highbit;
cache->data.mls_label.level[1].cat.node =
default:
goto netlbl_secattr_to_sid_return;
}
+ } else if (secattr->flags & NETLBL_SECATTR_SECID) {
+ *sid = secattr->attr.secid;
+ rc = 0;
} else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
ctx = sidtab_search(&sidtab, base_sid);
if (ctx == NULL)
mls_import_netlbl_lvl(&ctx_new, secattr);
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
- secattr->mls_cat) != 0)
+ secattr->attr.mls.cat) != 0)
goto netlbl_secattr_to_sid_return;
ctx_new.range.level[1].cat.highbit =
ctx_new.range.level[0].cat.highbit;
int rc = -ENOENT;
struct context *ctx;
- netlbl_secattr_init(secattr);
-
if (!ss_initialized)
return 0;