Commit e5c539b8 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] selinux: Conditional policy extension and MLS detection support

From: Stephen Smalley <sds@epoch.ncsc.mil>

This patch extends the SELinux policy engine to support conditional policy
logic based on a set of policy booleans, allowing well-formed changes to
the policy to be defined within and mediated by the policy itself.

The conditional policy extensions were implemented and contributed by
Tresys Technology.

Userland packages that support these extensions are already available from
nsa.gov/selinux, and backward compatibility is provided for the prior
policy version.

The patch also includes a small change to enable detection of the optional
MLS policy model on a SELinux system and fixes to the conditional policy
extensions to allow the MLS policy to work correctly with them that were
implemented and contributed by Trusted Computer Solutions.
parent a7e623a9
...@@ -84,6 +84,7 @@ static struct av_perm_to_string av_perm_to_string[] = { ...@@ -84,6 +84,7 @@ static struct av_perm_to_string av_perm_to_string[] = {
{ SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel" }, { SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel" },
{ SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user" }, { SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user" },
{ SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce" }, { SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce" },
{ SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool" },
{ SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info" }, { SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info" },
{ SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read" }, { SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read" },
{ SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod" }, { SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod" },
......
...@@ -512,6 +512,7 @@ ...@@ -512,6 +512,7 @@
#define SECURITY__COMPUTE_RELABEL 0x00000020UL #define SECURITY__COMPUTE_RELABEL 0x00000020UL
#define SECURITY__COMPUTE_USER 0x00000040UL #define SECURITY__COMPUTE_USER 0x00000040UL
#define SECURITY__SETENFORCE 0x00000080UL #define SECURITY__SETENFORCE 0x00000080UL
#define SECURITY__SETBOOL 0x00000100UL
#define SYSTEM__IPC_INFO 0x00000001UL #define SYSTEM__IPC_INFO 0x00000001UL
#define SYSTEM__SYSLOG_READ 0x00000002UL #define SYSTEM__SYSLOG_READ 0x00000002UL
......
/*
* Interface to booleans in the security server. This is exported
* for the selinuxfs.
*
* Author: Karl MacMillan <kmacmillan@tresys.com>
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#ifndef _SELINUX_CONDITIONAL_H_
#define _SELINUX_CONDITIONAL_H_
int security_get_bools(int *len, char ***names, int **values);
int security_set_bools(int len, int *values);
int security_get_bool_value(int bool);
#endif
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
* Security server interface. * Security server interface.
* *
* Author : Stephen Smalley, <sds@epoch.ncsc.mil> * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*
*/ */
#ifndef _SELINUX_SECURITY_H_ #ifndef _SELINUX_SECURITY_H_
#define _SELINUX_SECURITY_H_ #define _SELINUX_SECURITY_H_
...@@ -13,7 +15,8 @@ ...@@ -13,7 +15,8 @@
#define SECCLASS_NULL 0x0000 /* no class */ #define SECCLASS_NULL 0x0000 /* no class */
#define SELINUX_MAGIC 0xf97cff8c #define SELINUX_MAGIC 0xf97cff8c
#define POLICYDB_VERSION 15 #define POLICYDB_VERSION 16
#define POLICYDB_VERSION_COMPAT 15
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
extern int selinux_enabled; extern int selinux_enabled;
...@@ -21,6 +24,12 @@ extern int selinux_enabled; ...@@ -21,6 +24,12 @@ extern int selinux_enabled;
#define selinux_enabled 1 #define selinux_enabled 1
#endif #endif
#ifdef CONFIG_SECURITY_SELINUX_MLS
#define selinux_mls_enabled 1
#else
#define selinux_mls_enabled 0
#endif
int security_load_policy(void * data, size_t len); int security_load_policy(void * data, size_t len);
struct av_decision { struct av_decision {
......
This diff is collapsed.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
EXTRA_CFLAGS += -Isecurity/selinux/include EXTRA_CFLAGS += -Isecurity/selinux/include
obj-y := ss.o obj-y := ss.o
ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o
ss-$(CONFIG_SECURITY_SELINUX_MLS) += mls.o ss-$(CONFIG_SECURITY_SELINUX_MLS) += mls.o
...@@ -3,10 +3,22 @@ ...@@ -3,10 +3,22 @@
* *
* Author : Stephen Smalley, <sds@epoch.ncsc.mil> * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/ */
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 Tresys Technology, LLC
* 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.
*/
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/errno.h> #include <linux/errno.h>
#include "avtab.h" #include "avtab.h"
#include "policydb.h" #include "policydb.h"
...@@ -16,6 +28,29 @@ ...@@ -16,6 +28,29 @@
(keyp->source_type << 9)) & \ (keyp->source_type << 9)) & \
AVTAB_HASH_MASK) AVTAB_HASH_MASK)
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
struct avtab_key *key, struct avtab_datum *datum)
{
struct avtab_node * newnode;
newnode = (struct avtab_node *) kmalloc(sizeof(struct avtab_node),GFP_KERNEL);
if (newnode == NULL)
return NULL;
memset(newnode, 0, sizeof(struct avtab_node));
newnode->key = *key;
newnode->datum = *datum;
if (prev) {
newnode->next = prev->next;
prev->next = newnode;
} else {
newnode->next = h->htable[hvalue];
h->htable[hvalue] = newnode;
}
h->nel++;
return newnode;
}
int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
{ {
int hvalue; int hvalue;
...@@ -44,24 +79,48 @@ int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *dat ...@@ -44,24 +79,48 @@ int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *dat
break; break;
} }
newnode = kmalloc(sizeof(*newnode), GFP_KERNEL); newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
if (newnode == NULL) if(!newnode)
return -ENOMEM; return -ENOMEM;
memset(newnode, 0, sizeof(*newnode));
newnode->key = *key;
newnode->datum = *datum;
if (prev) {
newnode->next = prev->next;
prev->next = newnode;
} else {
newnode->next = h->htable[hvalue];
h->htable[hvalue] = newnode;
}
h->nel++;
return 0; return 0;
} }
/* Unlike avtab_insert(), this function allow multiple insertions of the same
* key/specified mask into the table, as needed by the conditional avtab.
* It also returns a pointer to the node inserted.
*/
struct avtab_node *
avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
{
int hvalue;
struct avtab_node *prev, *cur, *newnode;
if (!h)
return NULL;
hvalue = AVTAB_HASH(key);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
(datum->specified & cur->datum.specified))
break;
if (key->source_type < cur->key.source_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type < cur->key.target_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class < cur->key.target_class)
break;
}
newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
return newnode;
}
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified) struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
{ {
...@@ -93,6 +152,67 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int spe ...@@ -93,6 +152,67 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int spe
return NULL; return NULL;
} }
/* This search function returns a node pointer, and can be used in
* conjunction with avtab_search_next_node()
*/
struct avtab_node*
avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
{
int hvalue;
struct avtab_node *cur;
if (!h)
return NULL;
hvalue = AVTAB_HASH(key);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
(specified & cur->datum.specified))
return cur;
if (key->source_type < cur->key.source_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type < cur->key.target_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class < cur->key.target_class)
break;
}
return NULL;
}
struct avtab_node*
avtab_search_node_next(struct avtab_node *node, int specified)
{
struct avtab_node *cur;
if (!node)
return NULL;
for (cur = node->next; cur; cur = cur->next) {
if (node->key.source_type == cur->key.source_type &&
node->key.target_type == cur->key.target_type &&
node->key.target_class == cur->key.target_class &&
(specified & cur->datum.specified))
return cur;
if (node->key.source_type < cur->key.source_type)
break;
if (node->key.source_type == cur->key.source_type &&
node->key.target_type < cur->key.target_type)
break;
if (node->key.source_type == cur->key.source_type &&
node->key.target_type == cur->key.target_type &&
node->key.target_class < cur->key.target_class)
break;
}
return NULL;
}
void avtab_destroy(struct avtab *h) void avtab_destroy(struct avtab *h)
{ {
int i; int i;
...@@ -179,13 +299,72 @@ void avtab_hash_eval(struct avtab *h, char *tag) ...@@ -179,13 +299,72 @@ void avtab_hash_eval(struct avtab *h, char *tag)
max_chain_len); max_chain_len);
} }
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
{
__u32 *buf;
__u32 items, items2;
memset(avkey, 0, sizeof(struct avtab_key));
memset(avdatum, 0, sizeof(struct avtab_datum));
buf = next_entry(fp, sizeof(__u32));
if (!buf) {
printk(KERN_ERR "security: avtab: truncated entry\n");
goto bad;
}
items2 = le32_to_cpu(buf[0]);
buf = next_entry(fp, sizeof(__u32)*items2);
if (!buf) {
printk(KERN_ERR "security: avtab: truncated entry\n");
goto bad;
}
items = 0;
avkey->source_type = le32_to_cpu(buf[items++]);
avkey->target_type = le32_to_cpu(buf[items++]);
avkey->target_class = le32_to_cpu(buf[items++]);
avdatum->specified = le32_to_cpu(buf[items++]);
if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
printk(KERN_ERR "security: avtab: null entry\n");
goto bad;
}
if ((avdatum->specified & AVTAB_AV) &&
(avdatum->specified & AVTAB_TYPE)) {
printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
goto bad;
}
if (avdatum->specified & AVTAB_AV) {
if (avdatum->specified & AVTAB_ALLOWED)
avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_AUDITDENY)
avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_AUDITALLOW)
avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
} else {
if (avdatum->specified & AVTAB_TRANSITION)
avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_CHANGE)
avtab_change(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_MEMBER)
avtab_member(avdatum) = le32_to_cpu(buf[items++]);
}
if (items != items2) {
printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
items2, items);
goto bad;
}
return 0;
bad:
return -1;
}
int avtab_read(struct avtab *a, void *fp, u32 config) int avtab_read(struct avtab *a, void *fp, u32 config)
{ {
int i, rc = -EINVAL; int i, rc = -EINVAL;
struct avtab_key avkey; struct avtab_key avkey;
struct avtab_datum avdatum; struct avtab_datum avdatum;
u32 *buf; u32 *buf;
u32 nel, items, items2; u32 nel;
buf = next_entry(fp, sizeof(u32)); buf = next_entry(fp, sizeof(u32));
...@@ -199,55 +378,8 @@ int avtab_read(struct avtab *a, void *fp, u32 config) ...@@ -199,55 +378,8 @@ int avtab_read(struct avtab *a, void *fp, u32 config)
goto bad; goto bad;
} }
for (i = 0; i < nel; i++) { for (i = 0; i < nel; i++) {
memset(&avkey, 0, sizeof(avkey)); if (avtab_read_item(fp, &avdatum, &avkey))
memset(&avdatum, 0, sizeof(avdatum));
buf = next_entry(fp, sizeof(u32));
if (!buf) {
printk(KERN_ERR "security: avtab: truncated entry\n");
goto bad;
}
items2 = le32_to_cpu(buf[0]);
buf = next_entry(fp, sizeof(u32)*items2);
if (!buf) {
printk(KERN_ERR "security: avtab: truncated entry\n");
goto bad; goto bad;
}
items = 0;
avkey.source_type = le32_to_cpu(buf[items++]);
avkey.target_type = le32_to_cpu(buf[items++]);
avkey.target_class = le32_to_cpu(buf[items++]);
avdatum.specified = le32_to_cpu(buf[items++]);
if (!(avdatum.specified & (AVTAB_AV | AVTAB_TYPE))) {
printk(KERN_ERR "security: avtab: null entry\n");
goto bad;
}
if ((avdatum.specified & AVTAB_AV) &&
(avdatum.specified & AVTAB_TYPE)) {
printk(KERN_ERR "security: avtab: entry has both "
"access vectors and types\n");
goto bad;
}
if (avdatum.specified & AVTAB_AV) {
if (avdatum.specified & AVTAB_ALLOWED)
avtab_allowed(&avdatum) = le32_to_cpu(buf[items++]);
if (avdatum.specified & AVTAB_AUDITDENY)
avtab_auditdeny(&avdatum) = le32_to_cpu(buf[items++]);
if (avdatum.specified & AVTAB_AUDITALLOW)
avtab_auditallow(&avdatum) = le32_to_cpu(buf[items++]);
} else {
if (avdatum.specified & AVTAB_TRANSITION)
avtab_transition(&avdatum) = le32_to_cpu(buf[items++]);
if (avdatum.specified & AVTAB_CHANGE)
avtab_change(&avdatum) = le32_to_cpu(buf[items++]);
if (avdatum.specified & AVTAB_MEMBER)
avtab_member(&avdatum) = le32_to_cpu(buf[items++]);
}
if (items != items2) {
printk(KERN_ERR "security: avtab: entry only had %d "
"items, expected %d\n", items2, items);
goto bad;
}
rc = avtab_insert(a, &avkey, &avdatum); rc = avtab_insert(a, &avkey, &avdatum);
if (rc) { if (rc) {
if (rc == -ENOMEM) if (rc == -ENOMEM)
......
...@@ -7,6 +7,16 @@ ...@@ -7,6 +7,16 @@
* *
* Author : Stephen Smalley, <sds@epoch.ncsc.mil> * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/ */
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 Tresys Technology, LLC
* 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.
*/
#ifndef _SS_AVTAB_H_ #ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_ #define _SS_AVTAB_H_
...@@ -25,6 +35,7 @@ struct avtab_datum { ...@@ -25,6 +35,7 @@ struct avtab_datum {
#define AVTAB_MEMBER 32 #define AVTAB_MEMBER 32
#define AVTAB_CHANGE 64 #define AVTAB_CHANGE 64
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
#define AVTAB_ENABLED 0x80000000 /* reserved for used in cond_avtab */
u32 specified; /* what fields are specified */ u32 specified; /* what fields are specified */
u32 data[3]; /* access vectors or types */ u32 data[3]; /* access vectors or types */
#define avtab_allowed(x) (x)->data[0] #define avtab_allowed(x) (x)->data[0]
...@@ -56,8 +67,17 @@ int avtab_map(struct avtab *h, ...@@ -56,8 +67,17 @@ int avtab_map(struct avtab *h,
void *args), void *args),
void *args); void *args);
void avtab_hash_eval(struct avtab *h, char *tag); void avtab_hash_eval(struct avtab *h, char *tag);
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
int avtab_read(struct avtab *a, void *fp, u32 config); int avtab_read(struct avtab *a, void *fp, u32 config);
struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
struct avtab_datum *datum);
struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
#define AVTAB_HASH_BITS 15 #define AVTAB_HASH_BITS 15
#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) #define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) #define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
......
This diff is collapsed.
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
* Frank Mayer <mayerf@tresys.com>
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#ifndef _CONDITIONAL_H_
#define _CONDITIONAL_H_
#include "avtab.h"
#include "symtab.h"
#include "policydb.h"
#define COND_EXPR_MAXDEPTH 10
/*
* A conditional expression is a list of operators and operands
* in reverse polish notation.
*/
struct cond_expr {
#define COND_BOOL 1 /* plain bool */
#define COND_NOT 2 /* !bool */
#define COND_OR 3 /* bool || bool */
#define COND_AND 4 /* bool && bool */
#define COND_XOR 5 /* bool ^ bool */
#define COND_EQ 6 /* bool == bool */
#define COND_NEQ 7 /* bool != bool */
#define COND_LAST 8
__u32 expr_type;
__u32 bool;
struct cond_expr *next;
};
/*
* Each cond_node contains a list of rules to be enabled/disabled
* depending on the current value of the conditional expression. This
* struct is for that list.
*/
struct cond_av_list {
struct avtab_node *node;
struct cond_av_list *next;
};
/*
* A cond node represents a conditional block in a policy. It
* contains a conditional expression, the current state of the expression,
* two lists of rules to enable/disable depending on the value of the
* expression (the true list corresponds to if and the false list corresponds
* to else)..
*/
struct cond_node {
int cur_state;
struct cond_expr *expr;
struct cond_av_list *true_list;
struct cond_av_list *false_list;
struct cond_node *next;
};
int cond_policydb_init(struct policydb* p);
void cond_policydb_destroy(struct policydb* p);
int cond_init_bool_indexes(struct policydb* p);
int cond_destroy_bool(void *key, void *datum, void *p);
int cond_index_bool(void *key, void *datum, void *datap);
int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
int cond_read_list(struct policydb *p, void *fp);
void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
int evaluate_cond_node(struct policydb *p, struct cond_node *node);
#endif /* _CONDITIONAL_H_ */
...@@ -48,12 +48,12 @@ usercon.range = __ranges->range; ...@@ -48,12 +48,12 @@ usercon.range = __ranges->range;
#define mls_end_user_ranges } } #define mls_end_user_ranges } }
#define mls_symtab_names , "levels", "categories" #define mls_symtab_names "levels", "categories",
#define mls_symtab_sizes , 16, 16 #define mls_symtab_sizes 16, 16,
#define mls_index_f ,sens_index, cat_index #define mls_index_f sens_index, cat_index,
#define mls_destroy_f ,sens_destroy, cat_destroy #define mls_destroy_f sens_destroy, cat_destroy,
#define mls_read_f ,sens_read, cat_read #define mls_read_f sens_read, cat_read,
#define mls_write_f ,sens_write, cat_write #define mls_write_f sens_write, cat_write,
#define mls_policydb_index_others(p) printk(", %d levels", p->nlevels); #define mls_policydb_index_others(p) printk(", %d levels", p->nlevels);
#define mls_set_config(config) config |= POLICYDB_CONFIG_MLS #define mls_set_config(config) config |= POLICYDB_CONFIG_MLS
......
...@@ -3,12 +3,25 @@ ...@@ -3,12 +3,25 @@
* *
* Author : Stephen Smalley, <sds@epoch.ncsc.mil> * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/ */
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include "security.h" #include "security.h"
#include "policydb.h" #include "policydb.h"
#include "conditional.h"
#include "mls.h" #include "mls.h"
#define _DEBUG_HASHES #define _DEBUG_HASHES
...@@ -19,8 +32,9 @@ static char *symtab_name[SYM_NUM] = { ...@@ -19,8 +32,9 @@ static char *symtab_name[SYM_NUM] = {
"classes", "classes",
"roles", "roles",
"types", "types",
"users" "users",
mls_symtab_names mls_symtab_names
"bools"
}; };
#endif #endif
...@@ -29,8 +43,9 @@ static unsigned int symtab_sizes[SYM_NUM] = { ...@@ -29,8 +43,9 @@ static unsigned int symtab_sizes[SYM_NUM] = {
32, 32,
16, 16,
512, 512,
128 128,
mls_symtab_sizes mls_symtab_sizes
16
}; };
/* /*
...@@ -95,6 +110,10 @@ int policydb_init(struct policydb *p) ...@@ -95,6 +110,10 @@ int policydb_init(struct policydb *p)
if (rc) if (rc)
goto out_free_avtab; goto out_free_avtab;
rc = cond_policydb_init(p);
if (rc)
goto out_free_avtab;
out: out:
return rc; return rc;
...@@ -195,8 +214,9 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = ...@@ -195,8 +214,9 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
class_index, class_index,
role_index, role_index,
type_index, type_index,
user_index user_index,
mls_index_f mls_index_f
cond_index_bool
}; };
/* /*
...@@ -267,8 +287,8 @@ int policydb_index_others(struct policydb *p) ...@@ -267,8 +287,8 @@ int policydb_index_others(struct policydb *p)
{ {
int i, rc = 0; int i, rc = 0;
printk(KERN_INFO "security: %d users, %d roles, %d types", printk(KERN_INFO "security: %d users, %d roles, %d types, %d bools",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim); p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
mls_policydb_index_others(p); mls_policydb_index_others(p);
printk("\n"); printk("\n");
...@@ -296,6 +316,11 @@ int policydb_index_others(struct policydb *p) ...@@ -296,6 +316,11 @@ int policydb_index_others(struct policydb *p)
goto out; goto out;
} }
if (cond_init_bool_indexes(p)) {
rc = -ENOMEM;
goto out;
}
for (i = SYM_ROLES; i < SYM_NUM; i++) { for (i = SYM_ROLES; i < SYM_NUM; i++) {
p->sym_val_to_name[i] = p->sym_val_to_name[i] =
kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL); kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL);
...@@ -402,8 +427,9 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = ...@@ -402,8 +427,9 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
class_destroy, class_destroy,
role_destroy, role_destroy,
type_destroy, type_destroy,
user_destroy user_destroy,
mls_destroy_f mls_destroy_f
cond_destroy_bool
}; };
void ocontext_destroy(struct ocontext *c, int i) void ocontext_destroy(struct ocontext *c, int i)
...@@ -467,6 +493,8 @@ void policydb_destroy(struct policydb *p) ...@@ -467,6 +493,8 @@ void policydb_destroy(struct policydb *p)
kfree(gtmp); kfree(gtmp);
} }
cond_policydb_destroy(p);
return; return;
} }
...@@ -1040,8 +1068,9 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) ...@@ -1040,8 +1068,9 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
class_read, class_read,
role_read, role_read,
type_read, type_read,
user_read user_read,
mls_read_f mls_read_f
cond_read_bool
}; };
#define mls_config(x) \ #define mls_config(x) \
...@@ -1057,7 +1086,7 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1057,7 +1086,7 @@ int policydb_read(struct policydb *p, void *fp)
struct role_trans *tr, *ltr; struct role_trans *tr, *ltr;
struct ocontext *l, *c, *newc; struct ocontext *l, *c, *newc;
struct genfs *genfs_p, *genfs, *newgenfs; struct genfs *genfs_p, *genfs, *newgenfs;
int i, j, rc; int i, j, rc, policy_ver, num_syms;
u32 *buf, len, len2, config, nprim, nel, nel2; u32 *buf, len, len2, config, nprim, nel, nel2;
char *policydb_str; char *policydb_str;
...@@ -1122,7 +1151,8 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1122,7 +1151,8 @@ int policydb_read(struct policydb *p, void *fp)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
buf[i] = le32_to_cpu(buf[i]); buf[i] = le32_to_cpu(buf[i]);
if (buf[0] != POLICYDB_VERSION) { policy_ver = buf[0];
if (policy_ver != POLICYDB_VERSION && policy_ver != POLICYDB_VERSION_COMPAT) {
printk(KERN_ERR "security: policydb version %d does not match " printk(KERN_ERR "security: policydb version %d does not match "
"my version %d\n", buf[0], POLICYDB_VERSION); "my version %d\n", buf[0], POLICYDB_VERSION);
goto bad; goto bad;
...@@ -1134,18 +1164,30 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1134,18 +1164,30 @@ int policydb_read(struct policydb *p, void *fp)
mls_config(config)); mls_config(config));
goto bad; goto bad;
} }
if (buf[2] != SYM_NUM || buf[3] != OCON_NUM) {
printk(KERN_ERR "security: policydb table sizes (%d,%d) do " if (policy_ver == POLICYDB_VERSION_COMPAT) {
"not match mine (%d,%d)\n", if (buf[2] != (SYM_NUM - 1) || buf[3] != OCON_NUM) {
buf[2], buf[3], SYM_NUM, OCON_NUM); printk(KERN_ERR "security: policydb table sizes (%d,%d) do "
goto bad; "not match mine (%d,%d)\n",
buf[2], buf[3], SYM_NUM, OCON_NUM);
goto bad;
}
num_syms = SYM_NUM - 1;
} else {
if (buf[2] != SYM_NUM || buf[3] != OCON_NUM) {
printk(KERN_ERR "security: policydb table sizes (%d,%d) do "
"not match mine (%d,%d)\n",
buf[2], buf[3], SYM_NUM, OCON_NUM);
goto bad;
}
num_syms = SYM_NUM;
} }
rc = mls_read_nlevels(p, fp); rc = mls_read_nlevels(p, fp);
if (rc) if (rc)
goto bad; goto bad;
for (i = 0; i < SYM_NUM; i++) { for (i = 0; i < num_syms; i++) {
buf = next_entry(fp, sizeof(u32)*2); buf = next_entry(fp, sizeof(u32)*2);
if (!buf) { if (!buf) {
rc = -EINVAL; rc = -EINVAL;
...@@ -1166,6 +1208,12 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1166,6 +1208,12 @@ int policydb_read(struct policydb *p, void *fp)
if (rc) if (rc)
goto bad; goto bad;
if (policy_ver == POLICYDB_VERSION) {
rc = cond_read_list(p, fp);
if (rc)
goto bad;
}
buf = next_entry(fp, sizeof(u32)); buf = next_entry(fp, sizeof(u32));
if (!buf) { if (!buf) {
rc = -EINVAL; rc = -EINVAL;
......
...@@ -4,6 +4,17 @@ ...@@ -4,6 +4,17 @@
* *
* Author : Stephen Smalley, <sds@epoch.ncsc.mil> * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/ */
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#ifndef _SS_POLICYDB_H_ #ifndef _SS_POLICYDB_H_
#define _SS_POLICYDB_H_ #define _SS_POLICYDB_H_
...@@ -100,6 +111,13 @@ struct cat_datum { ...@@ -100,6 +111,13 @@ struct cat_datum {
}; };
#endif #endif
/* Boolean data type */
struct cond_bool_datum {
__u32 value; /* internal type value */
int state;
};
struct cond_node;
/* /*
* The configuration data includes security contexts for * The configuration data includes security contexts for
...@@ -145,9 +163,11 @@ struct genfs { ...@@ -145,9 +163,11 @@ struct genfs {
#ifdef CONFIG_SECURITY_SELINUX_MLS #ifdef CONFIG_SECURITY_SELINUX_MLS
#define SYM_LEVELS 5 #define SYM_LEVELS 5
#define SYM_CATS 6 #define SYM_CATS 6
#define SYM_NUM 7 #define SYM_BOOLS 7
#define SYM_NUM 8
#else #else
#define SYM_NUM 5 #define SYM_BOOLS 5
#define SYM_NUM 6
#endif #endif
/* object context array indices */ /* object context array indices */
...@@ -170,6 +190,7 @@ struct policydb { ...@@ -170,6 +190,7 @@ struct policydb {
#define p_users symtab[SYM_USERS] #define p_users symtab[SYM_USERS]
#define p_levels symtab[SYM_LEVELS] #define p_levels symtab[SYM_LEVELS]
#define p_cats symtab[SYM_CATS] #define p_cats symtab[SYM_CATS]
#define p_bools symtab[SYM_BOOLS]
/* symbol names indexed by (value - 1) */ /* symbol names indexed by (value - 1) */
char **sym_val_to_name[SYM_NUM]; char **sym_val_to_name[SYM_NUM];
...@@ -180,6 +201,7 @@ struct policydb { ...@@ -180,6 +201,7 @@ struct policydb {
#define p_user_val_to_name sym_val_to_name[SYM_USERS] #define p_user_val_to_name sym_val_to_name[SYM_USERS]
#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS] #define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
#define p_cat_val_to_name sym_val_to_name[SYM_CATS] #define p_cat_val_to_name sym_val_to_name[SYM_CATS]
#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
/* class, role, and user attributes indexed by (value - 1) */ /* class, role, and user attributes indexed by (value - 1) */
struct class_datum **class_val_to_struct; struct class_datum **class_val_to_struct;
...@@ -192,6 +214,13 @@ struct policydb { ...@@ -192,6 +214,13 @@ struct policydb {
/* role transitions */ /* role transitions */
struct role_trans *role_tr; struct role_trans *role_tr;
/* bools indexed by (value - 1) */
struct cond_bool_datum **bool_val_to_struct;
/* type enforcement conditional access vectors and transitions */
struct avtab te_cond_avtab;
/* linked list indexing te_cond_avtab by conditional */
struct cond_node* cond_list;
/* role allows */ /* role allows */
struct role_allow *role_allow; struct role_allow *role_allow;
......
...@@ -9,6 +9,15 @@ ...@@ -9,6 +9,15 @@
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, * it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -26,6 +35,7 @@ ...@@ -26,6 +35,7 @@
#include "policydb.h" #include "policydb.h"
#include "sidtab.h" #include "sidtab.h"
#include "services.h" #include "services.h"
#include "conditional.h"
#include "mls.h" #include "mls.h"
extern void selnl_notify_policyload(u32 seqno); extern void selnl_notify_policyload(u32 seqno);
...@@ -225,6 +235,9 @@ static int context_struct_compute_av(struct context *scontext, ...@@ -225,6 +235,9 @@ static int context_struct_compute_av(struct context *scontext,
avd->auditallow = avtab_auditallow(avdatum); avd->auditallow = avtab_auditallow(avdatum);
} }
/* Check conditional av table for additional permissions */
cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
/* /*
* Remove any permissions prohibited by the MLS policy. * Remove any permissions prohibited by the MLS policy.
*/ */
...@@ -573,6 +586,7 @@ static int security_compute_sid(u32 ssid, ...@@ -573,6 +586,7 @@ static int security_compute_sid(u32 ssid,
struct role_trans *roletr = 0; struct role_trans *roletr = 0;
struct avtab_key avkey; struct avtab_key avkey;
struct avtab_datum *avdatum; struct avtab_datum *avdatum;
struct avtab_node *node;
unsigned int type_change = 0; unsigned int type_change = 0;
int rc = 0; int rc = 0;
...@@ -639,6 +653,18 @@ static int security_compute_sid(u32 ssid, ...@@ -639,6 +653,18 @@ static int security_compute_sid(u32 ssid,
avkey.target_type = tcontext->type; avkey.target_type = tcontext->type;
avkey.target_class = tclass; avkey.target_class = tclass;
avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE); avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE);
/* If no permanent rule, also check for enabled conditional rules */
if(!avdatum) {
node = avtab_search_node(&policydb.te_cond_avtab, &avkey, specified);
for (; node != NULL; node = avtab_search_node_next(node, specified)) {
if (node->datum.specified & AVTAB_ENABLED) {
avdatum = &node->datum;
break;
}
}
}
type_change = (avdatum && (avdatum->specified & specified)); type_change = (avdatum && (avdatum->specified & specified));
if (type_change) { if (type_change) {
/* Use the type from the type transition/member/change rule. */ /* Use the type from the type transition/member/change rule. */
...@@ -1000,6 +1026,7 @@ int security_load_policy(void *data, size_t len) ...@@ -1000,6 +1026,7 @@ int security_load_policy(void *data, size_t len)
return -EINVAL; return -EINVAL;
} }
ss_initialized = 1; ss_initialized = 1;
LOAD_UNLOCK; LOAD_UNLOCK;
selinux_complete_init(); selinux_complete_init();
return 0; return 0;
...@@ -1046,6 +1073,7 @@ int security_load_policy(void *data, size_t len) ...@@ -1046,6 +1073,7 @@ int security_load_policy(void *data, size_t len)
memcpy(&policydb, &newpolicydb, sizeof policydb); memcpy(&policydb, &newpolicydb, sizeof policydb);
sidtab_set(&sidtab, &newsidtab); sidtab_set(&sidtab, &newsidtab);
seqno = ++latest_granting; seqno = ++latest_granting;
POLICY_WRUNLOCK; POLICY_WRUNLOCK;
LOAD_UNLOCK; LOAD_UNLOCK;
...@@ -1428,3 +1456,116 @@ int security_fs_use( ...@@ -1428,3 +1456,116 @@ int security_fs_use(
POLICY_RDUNLOCK; POLICY_RDUNLOCK;
return rc; return rc;
} }
int security_get_bools(int *len, char ***names, int **values)
{
int i, rc = -ENOMEM;
POLICY_RDLOCK;
*names = NULL;
*values = NULL;
*len = policydb.p_bools.nprim;
if (!*len) {
rc = 0;
goto out;
}
*names = (char**)kmalloc(sizeof(char*) * *len, GFP_ATOMIC);
if (!*names)
goto err;
memset(*names, 0, sizeof(char*) * *len);
*values = (int*)kmalloc(sizeof(int) * *len, GFP_ATOMIC);
if (!*values)
goto err;
for (i = 0; i < *len; i++) {
size_t name_len;
(*values)[i] = policydb.bool_val_to_struct[i]->state;
name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
(*names)[i] = (char*)kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
if (!(*names)[i])
goto err;
strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
(*names)[i][name_len - 1] = 0;
}
rc = 0;
out:
POLICY_RDUNLOCK;
return rc;
err:
if (*names) {
for (i = 0; i < *len; i++)
if ((*names)[i])
kfree((*names)[i]);
}
if (*values)
kfree(*values);
goto out;
}
int security_set_bools(int len, int *values)
{
int i, rc = 0;
int lenp, seqno = 0;
struct cond_node *cur;
POLICY_WRLOCK;
lenp = policydb.p_bools.nprim;
if (len != lenp) {
rc = -EFAULT;
goto out;
}
printk(KERN_INFO "security: committed booleans { ");
for (i = 0; i < len; i++) {
if (values[i]) {
policydb.bool_val_to_struct[i]->state = 1;
} else {
policydb.bool_val_to_struct[i]->state = 0;
}
if (i != 0)
printk(", ");
printk("%s:%d", policydb.p_bool_val_to_name[i],
policydb.bool_val_to_struct[i]->state);
}
printk(" }\n");
for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
rc = evaluate_cond_node(&policydb, cur);
if (rc)
goto out;
}
seqno = ++latest_granting;
out:
POLICY_WRUNLOCK;
if (!rc) {
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
}
return rc;
}
int security_get_bool_value(int bool)
{
int rc = 0;
int len;
POLICY_RDLOCK;
len = policydb.p_bools.nprim;
if (bool >= len) {
rc = -EFAULT;
goto out;
}
rc = policydb.bool_val_to_struct[bool]->state;
out:
POLICY_RDUNLOCK;
return rc;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment