1/* 2 * Implementation of the userspace SID hashtable. 3 * 4 * Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil> 5 */ 6#include <errno.h> 7#include <stdio.h> 8#include <stdlib.h> 9#include <stdint.h> 10#include <string.h> 11#include "selinux_internal.h" 12#include <selinux/avc.h> 13#include "avc_sidtab.h" 14#include "avc_internal.h" 15 16static inline unsigned sidtab_hash(const char * key) 17{ 18 const char *p; 19 unsigned int size; 20 unsigned int val; 21 22 val = 0; 23 size = strlen(key); 24 for (p = key; (unsigned int)(p - key) < size; p++) 25 val = 26 (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p); 27 return val & (SIDTAB_SIZE - 1); 28} 29 30int sidtab_init(struct sidtab *s) 31{ 32 int i, rc = 0; 33 34 s->htable = (struct sidtab_node **)avc_malloc 35 (sizeof(struct sidtab_node *) * SIDTAB_SIZE); 36 37 if (!s->htable) { 38 rc = -1; 39 goto out; 40 } 41 for (i = 0; i < SIDTAB_SIZE; i++) 42 s->htable[i] = NULL; 43 s->nel = 0; 44 out: 45 return rc; 46} 47 48int sidtab_insert(struct sidtab *s, const char * ctx) 49{ 50 int hvalue, rc = 0; 51 struct sidtab_node *newnode; 52 char * newctx; 53 54 newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode)); 55 if (!newnode) { 56 rc = -1; 57 goto out; 58 } 59 newctx = strdup(ctx); 60 if (!newctx) { 61 rc = -1; 62 avc_free(newnode); 63 goto out; 64 } 65 66 hvalue = sidtab_hash(newctx); 67 newnode->next = s->htable[hvalue]; 68 newnode->sid_s.ctx = newctx; 69 newnode->sid_s.refcnt = 1; /* unused */ 70 s->htable[hvalue] = newnode; 71 s->nel++; 72 out: 73 return rc; 74} 75 76int 77sidtab_context_to_sid(struct sidtab *s, 78 const char * ctx, security_id_t * sid) 79{ 80 int hvalue, rc = 0; 81 struct sidtab_node *cur; 82 83 *sid = NULL; 84 hvalue = sidtab_hash(ctx); 85 86 loop: 87 cur = s->htable[hvalue]; 88 while (cur != NULL && strcmp(cur->sid_s.ctx, ctx)) 89 cur = cur->next; 90 91 if (cur == NULL) { /* need to make a new entry */ 92 rc = sidtab_insert(s, ctx); 93 if (rc) 94 goto out; 95 goto loop; /* find the newly inserted node */ 96 } 97 98 *sid = &cur->sid_s; 99 out: 100 return rc; 101} 102 103void sidtab_sid_stats(struct sidtab *s, char *buf, int buflen) 104{ 105 int i, chain_len, slots_used, max_chain_len; 106 struct sidtab_node *cur; 107 108 slots_used = 0; 109 max_chain_len = 0; 110 for (i = 0; i < SIDTAB_SIZE; i++) { 111 cur = s->htable[i]; 112 if (cur) { 113 slots_used++; 114 chain_len = 0; 115 while (cur) { 116 chain_len++; 117 cur = cur->next; 118 } 119 120 if (chain_len > max_chain_len) 121 max_chain_len = chain_len; 122 } 123 } 124 125 snprintf(buf, buflen, 126 "%s: %u SID entries and %d/%d buckets used, longest " 127 "chain length %d\n", avc_prefix, s->nel, slots_used, 128 SIDTAB_SIZE, max_chain_len); 129} 130 131void sidtab_destroy(struct sidtab *s) 132{ 133 int i; 134 struct sidtab_node *cur, *temp; 135 136 if (!s) 137 return; 138 139 for (i = 0; i < SIDTAB_SIZE; i++) { 140 cur = s->htable[i]; 141 while (cur != NULL) { 142 temp = cur; 143 cur = cur->next; 144 freecon(temp->sid_s.ctx); 145 avc_free(temp); 146 } 147 s->htable[i] = NULL; 148 } 149 avc_free(s->htable); 150 s->htable = NULL; 151} 152