xref: /aosp_15_r20/external/selinux/libselinux/src/avc_sidtab.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
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