cd354f1ae7
After Al Viro (finally) succeeded in removing the sched.h #include in module.h recently, it makes sense again to remove other superfluous sched.h includes. There are quite a lot of files which include it but don't actually need anything defined in there. Presumably these includes were once needed for macros that used to live in sched.h, but moved to other header files in the course of cleaning it up. To ease the pain, this time I did not fiddle with any header files and only removed #includes from .c-files, which tend to cause less trouble. Compile tested against 2.6.20-rc2 and 2.6.20-rc2-mm2 (with offsets) on alpha, arm, i386, ia64, mips, powerpc, and x86_64 with allnoconfig, defconfig, allmodconfig, and allyesconfig as well as a few randconfigs on x86_64 and all configs in arch/arm/configs on arm. I also checked that no new warnings were introduced by the patch (actually, some warnings are removed that were emitted by unnecessarily included header files). Signed-off-by: Tim Schmielau <tim@physik3.uni-rostock.de> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
304 lines
5.5 KiB
C
304 lines
5.5 KiB
C
/*
|
|
* Implementation of the SID table type.
|
|
*
|
|
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/errno.h>
|
|
#include "flask.h"
|
|
#include "security.h"
|
|
#include "sidtab.h"
|
|
|
|
#define SIDTAB_HASH(sid) \
|
|
(sid & SIDTAB_HASH_MASK)
|
|
|
|
#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
|
|
#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
|
|
#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
|
|
|
|
int sidtab_init(struct sidtab *s)
|
|
{
|
|
int i;
|
|
|
|
s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
|
|
if (!s->htable)
|
|
return -ENOMEM;
|
|
for (i = 0; i < SIDTAB_SIZE; i++)
|
|
s->htable[i] = NULL;
|
|
s->nel = 0;
|
|
s->next_sid = 1;
|
|
s->shutdown = 0;
|
|
INIT_SIDTAB_LOCK(s);
|
|
return 0;
|
|
}
|
|
|
|
int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
|
|
{
|
|
int hvalue, rc = 0;
|
|
struct sidtab_node *prev, *cur, *newnode;
|
|
|
|
if (!s) {
|
|
rc = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
hvalue = SIDTAB_HASH(sid);
|
|
prev = NULL;
|
|
cur = s->htable[hvalue];
|
|
while (cur != NULL && sid > cur->sid) {
|
|
prev = cur;
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (cur && sid == cur->sid) {
|
|
rc = -EEXIST;
|
|
goto out;
|
|
}
|
|
|
|
newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
|
|
if (newnode == NULL) {
|
|
rc = -ENOMEM;
|
|
goto out;
|
|
}
|
|
newnode->sid = sid;
|
|
if (context_cpy(&newnode->context, context)) {
|
|
kfree(newnode);
|
|
rc = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
if (prev) {
|
|
newnode->next = prev->next;
|
|
wmb();
|
|
prev->next = newnode;
|
|
} else {
|
|
newnode->next = s->htable[hvalue];
|
|
wmb();
|
|
s->htable[hvalue] = newnode;
|
|
}
|
|
|
|
s->nel++;
|
|
if (sid >= s->next_sid)
|
|
s->next_sid = sid + 1;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
struct context *sidtab_search(struct sidtab *s, u32 sid)
|
|
{
|
|
int hvalue;
|
|
struct sidtab_node *cur;
|
|
|
|
if (!s)
|
|
return NULL;
|
|
|
|
hvalue = SIDTAB_HASH(sid);
|
|
cur = s->htable[hvalue];
|
|
while (cur != NULL && sid > cur->sid)
|
|
cur = cur->next;
|
|
|
|
if (cur == NULL || sid != cur->sid) {
|
|
/* Remap invalid SIDs to the unlabeled SID. */
|
|
sid = SECINITSID_UNLABELED;
|
|
hvalue = SIDTAB_HASH(sid);
|
|
cur = s->htable[hvalue];
|
|
while (cur != NULL && sid > cur->sid)
|
|
cur = cur->next;
|
|
if (!cur || sid != cur->sid)
|
|
return NULL;
|
|
}
|
|
|
|
return &cur->context;
|
|
}
|
|
|
|
int sidtab_map(struct sidtab *s,
|
|
int (*apply) (u32 sid,
|
|
struct context *context,
|
|
void *args),
|
|
void *args)
|
|
{
|
|
int i, rc = 0;
|
|
struct sidtab_node *cur;
|
|
|
|
if (!s)
|
|
goto out;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
rc = apply(cur->sid, &cur->context, args);
|
|
if (rc)
|
|
goto out;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
void sidtab_map_remove_on_error(struct sidtab *s,
|
|
int (*apply) (u32 sid,
|
|
struct context *context,
|
|
void *args),
|
|
void *args)
|
|
{
|
|
int i, ret;
|
|
struct sidtab_node *last, *cur, *temp;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
last = NULL;
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
ret = apply(cur->sid, &cur->context, args);
|
|
if (ret) {
|
|
if (last) {
|
|
last->next = cur->next;
|
|
} else {
|
|
s->htable[i] = cur->next;
|
|
}
|
|
|
|
temp = cur;
|
|
cur = cur->next;
|
|
context_destroy(&temp->context);
|
|
kfree(temp);
|
|
s->nel--;
|
|
} else {
|
|
last = cur;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static inline u32 sidtab_search_context(struct sidtab *s,
|
|
struct context *context)
|
|
{
|
|
int i;
|
|
struct sidtab_node *cur;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
if (context_cmp(&cur->context, context))
|
|
return cur->sid;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int sidtab_context_to_sid(struct sidtab *s,
|
|
struct context *context,
|
|
u32 *out_sid)
|
|
{
|
|
u32 sid;
|
|
int ret = 0;
|
|
unsigned long flags;
|
|
|
|
*out_sid = SECSID_NULL;
|
|
|
|
sid = sidtab_search_context(s, context);
|
|
if (!sid) {
|
|
SIDTAB_LOCK(s, flags);
|
|
/* Rescan now that we hold the lock. */
|
|
sid = sidtab_search_context(s, context);
|
|
if (sid)
|
|
goto unlock_out;
|
|
/* No SID exists for the context. Allocate a new one. */
|
|
if (s->next_sid == UINT_MAX || s->shutdown) {
|
|
ret = -ENOMEM;
|
|
goto unlock_out;
|
|
}
|
|
sid = s->next_sid++;
|
|
ret = sidtab_insert(s, sid, context);
|
|
if (ret)
|
|
s->next_sid--;
|
|
unlock_out:
|
|
SIDTAB_UNLOCK(s, flags);
|
|
}
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
*out_sid = sid;
|
|
return 0;
|
|
}
|
|
|
|
void sidtab_hash_eval(struct sidtab *h, char *tag)
|
|
{
|
|
int i, chain_len, slots_used, max_chain_len;
|
|
struct sidtab_node *cur;
|
|
|
|
slots_used = 0;
|
|
max_chain_len = 0;
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = h->htable[i];
|
|
if (cur) {
|
|
slots_used++;
|
|
chain_len = 0;
|
|
while (cur) {
|
|
chain_len++;
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (chain_len > max_chain_len)
|
|
max_chain_len = chain_len;
|
|
}
|
|
}
|
|
|
|
printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
|
|
"chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
|
|
max_chain_len);
|
|
}
|
|
|
|
void sidtab_destroy(struct sidtab *s)
|
|
{
|
|
int i;
|
|
struct sidtab_node *cur, *temp;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
temp = cur;
|
|
cur = cur->next;
|
|
context_destroy(&temp->context);
|
|
kfree(temp);
|
|
}
|
|
s->htable[i] = NULL;
|
|
}
|
|
kfree(s->htable);
|
|
s->htable = NULL;
|
|
s->nel = 0;
|
|
s->next_sid = 1;
|
|
}
|
|
|
|
void sidtab_set(struct sidtab *dst, struct sidtab *src)
|
|
{
|
|
unsigned long flags;
|
|
|
|
SIDTAB_LOCK(src, flags);
|
|
dst->htable = src->htable;
|
|
dst->nel = src->nel;
|
|
dst->next_sid = src->next_sid;
|
|
dst->shutdown = 0;
|
|
SIDTAB_UNLOCK(src, flags);
|
|
}
|
|
|
|
void sidtab_shutdown(struct sidtab *s)
|
|
{
|
|
unsigned long flags;
|
|
|
|
SIDTAB_LOCK(s, flags);
|
|
s->shutdown = 1;
|
|
SIDTAB_UNLOCK(s, flags);
|
|
}
|