16cd6a6acSopenharmony_ci 26cd6a6acSopenharmony_ci/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */ 36cd6a6acSopenharmony_ci 46cd6a6acSopenharmony_ci/* FLASK */ 56cd6a6acSopenharmony_ci 66cd6a6acSopenharmony_ci/* 76cd6a6acSopenharmony_ci * Implementation of the SID table type. 86cd6a6acSopenharmony_ci */ 96cd6a6acSopenharmony_ci 106cd6a6acSopenharmony_ci#include <stdlib.h> 116cd6a6acSopenharmony_ci#include <errno.h> 126cd6a6acSopenharmony_ci#include <limits.h> 136cd6a6acSopenharmony_ci#include <stdio.h> 146cd6a6acSopenharmony_ci 156cd6a6acSopenharmony_ci#include <sepol/policydb/sidtab.h> 166cd6a6acSopenharmony_ci 176cd6a6acSopenharmony_ci#include "flask.h" 186cd6a6acSopenharmony_ci#include "private.h" 196cd6a6acSopenharmony_ci 206cd6a6acSopenharmony_ci#define SIDTAB_HASH(sid) \ 216cd6a6acSopenharmony_ci(sid & SIDTAB_HASH_MASK) 226cd6a6acSopenharmony_ci 236cd6a6acSopenharmony_ci#define INIT_SIDTAB_LOCK(s) 246cd6a6acSopenharmony_ci#define SIDTAB_LOCK(s) 256cd6a6acSopenharmony_ci#define SIDTAB_UNLOCK(s) 266cd6a6acSopenharmony_ci 276cd6a6acSopenharmony_ciint sepol_sidtab_init(sidtab_t * s) 286cd6a6acSopenharmony_ci{ 296cd6a6acSopenharmony_ci s->htable = calloc(SIDTAB_SIZE, sizeof(sidtab_ptr_t)); 306cd6a6acSopenharmony_ci if (!s->htable) 316cd6a6acSopenharmony_ci return -ENOMEM; 326cd6a6acSopenharmony_ci s->nel = 0; 336cd6a6acSopenharmony_ci s->next_sid = 1; 346cd6a6acSopenharmony_ci s->shutdown = 0; 356cd6a6acSopenharmony_ci INIT_SIDTAB_LOCK(s); 366cd6a6acSopenharmony_ci return 0; 376cd6a6acSopenharmony_ci} 386cd6a6acSopenharmony_ci 396cd6a6acSopenharmony_ciint sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid, 406cd6a6acSopenharmony_ci context_struct_t * context) 416cd6a6acSopenharmony_ci{ 426cd6a6acSopenharmony_ci int hvalue; 436cd6a6acSopenharmony_ci sidtab_node_t *prev, *cur, *newnode; 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci if (!s || !s->htable) 466cd6a6acSopenharmony_ci return -ENOMEM; 476cd6a6acSopenharmony_ci 486cd6a6acSopenharmony_ci hvalue = SIDTAB_HASH(sid); 496cd6a6acSopenharmony_ci prev = NULL; 506cd6a6acSopenharmony_ci cur = s->htable[hvalue]; 516cd6a6acSopenharmony_ci while (cur != NULL && sid > cur->sid) { 526cd6a6acSopenharmony_ci prev = cur; 536cd6a6acSopenharmony_ci cur = cur->next; 546cd6a6acSopenharmony_ci } 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ci if (cur && sid == cur->sid) { 576cd6a6acSopenharmony_ci errno = EEXIST; 586cd6a6acSopenharmony_ci return -EEXIST; 596cd6a6acSopenharmony_ci } 606cd6a6acSopenharmony_ci 616cd6a6acSopenharmony_ci newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t)); 626cd6a6acSopenharmony_ci if (newnode == NULL) 636cd6a6acSopenharmony_ci return -ENOMEM; 646cd6a6acSopenharmony_ci newnode->sid = sid; 656cd6a6acSopenharmony_ci if (context_cpy(&newnode->context, context)) { 666cd6a6acSopenharmony_ci free(newnode); 676cd6a6acSopenharmony_ci return -ENOMEM; 686cd6a6acSopenharmony_ci } 696cd6a6acSopenharmony_ci 706cd6a6acSopenharmony_ci if (prev) { 716cd6a6acSopenharmony_ci newnode->next = prev->next; 726cd6a6acSopenharmony_ci prev->next = newnode; 736cd6a6acSopenharmony_ci } else { 746cd6a6acSopenharmony_ci newnode->next = s->htable[hvalue]; 756cd6a6acSopenharmony_ci s->htable[hvalue] = newnode; 766cd6a6acSopenharmony_ci } 776cd6a6acSopenharmony_ci 786cd6a6acSopenharmony_ci s->nel++; 796cd6a6acSopenharmony_ci if (sid >= s->next_sid) 806cd6a6acSopenharmony_ci s->next_sid = sid + 1; 816cd6a6acSopenharmony_ci return 0; 826cd6a6acSopenharmony_ci} 836cd6a6acSopenharmony_ci 846cd6a6acSopenharmony_cicontext_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid) 856cd6a6acSopenharmony_ci{ 866cd6a6acSopenharmony_ci int hvalue; 876cd6a6acSopenharmony_ci sidtab_node_t *cur; 886cd6a6acSopenharmony_ci 896cd6a6acSopenharmony_ci if (!s || !s->htable) 906cd6a6acSopenharmony_ci return NULL; 916cd6a6acSopenharmony_ci 926cd6a6acSopenharmony_ci hvalue = SIDTAB_HASH(sid); 936cd6a6acSopenharmony_ci cur = s->htable[hvalue]; 946cd6a6acSopenharmony_ci while (cur != NULL && sid > cur->sid) 956cd6a6acSopenharmony_ci cur = cur->next; 966cd6a6acSopenharmony_ci 976cd6a6acSopenharmony_ci if (cur == NULL || sid != cur->sid) { 986cd6a6acSopenharmony_ci /* Remap invalid SIDs to the unlabeled SID. */ 996cd6a6acSopenharmony_ci sid = SECINITSID_UNLABELED; 1006cd6a6acSopenharmony_ci hvalue = SIDTAB_HASH(sid); 1016cd6a6acSopenharmony_ci cur = s->htable[hvalue]; 1026cd6a6acSopenharmony_ci while (cur != NULL && sid > cur->sid) 1036cd6a6acSopenharmony_ci cur = cur->next; 1046cd6a6acSopenharmony_ci if (!cur || sid != cur->sid) 1056cd6a6acSopenharmony_ci return NULL; 1066cd6a6acSopenharmony_ci } 1076cd6a6acSopenharmony_ci 1086cd6a6acSopenharmony_ci return &cur->context; 1096cd6a6acSopenharmony_ci} 1106cd6a6acSopenharmony_ci 1116cd6a6acSopenharmony_ciint sepol_sidtab_map(sidtab_t * s, 1126cd6a6acSopenharmony_ci int (*apply) (sepol_security_id_t sid, 1136cd6a6acSopenharmony_ci context_struct_t * context, 1146cd6a6acSopenharmony_ci void *args), void *args) 1156cd6a6acSopenharmony_ci{ 1166cd6a6acSopenharmony_ci int i, ret; 1176cd6a6acSopenharmony_ci sidtab_node_t *cur; 1186cd6a6acSopenharmony_ci 1196cd6a6acSopenharmony_ci if (!s || !s->htable) 1206cd6a6acSopenharmony_ci return 0; 1216cd6a6acSopenharmony_ci 1226cd6a6acSopenharmony_ci for (i = 0; i < SIDTAB_SIZE; i++) { 1236cd6a6acSopenharmony_ci cur = s->htable[i]; 1246cd6a6acSopenharmony_ci while (cur != NULL) { 1256cd6a6acSopenharmony_ci ret = apply(cur->sid, &cur->context, args); 1266cd6a6acSopenharmony_ci if (ret) 1276cd6a6acSopenharmony_ci return ret; 1286cd6a6acSopenharmony_ci cur = cur->next; 1296cd6a6acSopenharmony_ci } 1306cd6a6acSopenharmony_ci } 1316cd6a6acSopenharmony_ci return 0; 1326cd6a6acSopenharmony_ci} 1336cd6a6acSopenharmony_ci 1346cd6a6acSopenharmony_civoid sepol_sidtab_map_remove_on_error(sidtab_t * s, 1356cd6a6acSopenharmony_ci int (*apply) (sepol_security_id_t sid, 1366cd6a6acSopenharmony_ci context_struct_t * context, 1376cd6a6acSopenharmony_ci void *args), void *args) 1386cd6a6acSopenharmony_ci{ 1396cd6a6acSopenharmony_ci int i, ret; 1406cd6a6acSopenharmony_ci sidtab_node_t *last, *cur, *temp; 1416cd6a6acSopenharmony_ci 1426cd6a6acSopenharmony_ci if (!s || !s->htable) 1436cd6a6acSopenharmony_ci return; 1446cd6a6acSopenharmony_ci 1456cd6a6acSopenharmony_ci for (i = 0; i < SIDTAB_SIZE; i++) { 1466cd6a6acSopenharmony_ci last = NULL; 1476cd6a6acSopenharmony_ci cur = s->htable[i]; 1486cd6a6acSopenharmony_ci while (cur != NULL) { 1496cd6a6acSopenharmony_ci ret = apply(cur->sid, &cur->context, args); 1506cd6a6acSopenharmony_ci if (ret) { 1516cd6a6acSopenharmony_ci if (last) { 1526cd6a6acSopenharmony_ci last->next = cur->next; 1536cd6a6acSopenharmony_ci } else { 1546cd6a6acSopenharmony_ci s->htable[i] = cur->next; 1556cd6a6acSopenharmony_ci } 1566cd6a6acSopenharmony_ci 1576cd6a6acSopenharmony_ci temp = cur; 1586cd6a6acSopenharmony_ci cur = cur->next; 1596cd6a6acSopenharmony_ci context_destroy(&temp->context); 1606cd6a6acSopenharmony_ci free(temp); 1616cd6a6acSopenharmony_ci s->nel--; 1626cd6a6acSopenharmony_ci } else { 1636cd6a6acSopenharmony_ci last = cur; 1646cd6a6acSopenharmony_ci cur = cur->next; 1656cd6a6acSopenharmony_ci } 1666cd6a6acSopenharmony_ci } 1676cd6a6acSopenharmony_ci } 1686cd6a6acSopenharmony_ci 1696cd6a6acSopenharmony_ci return; 1706cd6a6acSopenharmony_ci} 1716cd6a6acSopenharmony_ci 1726cd6a6acSopenharmony_cistatic inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s, 1736cd6a6acSopenharmony_ci context_struct_t * 1746cd6a6acSopenharmony_ci context) 1756cd6a6acSopenharmony_ci{ 1766cd6a6acSopenharmony_ci int i; 1776cd6a6acSopenharmony_ci sidtab_node_t *cur; 1786cd6a6acSopenharmony_ci 1796cd6a6acSopenharmony_ci for (i = 0; i < SIDTAB_SIZE; i++) { 1806cd6a6acSopenharmony_ci cur = s->htable[i]; 1816cd6a6acSopenharmony_ci while (cur != NULL) { 1826cd6a6acSopenharmony_ci if (context_cmp(&cur->context, context)) 1836cd6a6acSopenharmony_ci return cur->sid; 1846cd6a6acSopenharmony_ci cur = cur->next; 1856cd6a6acSopenharmony_ci } 1866cd6a6acSopenharmony_ci } 1876cd6a6acSopenharmony_ci return 0; 1886cd6a6acSopenharmony_ci} 1896cd6a6acSopenharmony_ci 1906cd6a6acSopenharmony_ciint sepol_sidtab_context_to_sid(sidtab_t * s, 1916cd6a6acSopenharmony_ci context_struct_t * context, 1926cd6a6acSopenharmony_ci sepol_security_id_t * out_sid) 1936cd6a6acSopenharmony_ci{ 1946cd6a6acSopenharmony_ci sepol_security_id_t sid; 1956cd6a6acSopenharmony_ci int ret = 0; 1966cd6a6acSopenharmony_ci 1976cd6a6acSopenharmony_ci *out_sid = SEPOL_SECSID_NULL; 1986cd6a6acSopenharmony_ci 1996cd6a6acSopenharmony_ci sid = sepol_sidtab_search_context(s, context); 2006cd6a6acSopenharmony_ci if (!sid) { 2016cd6a6acSopenharmony_ci SIDTAB_LOCK(s); 2026cd6a6acSopenharmony_ci /* Rescan now that we hold the lock. */ 2036cd6a6acSopenharmony_ci sid = sepol_sidtab_search_context(s, context); 2046cd6a6acSopenharmony_ci if (sid) 2056cd6a6acSopenharmony_ci goto unlock_out; 2066cd6a6acSopenharmony_ci /* No SID exists for the context. Allocate a new one. */ 2076cd6a6acSopenharmony_ci if (s->next_sid == UINT_MAX || s->shutdown) { 2086cd6a6acSopenharmony_ci ret = -ENOMEM; 2096cd6a6acSopenharmony_ci goto unlock_out; 2106cd6a6acSopenharmony_ci } 2116cd6a6acSopenharmony_ci sid = s->next_sid++; 2126cd6a6acSopenharmony_ci ret = sepol_sidtab_insert(s, sid, context); 2136cd6a6acSopenharmony_ci if (ret) 2146cd6a6acSopenharmony_ci s->next_sid--; 2156cd6a6acSopenharmony_ci unlock_out: 2166cd6a6acSopenharmony_ci SIDTAB_UNLOCK(s); 2176cd6a6acSopenharmony_ci } 2186cd6a6acSopenharmony_ci 2196cd6a6acSopenharmony_ci if (ret) 2206cd6a6acSopenharmony_ci return ret; 2216cd6a6acSopenharmony_ci 2226cd6a6acSopenharmony_ci *out_sid = sid; 2236cd6a6acSopenharmony_ci return 0; 2246cd6a6acSopenharmony_ci} 2256cd6a6acSopenharmony_ci 2266cd6a6acSopenharmony_civoid sepol_sidtab_hash_eval(sidtab_t * h, char *tag) 2276cd6a6acSopenharmony_ci{ 2286cd6a6acSopenharmony_ci int i, chain_len, slots_used, max_chain_len; 2296cd6a6acSopenharmony_ci sidtab_node_t *cur; 2306cd6a6acSopenharmony_ci 2316cd6a6acSopenharmony_ci slots_used = 0; 2326cd6a6acSopenharmony_ci max_chain_len = 0; 2336cd6a6acSopenharmony_ci for (i = 0; i < SIDTAB_SIZE; i++) { 2346cd6a6acSopenharmony_ci cur = h->htable[i]; 2356cd6a6acSopenharmony_ci if (cur) { 2366cd6a6acSopenharmony_ci slots_used++; 2376cd6a6acSopenharmony_ci chain_len = 0; 2386cd6a6acSopenharmony_ci while (cur) { 2396cd6a6acSopenharmony_ci chain_len++; 2406cd6a6acSopenharmony_ci cur = cur->next; 2416cd6a6acSopenharmony_ci } 2426cd6a6acSopenharmony_ci 2436cd6a6acSopenharmony_ci if (chain_len > max_chain_len) 2446cd6a6acSopenharmony_ci max_chain_len = chain_len; 2456cd6a6acSopenharmony_ci } 2466cd6a6acSopenharmony_ci } 2476cd6a6acSopenharmony_ci 2486cd6a6acSopenharmony_ci printf 2496cd6a6acSopenharmony_ci ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", 2506cd6a6acSopenharmony_ci tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len); 2516cd6a6acSopenharmony_ci} 2526cd6a6acSopenharmony_ci 2536cd6a6acSopenharmony_civoid sepol_sidtab_destroy(sidtab_t * s) 2546cd6a6acSopenharmony_ci{ 2556cd6a6acSopenharmony_ci int i; 2566cd6a6acSopenharmony_ci sidtab_ptr_t cur, temp; 2576cd6a6acSopenharmony_ci 2586cd6a6acSopenharmony_ci if (!s || !s->htable) 2596cd6a6acSopenharmony_ci return; 2606cd6a6acSopenharmony_ci 2616cd6a6acSopenharmony_ci for (i = 0; i < SIDTAB_SIZE; i++) { 2626cd6a6acSopenharmony_ci cur = s->htable[i]; 2636cd6a6acSopenharmony_ci while (cur != NULL) { 2646cd6a6acSopenharmony_ci temp = cur; 2656cd6a6acSopenharmony_ci cur = cur->next; 2666cd6a6acSopenharmony_ci context_destroy(&temp->context); 2676cd6a6acSopenharmony_ci free(temp); 2686cd6a6acSopenharmony_ci } 2696cd6a6acSopenharmony_ci s->htable[i] = NULL; 2706cd6a6acSopenharmony_ci } 2716cd6a6acSopenharmony_ci free(s->htable); 2726cd6a6acSopenharmony_ci s->htable = NULL; 2736cd6a6acSopenharmony_ci s->nel = 0; 2746cd6a6acSopenharmony_ci s->next_sid = 1; 2756cd6a6acSopenharmony_ci} 2766cd6a6acSopenharmony_ci 2776cd6a6acSopenharmony_civoid sepol_sidtab_set(sidtab_t * dst, sidtab_t * src) 2786cd6a6acSopenharmony_ci{ 2796cd6a6acSopenharmony_ci SIDTAB_LOCK(src); 2806cd6a6acSopenharmony_ci dst->htable = src->htable; 2816cd6a6acSopenharmony_ci dst->nel = src->nel; 2826cd6a6acSopenharmony_ci dst->next_sid = src->next_sid; 2836cd6a6acSopenharmony_ci dst->shutdown = 0; 2846cd6a6acSopenharmony_ci SIDTAB_UNLOCK(src); 2856cd6a6acSopenharmony_ci} 2866cd6a6acSopenharmony_ci 2876cd6a6acSopenharmony_civoid sepol_sidtab_shutdown(sidtab_t * s) 2886cd6a6acSopenharmony_ci{ 2896cd6a6acSopenharmony_ci SIDTAB_LOCK(s); 2906cd6a6acSopenharmony_ci s->shutdown = 1; 2916cd6a6acSopenharmony_ci SIDTAB_UNLOCK(s); 2926cd6a6acSopenharmony_ci} 2936cd6a6acSopenharmony_ci 2946cd6a6acSopenharmony_ci/* FLASK */ 295