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