• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sidtab_hash(const char * key)16 static 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 
sidtab_init(struct sidtab * s)30 int 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 
sidtab_insert(struct sidtab * s,const char * ctx)48 int 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 
76 int
sidtab_context_to_sid(struct sidtab * s,const char * ctx,security_id_t * sid)77 sidtab_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 
sidtab_sid_stats(struct sidtab * s,char * buf,int buflen)103 void 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 
sidtab_destroy(struct sidtab * s)131 void 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