xref: /third_party/selinux/libsepol/src/sidtab.c (revision 6cd6a6ac)
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