oskit/oskit-20020317/security/mls.c

545 lines
13 KiB
C
Executable File

/* FLASK */
/*
* Copyright (c) 1999, 2000 The University of Utah and the Flux Group.
* All rights reserved.
*
* Contributed by the Computer Security Research division,
* INFOSEC Research and Technology Office, NSA.
*
* This file is part of the Flux OSKit. The OSKit is free software, also known
* as "open source;" you can redistribute it and/or modify it under the terms
* of the GNU General Public License (GPL), version 2, as published by the Free
* Software Foundation (FSF). To explore alternate licensing terms, contact
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
*
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
* received a copy of the GPL along with the OSKit; see the file COPYING. If
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
*/
/*
* Implementation of the multi-level security (MLS) policy.
*/
#include "mls.h"
/*
* Remove any permissions from `allowed' that are
* denied by the MLS policy.
*/
void mls_compute_av(context_struct_t * scontext,
context_struct_t * tcontext,
class_datum_t * tclass,
access_vector_t * allowed)
{
unsigned int rel[2];
int l;
for (l = 0; l < 2; l++)
rel[l] = mls_level_relation(scontext->range.level[l],
tcontext->range.level[l]);
if (rel[1] != MLS_RELATION_EQ) {
if (rel[1] != MLS_RELATION_DOM)
/* read(s,t) = (s.high >= t.high) = False */
*allowed = (*allowed) & ~(tclass->mlsperms.read);
if (rel[1] != MLS_RELATION_DOMBY)
/* readby(s,t) = read(t,s) = False */
*allowed = (*allowed) & ~(tclass->mlsperms.readby);
}
if ((rel[0] != MLS_RELATION_DOMBY && rel[0] != MLS_RELATION_EQ) ||
((!mls_level_eq(tcontext->range.level[0],
tcontext->range.level[1])) &&
(rel[1] != MLS_RELATION_DOM && rel[1] != MLS_RELATION_EQ)))
/*
* write(s,t) = ((s.low <= t.low = t.high) or (s.low
* <= t.low <= t.high <= s.high)) = False
*/
*allowed = (*allowed) & ~(tclass->mlsperms.write);
if ((rel[0] != MLS_RELATION_DOM && rel[0] != MLS_RELATION_EQ) ||
((!mls_level_eq(scontext->range.level[0],
scontext->range.level[1])) &&
(rel[1] != MLS_RELATION_DOMBY && rel[1] != MLS_RELATION_EQ)))
/* writeby(s,t) = write(t,s) = False */
*allowed = (*allowed) & ~(tclass->mlsperms.writeby);
}
/*
* Return the length in bytes for the MLS fields of the
* security context string representation of `context'.
*/
int mls_compute_context_len(context_struct_t * context)
{
int i, l, len;
len = 0;
for (l = 0; l < 2; l++) {
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]) + 1;
for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
if (ebitmap_get_bit(&context->range.level[l].cat, i - 1))
len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
if (mls_level_relation(context->range.level[0], context->range.level[1]) == MLS_RELATION_EQ)
break;
}
return len;
}
/*
* Write the security context string representation of
* the MLS fields of `context' into the string `*scontext'.
* Update `*scontext' to point to the end of the MLS fields.
*/
int mls_sid_to_context(context_struct_t * context,
char **scontext)
{
char *scontextp;
int i, l;
scontextp = *scontext;
for (l = 0; l < 2; l++) {
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
*scontextp = ':';
scontextp++;
for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
*scontextp = ',';
scontextp++;
}
if (mls_level_relation(context->range.level[0], context->range.level[1]) != MLS_RELATION_EQ) {
scontextp--;
sprintf(scontextp, "-");
scontextp++;
} else {
break;
}
}
scontextp--;
*scontextp = 0;
*scontext = scontextp;
return 0;
}
/*
* Return TRUE if the MLS fields in the security context
* structure `c' are valid. Return FALSE otherwise.
*/
int mls_context_isvalid(policydb_t *p, context_struct_t * c)
{
unsigned int relation;
level_datum_t *levdatum;
user_datum_t *usrdatum;
mls_range_list_t *rnode;
int i, l;
/*
* MLS range validity checks: high must dominate low, low level must
* be valid (category set <-> sensitivity check), and high level must
* be valid (category set <-> sensitivity check)
*/
relation = mls_level_relation(c->range.level[1],
c->range.level[0]);
if (!(relation & (MLS_RELATION_DOM | MLS_RELATION_EQ)))
/* High does not dominate low. */
return FALSE;
for (l = 0; l < 2; l++) {
if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
return FALSE;
levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
p->p_sens_val_to_name[c->range.level[l].sens - 1]);
if (!levdatum)
return FALSE;
for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
if (i > p->p_cats.nprim)
return FALSE;
if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
/*
* Category may not be associated with
* sensitivity in low level.
*/
return FALSE;
}
}
}
/*
* User must be authorized for the MLS range.
*/
if (!c->user || c->user > p->p_users.nprim)
return FALSE;
usrdatum = p->user_val_to_struct[c->user - 1];
for (rnode = usrdatum->ranges; rnode; rnode = rnode->next) {
if (mls_range_contains(rnode->range, c->range))
break;
}
if (!rnode)
/* user may not be associated with range */
return FALSE;
return TRUE;
}
/*
* Set the MLS fields in the security context structure
* `context' based on the string representation in
* the string `*scontext'. Update `*scontext' to
* point to the end of the string representation of
* the MLS fields.
*
* This function modifies the string in place, inserting
* NULL characters to terminate the MLS fields.
*/
int mls_context_to_sid(char **scontext,
context_struct_t * context)
{
char delim;
char *scontextp, *p;
level_datum_t *levdatum;
cat_datum_t *catdatum;
int l;
/* Extract low sensitivity. */
scontextp = p = *scontext;
while (*p && *p != ':' && *p != '-')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
for (l = 0; l < 2; l++) {
levdatum = (level_datum_t *) hashtab_search(policydb.p_levels.table,
(hashtab_key_t) scontextp);
if (!levdatum)
return -EINVAL;
context->range.level[l].sens = levdatum->level->sens;
if (delim == ':') {
/* Extract low category set. */
while (1) {
scontextp = p;
while (*p && *p != ',' && *p != '-')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
catdatum = (cat_datum_t *) hashtab_search(policydb.p_cats.table,
(hashtab_key_t) scontextp);
if (!catdatum)
return -EINVAL;
if (!ebitmap_set_bit(&context->range.level[l].cat,
catdatum->value - 1, TRUE))
return -ENOMEM;
if (delim != ',')
break;
}
}
if (delim == '-') {
/* Extract high sensitivity. */
scontextp = p;
while (*p && *p != ':')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
} else
break;
}
if (l == 0) {
context->range.level[1].sens = context->range.level[0].sens;
ebitmap_cpy(&context->range.level[1].cat, &context->range.level[0].cat);
}
*scontext = p;
return 0;
}
/*
* Copies the MLS range from `scontext' into `newcontext'.
*/
int mls_member_sid(context_struct_t * newcontext,
context_struct_t * scontext)
{
int l;
/* Copy the MLS range from the source context */
for (l = 0; l < 2; l++) {
newcontext->range.level[l].sens = scontext->range.level[l].sens;
if (!ebitmap_cpy(&newcontext->range.level[l].cat, &scontext->range.level[l].cat))
return -ENOMEM;
}
return 0;
}
/*
* Convert the MLS fields in the security context
* structure `c' from the values specified in the
* policy `oldp' to the values specified in the policy `newp'.
*/
int mls_convert_context(policydb_t * oldp,
policydb_t * newp,
context_struct_t * c)
{
level_datum_t *levdatum;
cat_datum_t *catdatum;
ebitmap_t bitmap;
int l, i;
for (l = 0; l < 2; l++) {
levdatum = (level_datum_t *) hashtab_search(
newp->p_levels.table,
oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
if (!levdatum)
return -EINVAL;
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
catdatum = (cat_datum_t *) hashtab_search(newp->p_cats.table,
oldp->p_cat_val_to_name[i - 1]);
if (!catdatum)
return -EINVAL;
if (!ebitmap_set_bit(&bitmap, catdatum->value - 1, TRUE))
return -ENOMEM;
}
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
}
return 0;
}
/*
* Read a MLS level structure from a policydb binary
* representation file.
*/
mls_level_t *mls_read_level(FILE * fp)
{
mls_level_t *l;
__u32 sens;
int items;
l = malloc(sizeof(mls_level_t));
if (!l) {
printf("security: mls: out of memory\n");
return NULL;
}
memset(l, 0, sizeof(mls_level_t));
items = fread(&sens, sizeof(__u32), 1, fp);
if (items != 1) {
printf("security: mls: truncated level\n");
goto bad;
}
l->sens = cpu_to_le32(sens);
if (!ebitmap_read(&l->cat, fp)) {
printf("security: mls: error reading level categories\n");
goto bad;
}
return l;
bad:
free(l);
return NULL;
}
/*
* Read a MLS range structure from a policydb binary
* representation file.
*/
int mls_read_range(mls_range_t * r,
FILE * fp)
{
__u32 buf[3];
int items, items2;
items = fread(buf, sizeof(__u32), 1, fp);
if (items != 1)
return -1;
items2 = le32_to_cpu(buf[0]);
if (items2 > (sizeof(buf) / sizeof(__u32))) {
printf("security: mls: range too large\n");
return -1;
}
items = fread(buf, sizeof(__u32), items2, fp);
if (items != items2) {
printf("security: mls: truncated range\n");
return -1;
}
r->level[0].sens = le32_to_cpu(buf[0]);
if (items > 1) {
r->level[1].sens = le32_to_cpu(buf[1]);
} else {
r->level[1].sens = r->level[0].sens;
}
if (!ebitmap_read(&r->level[0].cat, fp)) {
printf("security: mls: error reading low categories\n");
return -1;
}
if (items > 1) {
if (!ebitmap_read(&r->level[1].cat, fp)) {
printf("security: mls: error reading high categories\n");
goto bad_high;
}
} else {
if (!ebitmap_cpy(&r->level[1].cat, &r->level[0].cat)) {
printf("security: mls: out of memory\n");
goto bad_high;
}
}
return 0;
bad_high:
ebitmap_destroy(&r->level[0].cat);
return -1;
}
/*
* Read a MLS perms structure from a policydb binary
* representation file.
*/
int mls_read_perms(mls_perms_t * p,
FILE * fp)
{
__u32 buf[32];
int items;
items = fread(buf, sizeof(__u32), 4, fp);
if (items != 4) {
printf("security: mls: truncated mls permissions\n");
return -1;
}
p->read = le32_to_cpu(buf[0]);
p->readby = le32_to_cpu(buf[1]);
p->write = le32_to_cpu(buf[2]);
p->writeby = le32_to_cpu(buf[3]);
return 0;
}
#ifndef __KERNEL__
/*
* Write a MLS level structure to a policydb binary
* representation file.
*/
int mls_write_level(mls_level_t * l,
FILE * fp)
{
__u32 sens;
int items;
sens = cpu_to_le32(l->sens);
items = fwrite(&sens, sizeof(__u32), 1, fp);
if (items != 1)
return -1;
if (!ebitmap_write(&l->cat, fp))
return -1;
return 0;
}
/*
* Write a MLS range structure to a policydb binary
* representation file.
*/
int mls_write_range(mls_range_t * r,
FILE * fp)
{
__u32 buf[3];
int items, items2;
int rel;
rel = mls_level_relation(r->level[1], r->level[0]);
items = 1; /* item 0 is used for the item count */
buf[items++] = cpu_to_le32(r->level[0].sens);
if (rel != MLS_RELATION_EQ)
buf[items++] = cpu_to_le32(r->level[1].sens);
buf[0] = cpu_to_le32(items - 1);
items2 = fwrite(buf, sizeof(__u32), items, fp);
if (items2 != items)
return -1;
if (!ebitmap_write(&r->level[0].cat, fp))
return -1;
if (rel != MLS_RELATION_EQ)
if (!ebitmap_write(&r->level[1].cat, fp))
return -1;
return 0;
}
/*
* Write a MLS perms structure to a policydb binary
* representation file.
*/
int mls_write_perms(mls_perms_t * p,
FILE * fp)
{
__u32 buf[32];
int items, items2;
items = 0;
buf[items++] = cpu_to_le32(p->read);
buf[items++] = cpu_to_le32(p->readby);
buf[items++] = cpu_to_le32(p->write);
buf[items++] = cpu_to_le32(p->writeby);
items2 = fwrite(buf, sizeof(__u32), items, fp);
if (items2 != items)
return -1;
return 0;
}
#endif
/* FLASK */