mirror of https://github.com/dzavalishin/oskit/
545 lines
13 KiB
C
Executable File
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 */
|