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 char *p, *keyp;
19 unsigned int size;
20 unsigned int val;
21
22 val = 0;
23 keyp = (char *)key;
24 size = strlen(keyp);
25 for (p = keyp; (unsigned int)(p - keyp) < size; p++)
26 val =
27 (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
28 return val & (SIDTAB_SIZE - 1);
29 }
30
sidtab_init(struct sidtab * s)31 int sidtab_init(struct sidtab *s)
32 {
33 int i, rc = 0;
34
35 s->htable = (struct sidtab_node **)avc_malloc
36 (sizeof(struct sidtab_node *) * SIDTAB_SIZE);
37
38 if (!s->htable) {
39 rc = -1;
40 goto out;
41 }
42 for (i = 0; i < SIDTAB_SIZE; i++)
43 s->htable[i] = NULL;
44 s->nel = 0;
45 out:
46 return rc;
47 }
48
sidtab_insert(struct sidtab * s,const char * ctx)49 int sidtab_insert(struct sidtab *s, const char * ctx)
50 {
51 int hvalue, rc = 0;
52 struct sidtab_node *newnode;
53 char * newctx;
54
55 newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode));
56 if (!newnode) {
57 rc = -1;
58 goto out;
59 }
60 newctx = (char *) strdup(ctx);
61 if (!newctx) {
62 rc = -1;
63 avc_free(newnode);
64 goto out;
65 }
66
67 hvalue = sidtab_hash(newctx);
68 newnode->next = s->htable[hvalue];
69 newnode->sid_s.ctx = newctx;
70 newnode->sid_s.refcnt = 1; /* unused */
71 s->htable[hvalue] = newnode;
72 s->nel++;
73 out:
74 return rc;
75 }
76
77 int
sidtab_context_to_sid(struct sidtab * s,const char * ctx,security_id_t * sid)78 sidtab_context_to_sid(struct sidtab *s,
79 const char * ctx, security_id_t * sid)
80 {
81 int hvalue, rc = 0;
82 struct sidtab_node *cur;
83
84 *sid = NULL;
85 hvalue = sidtab_hash(ctx);
86
87 loop:
88 cur = s->htable[hvalue];
89 while (cur != NULL && strcmp(cur->sid_s.ctx, ctx))
90 cur = cur->next;
91
92 if (cur == NULL) { /* need to make a new entry */
93 rc = sidtab_insert(s, ctx);
94 if (rc)
95 goto out;
96 goto loop; /* find the newly inserted node */
97 }
98
99 *sid = &cur->sid_s;
100 out:
101 return rc;
102 }
103
sidtab_sid_stats(struct sidtab * h,char * buf,int buflen)104 void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen)
105 {
106 int i, chain_len, slots_used, max_chain_len;
107 struct sidtab_node *cur;
108
109 slots_used = 0;
110 max_chain_len = 0;
111 for (i = 0; i < SIDTAB_SIZE; i++) {
112 cur = h->htable[i];
113 if (cur) {
114 slots_used++;
115 chain_len = 0;
116 while (cur) {
117 chain_len++;
118 cur = cur->next;
119 }
120
121 if (chain_len > max_chain_len)
122 max_chain_len = chain_len;
123 }
124 }
125
126 snprintf(buf, buflen,
127 "%s: %u SID entries and %d/%d buckets used, longest "
128 "chain length %d\n", avc_prefix, h->nel, slots_used,
129 SIDTAB_SIZE, max_chain_len);
130 }
131
sidtab_destroy(struct sidtab * s)132 void sidtab_destroy(struct sidtab *s)
133 {
134 int i;
135 struct sidtab_node *cur, *temp;
136
137 if (!s)
138 return;
139
140 for (i = 0; i < SIDTAB_SIZE; i++) {
141 cur = s->htable[i];
142 while (cur != NULL) {
143 temp = cur;
144 cur = cur->next;
145 freecon(temp->sid_s.ctx);
146 avc_free(temp);
147 }
148 s->htable[i] = NULL;
149 }
150 avc_free(s->htable);
151 s->htable = NULL;
152 }
153