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