* Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
* James Morris <jmorris@redhat.com>
*
- * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
+ * Support for enhanced MLS infrastructure.
*
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* 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
* the Free Software Foundation, version 2.
#define LOAD_LOCK down(&load_sem)
#define LOAD_UNLOCK up(&load_sem)
-struct sidtab sidtab;
+static struct sidtab sidtab;
struct policydb policydb;
int ss_initialized = 0;
*/
static u32 latest_granting = 0;
+/* Forward declaration. */
+static int context_struct_to_string(struct context *context, char **scontext,
+ u32 *scontext_len);
+
/*
* Return the boolean value of a constraint expression
* when it is applied to the specified source and target
* security contexts.
+ *
+ * xcontext is a special beast... It is used by the validatetrans rules
+ * only. For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the context
+ * of the process performing the transition. All other callers of
+ * constraint_expr_eval should pass in NULL for xcontext.
*/
static int constraint_expr_eval(struct context *scontext,
struct context *tcontext,
+ struct context *xcontext,
struct constraint_expr *cexpr)
{
u32 val1, val2;
struct context *c;
struct role_datum *r1, *r2;
+ struct mls_level *l1, *l2;
struct constraint_expr *e;
int s[CEXPR_MAXDEPTH];
int sp = -1;
break;
}
break;
+ case CEXPR_L1L2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[0]);
+ goto mls_ops;
+ case CEXPR_L1H2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_H1L2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[0]);
+ goto mls_ops;
+ case CEXPR_H1H2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_L1H1:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(scontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_L2H2:
+ l1 = &(tcontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+mls_ops:
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_NEQ:
+ s[++sp] = !mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_DOM:
+ s[++sp] = mls_level_dom(l1, l2);
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = mls_level_dom(l2, l1);
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = mls_level_incomp(l2, l1);
+ continue;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
default:
BUG();
return 0;
c = scontext;
if (e->attr & CEXPR_TARGET)
c = tcontext;
+ else if (e->attr & CEXPR_XTARGET) {
+ c = xcontext;
+ if (!c) {
+ BUG();
+ return 0;
+ }
+ }
if (e->attr & CEXPR_USER)
val1 = c->user;
else if (e->attr & CEXPR_ROLE)
cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
/*
- * Remove any permissions prohibited by the MLS policy.
- */
- mls_compute_av(scontext, tcontext, tclass_datum, &avd->allowed);
-
- /*
- * Remove any permissions prohibited by a constraint.
+ * Remove any permissions prohibited by a constraint (this includes
+ * the MLS policy).
*/
constraint = tclass_datum->constraints;
while (constraint) {
if ((constraint->permissions & (avd->allowed)) &&
- !constraint_expr_eval(scontext, tcontext,
+ !constraint_expr_eval(scontext, tcontext, NULL,
constraint->expr)) {
avd->allowed = (avd->allowed) & ~(constraint->permissions);
}
return 0;
}
+static int security_validtrans_handle_fail(struct context *ocontext,
+ struct context *ncontext,
+ struct context *tcontext,
+ u16 tclass)
+{
+ char *o = NULL, *n = NULL, *t = NULL;
+ u32 olen, nlen, tlen;
+
+ if (context_struct_to_string(ocontext, &o, &olen) < 0)
+ goto out;
+ if (context_struct_to_string(ncontext, &n, &nlen) < 0)
+ goto out;
+ if (context_struct_to_string(tcontext, &t, &tlen) < 0)
+ goto out;
+ audit_log(current->audit_context,
+ "security_validate_transition: denied for"
+ " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
+ o, n, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+ kfree(o);
+ kfree(n);
+ kfree(t);
+
+ if (!selinux_enforcing)
+ return 0;
+ return -EPERM;
+}
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 tclass)
+{
+ struct context *ocontext;
+ struct context *ncontext;
+ struct context *tcontext;
+ struct class_datum *tclass_datum;
+ struct constraint_node *constraint;
+ int rc = 0;
+
+ if (!ss_initialized)
+ return 0;
+
+ POLICY_RDLOCK;
+
+ /*
+ * Remap extended Netlink classes for old policy versions.
+ * Do this here rather than socket_type_to_security_class()
+ * in case a newer policy version is loaded, allowing sockets
+ * to remain in the correct class.
+ */
+ if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
+ if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
+ tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
+ tclass = SECCLASS_NETLINK_SOCKET;
+
+ if (!tclass || tclass > policydb.p_classes.nprim) {
+ printk(KERN_ERR "security_validate_transition: "
+ "unrecognized class %d\n", tclass);
+ rc = -EINVAL;
+ goto out;
+ }
+ tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+ ocontext = sidtab_search(&sidtab, oldsid);
+ if (!ocontext) {
+ printk(KERN_ERR "security_validate_transition: "
+ " unrecognized SID %d\n", oldsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ ncontext = sidtab_search(&sidtab, newsid);
+ if (!ncontext) {
+ printk(KERN_ERR "security_validate_transition: "
+ " unrecognized SID %d\n", newsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ tcontext = sidtab_search(&sidtab, tasksid);
+ if (!tcontext) {
+ printk(KERN_ERR "security_validate_transition: "
+ " unrecognized SID %d\n", tasksid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ constraint = tclass_datum->validatetrans;
+ while (constraint) {
+ if (!constraint_expr_eval(ocontext, ncontext, tcontext,
+ constraint->expr)) {
+ rc = security_validtrans_handle_fail(ocontext, ncontext,
+ tcontext, tclass);
+ goto out;
+ }
+ constraint = constraint->next;
+ }
+
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
/**
* security_compute_av - Compute access vector decisions.
* @ssid: source security identifier
int rc = 0;
if (!ss_initialized) {
- avd->allowed = requested;
- avd->decided = requested;
+ avd->allowed = 0xffffffff;
+ avd->decided = 0xffffffff;
avd->auditallow = 0;
avd->auditdeny = 0xffffffff;
avd->seqno = latest_granting;
* to point to this string and set `*scontext_len' to
* the length of the string.
*/
-int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
{
char *scontextp;
*scontext_len += mls_compute_context_len(context);
/* Allocate space for the context; caller must free this space. */
- scontextp = kmalloc(*scontext_len+1,GFP_ATOMIC);
+ scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
if (!scontextp) {
return -ENOMEM;
}
/*
* Copy the user name, role name and type name into the context.
*/
- sprintf(scontextp, "%s:%s:%s:",
+ sprintf(scontextp, "%s:%s:%s",
policydb.p_user_val_to_name[context->user - 1],
policydb.p_role_val_to_name[context->role - 1],
policydb.p_type_val_to_name[context->type - 1]);
scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
- 1 + strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+ 1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
mls_sid_to_context(context, &scontextp);
- scontextp--;
*scontextp = 0;
return 0;
}
}
}
-
- if (!type_change && !roletr) {
- /* No change in process role or type. */
- *out_sid = ssid;
- goto out_unlock;
-
- }
break;
default:
- if (!type_change &&
- (newcontext.user == tcontext->user) &&
- mls_context_cmp(scontext, tcontext)) {
- /* No change in object type, owner,
- or MLS attributes. */
- *out_sid = tsid;
- goto out_unlock;
- }
break;
}
}
policydb_loaded_version = policydb.policyvers;
ss_initialized = 1;
-
+ seqno = ++latest_granting;
LOAD_UNLOCK;
selinux_complete_init();
+ avc_ss_reset(seqno);
+ selnl_notify_policyload(seqno);
return 0;
}
if (!ebitmap_get_bit(&role->types, j))
continue;
usercon.type = j+1;
- mls_for_user_ranges(user,usercon) {
- rc = context_struct_compute_av(fromcon, &usercon,
- SECCLASS_PROCESS,
- PROCESS__TRANSITION,
- &avd);
- if (rc || !(avd.allowed & PROCESS__TRANSITION))
- continue;
- rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
- if (rc) {
+
+ if (mls_setup_user_range(fromcon, user, &usercon))
+ continue;
+
+ rc = context_struct_compute_av(fromcon, &usercon,
+ SECCLASS_PROCESS,
+ PROCESS__TRANSITION,
+ &avd);
+ if (rc || !(avd.allowed & PROCESS__TRANSITION))
+ continue;
+ rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
+ if (rc) {
+ kfree(mysids);
+ goto out_unlock;
+ }
+ if (mynel < maxnel) {
+ mysids[mynel++] = sid;
+ } else {
+ maxnel += SIDS_NEL;
+ mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC);
+ if (!mysids2) {
+ rc = -ENOMEM;
kfree(mysids);
goto out_unlock;
}
- if (mynel < maxnel) {
- mysids[mynel++] = sid;
- } else {
- maxnel += SIDS_NEL;
- mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC);
- if (!mysids2) {
- rc = -ENOMEM;
- kfree(mysids);
- goto out_unlock;
- }
- memset(mysids2, 0, maxnel*sizeof(*mysids2));
- memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
- kfree(mysids);
- mysids = mysids2;
- mysids[mynel++] = sid;
- }
+ memset(mysids2, 0, maxnel*sizeof(*mysids2));
+ memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
+ kfree(mysids);
+ mysids = mysids2;
+ mysids[mynel++] = sid;
}
- mls_end_user_ranges;
}
}