|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Implementation of the userspace SID hashtable.
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil>
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
#include <errno.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdio.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdlib.h>
|
|
Chris PeBenito |
473ea7 |
#include <string.h>
|
|
Chris PeBenito |
473ea7 |
#include "selinux_internal.h"
|
|
Chris PeBenito |
473ea7 |
#include <selinux/avc.h>
|
|
Chris PeBenito |
473ea7 |
#include "avc_sidtab.h"
|
|
Chris PeBenito |
473ea7 |
#include "avc_internal.h"
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline unsigned sidtab_hash(security_context_t key) {
|
|
Chris PeBenito |
473ea7 |
char *p, *keyp;
|
|
Chris PeBenito |
473ea7 |
unsigned int size;
|
|
Chris PeBenito |
473ea7 |
unsigned int val;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
val = 0;
|
|
Chris PeBenito |
473ea7 |
keyp = (char*)key;
|
|
Chris PeBenito |
473ea7 |
size = strlen(keyp);
|
|
Chris PeBenito |
473ea7 |
for (p = keyp; (unsigned int)(p - keyp) < size; p++)
|
|
Chris PeBenito |
473ea7 |
val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
|
|
Chris PeBenito |
473ea7 |
return val & (SIDTAB_SIZE - 1);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int sidtab_init(struct sidtab *s)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i, rc = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
s->htable = (struct sidtab_node **)avc_malloc
|
|
Chris PeBenito |
473ea7 |
(sizeof(struct sidtab_node *) * SIDTAB_SIZE);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!s->htable) {
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < SIDTAB_SIZE; i++)
|
|
Chris PeBenito |
473ea7 |
s->htable[i] = NULL;
|
|
Chris PeBenito |
473ea7 |
s->nel = 0;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int
|
|
Chris PeBenito |
473ea7 |
sidtab_insert(struct sidtab *s, security_context_t ctx)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int hvalue, rc = 0;
|
|
Chris PeBenito |
473ea7 |
struct sidtab_node *newnode;
|
|
Chris PeBenito |
473ea7 |
security_context_t newctx;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
newnode = (struct sidtab_node*)avc_malloc(sizeof(*newnode));
|
|
Chris PeBenito |
473ea7 |
if (!newnode) {
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
newctx = (security_context_t)strdup(ctx);
|
|
Chris PeBenito |
473ea7 |
if (!newctx) {
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
avc_free(newnode);
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
hvalue = sidtab_hash(newctx);
|
|
Chris PeBenito |
473ea7 |
newnode->next = s->htable[hvalue];
|
|
Chris PeBenito |
473ea7 |
newnode->sid_s.ctx = newctx;
|
|
Chris PeBenito |
473ea7 |
newnode->sid_s.refcnt = 0; /* caller should increment */
|
|
Chris PeBenito |
473ea7 |
s->htable[hvalue] = newnode;
|
|
Chris PeBenito |
473ea7 |
s->nel++;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void
|
|
Chris PeBenito |
473ea7 |
sidtab_remove(struct sidtab *s, security_id_t sid)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int hvalue;
|
|
Chris PeBenito |
473ea7 |
struct sidtab_node *cur, *prev;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
hvalue = sidtab_hash(sid->ctx);
|
|
Chris PeBenito |
473ea7 |
cur = s->htable[hvalue];
|
|
Chris PeBenito |
473ea7 |
prev = NULL;
|
|
Chris PeBenito |
473ea7 |
while (cur) {
|
|
Chris PeBenito |
473ea7 |
if (sid == &cur->sid_s) {
|
|
Chris PeBenito |
473ea7 |
if (prev)
|
|
Chris PeBenito |
473ea7 |
prev->next = cur->next;
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
s->htable[hvalue] = cur->next;
|
|
Chris PeBenito |
473ea7 |
avc_free(cur);
|
|
Chris PeBenito |
473ea7 |
s->nel--;
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
prev = cur;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
security_id_t
|
|
Chris PeBenito |
473ea7 |
sidtab_claim_sid(struct sidtab *s)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
struct sidtab_node *cur;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i=0; i < SIDTAB_SIZE; i++) {
|
|
Chris PeBenito |
473ea7 |
cur = s->htable[i];
|
|
Chris PeBenito |
473ea7 |
while (cur) {
|
|
Chris PeBenito |
473ea7 |
if (!cur->sid_s.refcnt)
|
|
Chris PeBenito |
473ea7 |
return &cur->sid_s;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
return NULL;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int
|
|
Chris PeBenito |
473ea7 |
sidtab_context_to_sid(struct sidtab *s,
|
|
Chris PeBenito |
473ea7 |
security_context_t ctx,
|
|
Chris PeBenito |
473ea7 |
security_id_t *sid)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int hvalue, rc = 0;
|
|
Chris PeBenito |
473ea7 |
struct sidtab_node *cur;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
*sid = NULL;
|
|
Chris PeBenito |
473ea7 |
hvalue = sidtab_hash(ctx);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
loop:
|
|
Chris PeBenito |
473ea7 |
cur = s->htable[hvalue];
|
|
Chris PeBenito |
473ea7 |
while (cur != NULL && strcmp(cur->sid_s.ctx, ctx))
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (cur == NULL) { /* need to make a new entry */
|
|
Chris PeBenito |
473ea7 |
rc = sidtab_insert(s, ctx);
|
|
Chris PeBenito |
473ea7 |
if (rc)
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
goto loop; /* find the newly inserted node */
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
*sid = &cur->sid_s;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i, chain_len, slots_used, max_chain_len;
|
|
Chris PeBenito |
473ea7 |
struct sidtab_node *cur;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
slots_used = 0;
|
|
Chris PeBenito |
473ea7 |
max_chain_len = 0;
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
Chris PeBenito |
473ea7 |
cur = h->htable[i];
|
|
Chris PeBenito |
473ea7 |
if (cur) {
|
|
Chris PeBenito |
473ea7 |
slots_used++;
|
|
Chris PeBenito |
473ea7 |
chain_len = 0;
|
|
Chris PeBenito |
473ea7 |
while (cur) {
|
|
Chris PeBenito |
473ea7 |
chain_len++;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (chain_len > max_chain_len)
|
|
Chris PeBenito |
473ea7 |
max_chain_len = chain_len;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
snprintf(buf, buflen,
|
|
Chris PeBenito |
473ea7 |
"%s: %d SID entries and %d/%d buckets used, longest "
|
|
Chris PeBenito |
473ea7 |
"chain length %d\n", avc_prefix, h->nel, slots_used,
|
|
Chris PeBenito |
473ea7 |
SIDTAB_SIZE, max_chain_len);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void sidtab_destroy(struct sidtab *s)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
struct sidtab_node *cur, *temp;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!s)
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
Chris PeBenito |
473ea7 |
cur = s->htable[i];
|
|
Chris PeBenito |
473ea7 |
while (cur != NULL) {
|
|
Chris PeBenito |
473ea7 |
temp = cur;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
freecon(temp->sid_s.ctx);
|
|
Chris PeBenito |
473ea7 |
avc_free(temp);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
s->htable[i] = NULL;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
avc_free(s->htable);
|
|
Chris PeBenito |
473ea7 |
s->htable = NULL;
|
|
Chris PeBenito |
473ea7 |
}
|