1 2/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */ 3 4/* FLASK */ 5 6/* 7 * Implementation of the SID table type. 8 */ 9 10#include <stdlib.h> 11#include <errno.h> 12#include <limits.h> 13#include <stdio.h> 14 15#include <sepol/policydb/sidtab.h> 16 17#include "flask.h" 18#include "private.h" 19 20#define SIDTAB_HASH(sid) \ 21(sid & SIDTAB_HASH_MASK) 22 23#define INIT_SIDTAB_LOCK(s) 24#define SIDTAB_LOCK(s) 25#define SIDTAB_UNLOCK(s) 26 27int sepol_sidtab_init(sidtab_t * s) 28{ 29 s->htable = calloc(SIDTAB_SIZE, sizeof(sidtab_ptr_t)); 30 if (!s->htable) 31 return -ENOMEM; 32 s->nel = 0; 33 s->next_sid = 1; 34 s->shutdown = 0; 35 INIT_SIDTAB_LOCK(s); 36 return 0; 37} 38 39int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid, 40 context_struct_t * context) 41{ 42 int hvalue; 43 sidtab_node_t *prev, *cur, *newnode; 44 45 if (!s || !s->htable) 46 return -ENOMEM; 47 48 hvalue = SIDTAB_HASH(sid); 49 prev = NULL; 50 cur = s->htable[hvalue]; 51 while (cur != NULL && sid > cur->sid) { 52 prev = cur; 53 cur = cur->next; 54 } 55 56 if (cur && sid == cur->sid) { 57 errno = EEXIST; 58 return -EEXIST; 59 } 60 61 newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t)); 62 if (newnode == NULL) 63 return -ENOMEM; 64 newnode->sid = sid; 65 if (context_cpy(&newnode->context, context)) { 66 free(newnode); 67 return -ENOMEM; 68 } 69 70 if (prev) { 71 newnode->next = prev->next; 72 prev->next = newnode; 73 } else { 74 newnode->next = s->htable[hvalue]; 75 s->htable[hvalue] = newnode; 76 } 77 78 s->nel++; 79 if (sid >= s->next_sid) 80 s->next_sid = sid + 1; 81 return 0; 82} 83 84context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid) 85{ 86 int hvalue; 87 sidtab_node_t *cur; 88 89 if (!s || !s->htable) 90 return NULL; 91 92 hvalue = SIDTAB_HASH(sid); 93 cur = s->htable[hvalue]; 94 while (cur != NULL && sid > cur->sid) 95 cur = cur->next; 96 97 if (cur == NULL || sid != cur->sid) { 98 /* Remap invalid SIDs to the unlabeled SID. */ 99 sid = SECINITSID_UNLABELED; 100 hvalue = SIDTAB_HASH(sid); 101 cur = s->htable[hvalue]; 102 while (cur != NULL && sid > cur->sid) 103 cur = cur->next; 104 if (!cur || sid != cur->sid) 105 return NULL; 106 } 107 108 return &cur->context; 109} 110 111int sepol_sidtab_map(sidtab_t * s, 112 int (*apply) (sepol_security_id_t sid, 113 context_struct_t * context, 114 void *args), void *args) 115{ 116 int i, ret; 117 sidtab_node_t *cur; 118 119 if (!s || !s->htable) 120 return 0; 121 122 for (i = 0; i < SIDTAB_SIZE; i++) { 123 cur = s->htable[i]; 124 while (cur != NULL) { 125 ret = apply(cur->sid, &cur->context, args); 126 if (ret) 127 return ret; 128 cur = cur->next; 129 } 130 } 131 return 0; 132} 133 134void sepol_sidtab_map_remove_on_error(sidtab_t * s, 135 int (*apply) (sepol_security_id_t sid, 136 context_struct_t * context, 137 void *args), void *args) 138{ 139 int i, ret; 140 sidtab_node_t *last, *cur, *temp; 141 142 if (!s || !s->htable) 143 return; 144 145 for (i = 0; i < SIDTAB_SIZE; i++) { 146 last = NULL; 147 cur = s->htable[i]; 148 while (cur != NULL) { 149 ret = apply(cur->sid, &cur->context, args); 150 if (ret) { 151 if (last) { 152 last->next = cur->next; 153 } else { 154 s->htable[i] = cur->next; 155 } 156 157 temp = cur; 158 cur = cur->next; 159 context_destroy(&temp->context); 160 free(temp); 161 s->nel--; 162 } else { 163 last = cur; 164 cur = cur->next; 165 } 166 } 167 } 168 169 return; 170} 171 172static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s, 173 context_struct_t * 174 context) 175{ 176 int i; 177 sidtab_node_t *cur; 178 179 for (i = 0; i < SIDTAB_SIZE; i++) { 180 cur = s->htable[i]; 181 while (cur != NULL) { 182 if (context_cmp(&cur->context, context)) 183 return cur->sid; 184 cur = cur->next; 185 } 186 } 187 return 0; 188} 189 190int sepol_sidtab_context_to_sid(sidtab_t * s, 191 context_struct_t * context, 192 sepol_security_id_t * out_sid) 193{ 194 sepol_security_id_t sid; 195 int ret = 0; 196 197 *out_sid = SEPOL_SECSID_NULL; 198 199 sid = sepol_sidtab_search_context(s, context); 200 if (!sid) { 201 SIDTAB_LOCK(s); 202 /* Rescan now that we hold the lock. */ 203 sid = sepol_sidtab_search_context(s, context); 204 if (sid) 205 goto unlock_out; 206 /* No SID exists for the context. Allocate a new one. */ 207 if (s->next_sid == UINT_MAX || s->shutdown) { 208 ret = -ENOMEM; 209 goto unlock_out; 210 } 211 sid = s->next_sid++; 212 ret = sepol_sidtab_insert(s, sid, context); 213 if (ret) 214 s->next_sid--; 215 unlock_out: 216 SIDTAB_UNLOCK(s); 217 } 218 219 if (ret) 220 return ret; 221 222 *out_sid = sid; 223 return 0; 224} 225 226void sepol_sidtab_hash_eval(sidtab_t * h, char *tag) 227{ 228 int i, chain_len, slots_used, max_chain_len; 229 sidtab_node_t *cur; 230 231 slots_used = 0; 232 max_chain_len = 0; 233 for (i = 0; i < SIDTAB_SIZE; i++) { 234 cur = h->htable[i]; 235 if (cur) { 236 slots_used++; 237 chain_len = 0; 238 while (cur) { 239 chain_len++; 240 cur = cur->next; 241 } 242 243 if (chain_len > max_chain_len) 244 max_chain_len = chain_len; 245 } 246 } 247 248 printf 249 ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", 250 tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len); 251} 252 253void sepol_sidtab_destroy(sidtab_t * s) 254{ 255 int i; 256 sidtab_ptr_t cur, temp; 257 258 if (!s || !s->htable) 259 return; 260 261 for (i = 0; i < SIDTAB_SIZE; i++) { 262 cur = s->htable[i]; 263 while (cur != NULL) { 264 temp = cur; 265 cur = cur->next; 266 context_destroy(&temp->context); 267 free(temp); 268 } 269 s->htable[i] = NULL; 270 } 271 free(s->htable); 272 s->htable = NULL; 273 s->nel = 0; 274 s->next_sid = 1; 275} 276 277void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src) 278{ 279 SIDTAB_LOCK(src); 280 dst->htable = src->htable; 281 dst->nel = src->nel; 282 dst->next_sid = src->next_sid; 283 dst->shutdown = 0; 284 SIDTAB_UNLOCK(src); 285} 286 287void sepol_sidtab_shutdown(sidtab_t * s) 288{ 289 SIDTAB_LOCK(s); 290 s->shutdown = 1; 291 SIDTAB_UNLOCK(s); 292} 293 294/* FLASK */ 295