mirror of
https://github.com/SELinuxProject/selinux
synced 2025-03-08 03:07:33 +00:00
329 lines
5.9 KiB
C
329 lines
5.9 KiB
C
|
|
/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
|
|
|
|
/* FLASK */
|
|
|
|
/*
|
|
* Implementation of the SID table type.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
|
|
#include <sepol/policydb/sidtab.h>
|
|
|
|
#include <sepol/policydb/flask.h>
|
|
|
|
#define SIDTAB_HASH(sid) \
|
|
(sid & SIDTAB_HASH_MASK)
|
|
|
|
#define INIT_SIDTAB_LOCK(s)
|
|
#define SIDTAB_LOCK(s)
|
|
#define SIDTAB_UNLOCK(s)
|
|
|
|
int sepol_sidtab_init(sidtab_t * s)
|
|
{
|
|
int i;
|
|
|
|
s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE);
|
|
if (!s->htable)
|
|
return -ENOMEM;
|
|
for (i = 0; i < SIDTAB_SIZE; i++)
|
|
s->htable[i] = (sidtab_ptr_t) NULL;
|
|
s->nel = 0;
|
|
s->next_sid = 1;
|
|
s->shutdown = 0;
|
|
INIT_SIDTAB_LOCK(s);
|
|
return 0;
|
|
}
|
|
|
|
int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid,
|
|
context_struct_t * context)
|
|
{
|
|
int hvalue;
|
|
sidtab_node_t *prev, *cur, *newnode;
|
|
|
|
if (!s || !s->htable)
|
|
return -ENOMEM;
|
|
|
|
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) {
|
|
errno = EEXIST;
|
|
return -EEXIST;
|
|
}
|
|
|
|
newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t));
|
|
if (newnode == NULL)
|
|
return -ENOMEM;
|
|
newnode->sid = sid;
|
|
if (context_cpy(&newnode->context, context)) {
|
|
free(newnode);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (prev) {
|
|
newnode->next = prev->next;
|
|
prev->next = newnode;
|
|
} else {
|
|
newnode->next = s->htable[hvalue];
|
|
s->htable[hvalue] = newnode;
|
|
}
|
|
|
|
s->nel++;
|
|
if (sid >= s->next_sid)
|
|
s->next_sid = sid + 1;
|
|
return 0;
|
|
}
|
|
|
|
int sepol_sidtab_remove(sidtab_t * s, sepol_security_id_t sid)
|
|
{
|
|
int hvalue;
|
|
sidtab_node_t *cur, *last;
|
|
|
|
if (!s || !s->htable)
|
|
return -ENOENT;
|
|
|
|
hvalue = SIDTAB_HASH(sid);
|
|
last = NULL;
|
|
cur = s->htable[hvalue];
|
|
while (cur != NULL && sid > cur->sid) {
|
|
last = cur;
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (cur == NULL || sid != cur->sid)
|
|
return -ENOENT;
|
|
|
|
if (last == NULL)
|
|
s->htable[hvalue] = cur->next;
|
|
else
|
|
last->next = cur->next;
|
|
|
|
context_destroy(&cur->context);
|
|
|
|
free(cur);
|
|
s->nel--;
|
|
return 0;
|
|
}
|
|
|
|
context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid)
|
|
{
|
|
int hvalue;
|
|
sidtab_node_t *cur;
|
|
|
|
if (!s || !s->htable)
|
|
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 sepol_sidtab_map(sidtab_t * s,
|
|
int (*apply) (sepol_security_id_t sid,
|
|
context_struct_t * context,
|
|
void *args), void *args)
|
|
{
|
|
int i, ret;
|
|
sidtab_node_t *cur;
|
|
|
|
if (!s || !s->htable)
|
|
return 0;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
ret = apply(cur->sid, &cur->context, args);
|
|
if (ret)
|
|
return ret;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void sepol_sidtab_map_remove_on_error(sidtab_t * s,
|
|
int (*apply) (sepol_security_id_t sid,
|
|
context_struct_t * context,
|
|
void *args), void *args)
|
|
{
|
|
int i, ret;
|
|
sidtab_node_t *last, *cur, *temp;
|
|
|
|
if (!s || !s->htable)
|
|
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);
|
|
free(temp);
|
|
s->nel--;
|
|
} else {
|
|
last = cur;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s,
|
|
context_struct_t *
|
|
context)
|
|
{
|
|
int i;
|
|
sidtab_node_t *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 sepol_sidtab_context_to_sid(sidtab_t * s,
|
|
context_struct_t * context,
|
|
sepol_security_id_t * out_sid)
|
|
{
|
|
sepol_security_id_t sid;
|
|
int ret = 0;
|
|
|
|
*out_sid = SEPOL_SECSID_NULL;
|
|
|
|
sid = sepol_sidtab_search_context(s, context);
|
|
if (!sid) {
|
|
SIDTAB_LOCK(s);
|
|
/* Rescan now that we hold the lock. */
|
|
sid = sepol_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 = sepol_sidtab_insert(s, sid, context);
|
|
if (ret)
|
|
s->next_sid--;
|
|
unlock_out:
|
|
SIDTAB_UNLOCK(s);
|
|
}
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
*out_sid = sid;
|
|
return 0;
|
|
}
|
|
|
|
void sepol_sidtab_hash_eval(sidtab_t * h, char *tag)
|
|
{
|
|
int i, chain_len, slots_used, max_chain_len;
|
|
sidtab_node_t *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;
|
|
}
|
|
}
|
|
|
|
printf
|
|
("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
|
|
tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len);
|
|
}
|
|
|
|
void sepol_sidtab_destroy(sidtab_t * s)
|
|
{
|
|
int i;
|
|
sidtab_ptr_t cur, temp;
|
|
|
|
if (!s || !s->htable)
|
|
return;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
temp = cur;
|
|
cur = cur->next;
|
|
context_destroy(&temp->context);
|
|
free(temp);
|
|
}
|
|
s->htable[i] = NULL;
|
|
}
|
|
free(s->htable);
|
|
s->htable = NULL;
|
|
s->nel = 0;
|
|
s->next_sid = 1;
|
|
}
|
|
|
|
void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src)
|
|
{
|
|
SIDTAB_LOCK(src);
|
|
dst->htable = src->htable;
|
|
dst->nel = src->nel;
|
|
dst->next_sid = src->next_sid;
|
|
dst->shutdown = 0;
|
|
SIDTAB_UNLOCK(src);
|
|
}
|
|
|
|
void sepol_sidtab_shutdown(sidtab_t * s)
|
|
{
|
|
SIDTAB_LOCK(s);
|
|
s->shutdown = 1;
|
|
SIDTAB_UNLOCK(s);
|
|
}
|
|
|
|
/* FLASK */
|